I am coming at Javascript from a classical OOP background and am having trouble with understanding the prototype.
Given the code example below:
How would I call/execute bar in foo?
why use the "privileged" function instead of putting it on the prototype?
This is probably answered in Q1 but can bar1 and bar2 call each other?
function foo()
{
this.property = "I'm a property";
this.privileged = function()
{
// do stuff
}
}
foo.prototype.bar = function()
{
// do stuff
}
foo.prototype.bar2 = function()
{
// stuff
}
There's a lot of FUD about this to this day.
1). Simple usage:
var xxx = new foo(); // Create instance of object.
xxx.privileged(); // Calls the internal closure.
xxx.bar(); // First looks for internals, then looks to the prototype object.
2). This basically creates a closure that can only be modified on the instance. Not a private at all (since anything can talk to it through the object instance), but rather an individual copy of a function, where each instance of the object gets a new copy of the function. You can alter the function itself, but you cannot alter it globally. I'm not a big fan of this method of creating things.
3). Yes:
foo.prototype.bar = function(){
this.bar2();
}
foo.prototype.bar2 = function(){
this.bar();
}
// Although... NEVER do both. You'll wind up in a circular chain.
For edification, I built you a fiddle which should help show how things get called:
http://jsfiddle.net/7Y5QK/
1) frist is some as Clyde Lobo's an answer:
var f = new foo();
f.bar();
2) write a function on consturctor (privileged), every instance will create a new one, if defined a method on prototype, every instance share the same prototype's method:
var f1 = new foo(), // instance 1
f2 = new foo(); // instance 2
f1.privileged === f2. privileged // -> false , every instance has different function
f1.bar === f2.bar // -> true, every instance share the some function
3) You can call bar2 in bar' bythis.bar()`, code like this:
function foo() {
this.property = "I'm a property";
this.privileged = function() {
// do stuff
};
}
foo.prototype.bar = function() { // defined a method bar
alert('bar called');
this.bar2(); // call bar2
};
foo.prototype.bar2 = function() { // defined a method bar2
alert('bar2 called');
};
var f = new foo();
f.bar(); // alert 'bar called' and 'bar2 called'
f.bar2(); // alert 'bar2 called'
You can execute bar in foo by doing this.bar();
but it will only work if you use new foo(); and have an object inheriting from foo. Otherwise, if you just call foo();, this will point to the global object.
It's essentially the same thing only the properties and methods you give the inheriting object inside the function have access to any arguments you pass to foo.
Yes, they can call each other since functions are "hoisted". They have access to all the variables and objects in their nearest outer scope, and in their functional context.
You actually have syntax errors in your code. Where you were assigning the prototype you didn't create a function. You meant:
foo.prototype.bar = function() { /* ... */ };
1.You can create an instance of foo like
var f = new foo();
and then call f.bar() and f.bar2()
points 2 & 3 are already explained by David
Related
Learning JavaScript Fundamentals, confused on what the function calls return.
I have an idea of f.bar returns 7 because when the f object is created it gets access to functions of Foo that have the "this" keyword. Also I believe f.baz returns an error because this function is only available locally and does not use the "this" keyword which makes it unavailable outside Foo. f.biz I am confused but I do know the Prototype keyword allows for inheritance of Foo properties.
An explanation for each function call would be awesome, thank you everyone!
var Foo = function(a){
this.bar = () => {
return a;
}
var baz = function(){
return a;
}
Foo.prototype = {
biz: () => {
return this.bar();
}
}
}
var f = new Foo(7);
f.bar();// what does this return?
f.baz(); // what does this return?
f.biz(); // what does this return?
As it is now, only the bar function will work as intended.
The baz function is in a local variable, so it's only accessible inside the Foo function as baz but not as this.baz (variables and instance properties (this.whatever) are not connected in any way).
The case of biz is a bit more complicated. Normally, that's more or less how you'd create a prototype method, but you did it in the wrong place. It should be outside the function, because the way it is now, it's:
reassigned on every call of new Foo() (unnecessary)
assigned only after the current instance is created, so it will take effect only on the next instance (also if you used a in it (which you shouldn't), you'd find that it always has the a of the previous call)
You also don't want to use an arrow function when you want to "let JS set this" (arrow functions copy their this from where they were defined).
So, to make biz work, you have to do this:
var Foo = function(a){
this.bar = () => {
return a;
}
}
Foo.prototype = {
biz: function (){
return this.bar();
}
}
var f = new Foo(7);
console.log(f.bar());
console.log(f.biz());
I keep on trying to assign a function to a variable and I keep getting a message saying foo is not a function. I am not sure why it is saying that. When I invoke the method by itself it works, but when I assign it to a variable it won't work.
Can anyone please help me figure this out? Thank you!!!
Below is my code:
function Test(){
function foo(){
return "foo";
}
this.bar = function () {
var foo = foo();
console.log(foo);
};
}
var test = new Test();
test.bar();
The culprit is this line var foo = foo();. The statement var foo is redeclaring the local foo variable. By the time you try to access it with foo() it has become an undefined variable.
Rename the variable or the function and everything works correctly.
Following code will work. As Now we are not trying to assign same function variable to variable.
The problem is because JavaScript is function scoped. It is failing because this.bar function will try to evaluate foo first and foo is name of variable in this function so interpreter will try to execute the foo but foo is variable in this scope it will not consider foo mentioned above. Hence it fails.
Where as foo1 will work because when interpreter hits the term foo1 it will look for current scope and all parent scopes and it will get it.
function Test(){
function foo1(){
return "foo";
}
this.bar = function () {
var foo = foo1();
console.log(foo);
};
}
var test = new Test();
test.bar();
Error is at this line
var foo = foo();
Your variable foo has the same name as the function, that hides the function outside.
Renaming it will resolve the error.
var foo1 = foo();
There error you're seeing is from this line:
var foo = foo();
When you use var there you are saying that foo is being defined for the current level of scope (this.bar) - meaning it won't bubble up to Test. You can either rename the variable to something else:
var result = foo();
console.log(result);
or just forgo that variable altogether like this:
console.log(foo());
totally your choice.
If you are learning how to create and work with JavaScript objects, you may want to rewrite your code like so:
// This function constructs the object when called with new
function Test(prop) {
// Some arbitrary property
if (typeof prop === "undefined") {
prop = null;
}
this.prop = prop;
}
// The two functions
Test.prototype.foo = function() {
return "foo";
}
Test.prototype.bar = function() {
var foo = this.foo();
console.log(foo);
}
// Create the object and call foo
var test = new Test('p');
test.bar();
All JavaScript objects inherit the properties and methods from their
prototype. Objects created using an object literal, or with new
Object(), inherit from a prototype called Object.prototype. Objects
created with new Date() inherit the Date.prototype. The
Object.prototype is on the top of the prototype chain.
From: http://www.w3schools.com/js/js_object_prototypes.asp
Conventional wisdom is that to simulate OOP in Javascript, we do everything in terms of functions and prototypes:
var fooObject = function () {
//Variables should be defined in the constructor function itself,
//rather than the prototype so that each object will have its own variables
this.someProperty = 5; //Default value
};
//Functions should be defined on the prototype chain so that each object does not
//have its own, separate function methods attached to it for performing the same
//tasks.
fooObject.prototype.doFoo = function () {
//Foo
}
Now, to create a derived class, we do:
var derivedFromFoo = new foo();
But what happens if we want to do some other stuff in our constructor for the derived object? Like set other properties? Can we do something like
var derivedFromFoo = function () {
this = new foo();
};
new foo();
That's an instance, not a class.
To create a derived class, you need to make a new function, call the base ctor from inside of it, then set the new function's prototype to an object created from the base prototype:
function Derived() {
Base.call(this);
}
Derived.prototype = Object.create(Base.prototype);
For more details, and a longer, more-correct implementation, see my blog post.
What's the difference between these two method of defining a 'class' in JavaScript?
Method One
Define method within the constructor:
function MyClass()
{
this.foo = function() { console.log('hello world!'); };
}
Method Two
Define method on the prototype:
function MyClass()
{}
MyClass.prototype.foo = function() { console.log('hello world!'); };
The first will create a new function object on each instantiation of your object, the second will assign a reference to a prototype method to each instance. In short: the second is more efficient, because all instances will share a single function object.
That's just the logic of a prototype chain, you can try and access anything via any object:
var objLiteral = {foo:'bar'};
When accessing objLiteral.foo JS will first look at the properties that the object itself has defined, and return the value if it is found. If JS can't find the property on the object itself, it'll check the object's prototype, hence:
objLiteral.valueOf();//method defined #Object.prototype
objLiteral.valueOf === Object.prototype.valueOf //true
But when you use your first method:
function SomeConstructor()
{
this.methd = function()
{
return true;
}
}
var f = new SomeConstructor();
var g = new SomeConstructor();
f.methd === g.methd;//FALSE!
That shows that we're dealing with 2 separate function objects. Move the function definition to the prototype and f.methd === g.methd; will be true:
function SomeConstructor()
{
}
SomeConstructor.prototype.methd = function()
{
return true;
}
var f = new SomeConstructor();
var g = new SomeConstructor();
f.methd === g.methd;//true!
In response to your comment:
Defining a method on a prototype-level allows you to change a method for a specific task, and then "reset" it back to it's default behaviour. Suppose you're in a function that's creating an AJAX request:
someObject.toString = function(){ return JSON.stringify(this);}
//when concatinating this object you'll get its json string
//do a lot of stuff
delete (someObject.toString);
Again JS will check if the object has the toString property defined on itself, which it has. So JS will delete the function you've assigned to the toString property. Next time the toString will be invoked, JS will start scanning the prototype chain all over again, and use the first occurance of the method (in the prototype). Let's clarify:
function SomeConstructor()
{
}
SomeConstructor.prototype.methd = function()
{
return true;
}
var f = new SomeConstructor();
var g = new SomeConstructor();
f.methd = function(){return false;};
g.methd();//returns true, still <-- method is gotten from the prototype
f.methd();//returns false <-- method is defined # instance level
delete (f.methd);
f.methd();//returns true, f doesn't have the method, but the prototype still does, so JS uses that.
Or even better, you can even replace an instance's method by a method from another prototype:
f.methd = Object.prototype.valueOf;//for as long as you need
the last example is pointless, because f has the valueOf method already: its inheritance chain looks like this: var f ---> SomeConstructor ---> Object, giving you access to all Object.prototype methods, too! Neat, isn't it?
These are just dummy examples, but I hope you see this is one of those features that make JS an incredibly flexible (sometimes too flexible, I must admit) and expressive language.
In first case the function will be created for each instance and set to the foo property in the object. In second case it is shared function. When you call obj.prop then it looks for it in object itself, if it is not there, then it looks for it in proto object and so on, it is called chain of prototypes.
For example this code provides foo:
function MyClass() {
this.foo = function () {};
}
var myVariable = new MyClass();
for (var i in myVariable) if (myVariable.hasOwnProperty(i)) console.log(i);
But this not:
function MyClass() {
}
MyClass.prototype.foo = function () {};
var myVariable = new MyClass();
for (var i in myVariable) if (myVariable.hasOwnProperty(i)) console.log(i);
In example:
function foo() {
var bar = this.bar = function () {
return "bar";
};
this.mybar = function () {
return bar();
}
}
var myFoo = new foo();
myFoo.bar = function() {
return "notbar";
};
myFoo.bar(); // returns 'notbar'
myFoo.mybar(); // returns "bar"
Basically it allows for an internal private method to a closure, with the possibility of being overwritten only for external access. So the reference to the original function never changes, for references of that function within the closure. But instantiators of the closure object can overwrite that function without breaking the functionality of the object.
Is there a name for this particular construct, and is it even useful?
If you refer to assigning a function to a local variable and using this function in another public method, then yes, this would some form of data encapsulation. Apart from that, I'd say there is not special name for that.
var bar is a variable local to the function and this.bar is a property of the new object. The variable and the property happen to have the same name, but they are not related.
It is only useful if you want to make the function in bar publicly accessible and ensure the correct working of the other function, in case the public bar is overwritten.
So it is some form of protecting the other functions, but it is not a special pattern to allow external overwriting.
If the sole purpose of this.bar is to be overwritten, then you'd achieve the same with:
function foo() {
var bar = function () {
return "bar";
};
this.mybar = function () {
return bar();
}
}
var myFoo = new foo();
myFoo.bar = function() {
return "notbar";
};
myFoo.bar(); // returns 'notbar'
myFoo.mybar(); // returns "bar"
Of course, if you call myFoo.bar() before you assign a function to it, then you will get an error.