Why does this JavaScript example point to the global object (Window)? - javascript

function F() {
function C() {
return this;
}
return C();
}
var o = new F();

Break down the component elements.
Suppose you were to do this:
function C() {
return this;
}
var o = C();
There is clearly no object context here, so this is window.
Wrapping that setup in a constructor doesn't change the fact that there isn't any object involved in the context of a straightforward call to C().

function C() is not a method of F, what you need to do is something like this:
function F() {
this.C = function() {
return this;
}
return this.C();
}
var o = new F();
Although that is a bit convoluted, when you could just do this to achieve the same thing:
function F() {}
var o = new F();

C() is not a method of the f object. As in, you can't call o.C();. If that makes sense. and because you return the return value of C() instead of a new instance of C it returns the window object.

function F() { return this; } will also return window. So will var obj = this. It't the value of "this" whenever "this" has no other value.

Related

Javascript : Adding a method to a parent class / to be inherited

I'd like to add a method "bar" to a parent class A, after a subclass B are is defined, so that the method is inherited. Is it possible?
I tried the following code
function A() {
this.foo = function () {
console.log('foo')
}
}
function B() {
A.call(this)
}
// (trying to) add a new method to A
A.prototype.bar = function () {
console.log('bar');
}
// It works with instances of A
var a = new A()
a.foo() // ok
a.bar() // ok
// but not with an instance of B
var b = new B()
b.foo() // this works
b.bar() // not this one <------
/*
Exception: b.bar is not a function
#Scratchpad/3:17:1
*/
Any suggestion, please?
If you need just fix your code, you can link methods like this:
function B() {
A.call(this)
for(var i in A.prototype){ this[i] = A.prototype[i]; }
}
But i think it is bad way.
function A() {
this.foo = function () {
console.log('foo');
};
}
function B() {
A.call(this);
}
// (trying to) add a new method to A
A.prototype.bar = function () {
console.log('bar');
};
B.prototype = Object.create(A.prototype);
// It works with instances of A
var a = new A() ;
a.foo() ; // ok
a.bar() ; // ok
// but not with an instance of B
var b = new B() ;
b.foo() ; // this works
b.bar() ;
I case of functional-type of inheritance - you can't add methods, that don't exists in class. Use prototypes
// if you define the prototype as an object
var A = {
foo: function() {
console.log('foo');
}
};
// and define constructors using Object.create
function newA() {
return Object.create(A);
};
function newB() {
return Object.create(newA());
};
// you can add methods to the prototype
A.bar = function () {
console.log('bar');
};
// it works with instances of A
var a = newA()
a.foo();
a.bar();
// and instances of B
var b = newB();
b.foo();
b.bar();
// you can even modify the prototype after the fact
A.baz = function() {
console.log('baz');
};
// and that will work as well
a.baz();
b.baz();
http://jsfiddle.net/5s8ahvLq/
If you don't want the latter behavior of being able to edit the protoype after the fact, use Object.assign or something like underscore or lodash that provides that functionality:
function newA() {
return Object.create(Object.assign({}, A));
}
You're missing:
B.prototype.__proto__ = A.prototype
If you don't like using __proto__ you can use:
B.prototype = Object.create(A.prototype);

How to create an object in which the object itself is a function?

I have a javascript object from which I created from a constructor.
var obj = new Obj();
It has several functions but I wish to also use it as follows;
obj();
Obj is defined as:
function obj() {
this.blah = function () {
};
}
How can I do this?
It would be easier to have a function you call which returns an arbitrary function that is treated as both an object and a function. Each one would be unique, and you would not need to use new.
function Obj() {
var ret = function(){
console.log('Hello');
};
ret.blah = function () {
console.log('World');
};
return ret;
}
var obj = Obj();
obj();//Hello
obj.blah();//World
You can create properties on function objects. For instance, if you have the function
function foo() {
return "bar";
}
You can set a property on foo.
foo.baz = 42;
So now you can call foo and get the result "bar", and you can access its baz property.
I think you are looking for 'closure' here.
Try:
function MyObject(/* constructor params */) {
//assign properties to 'this'
return function() {
return this; //<== placeholder implementation
}.bind(this);
}
var obj1 = new MyObject();
Now if you do console.log(obj1) you will see function() { [...] } and you will be able to do obj1() to execute your function.
As a bonus in the code above, I also added this binding in the 'closure' as you will need it in most cases that you are doing anything interesting.

javascript inheritance using the prototype property

I'm trying to do inheritance in javascript. First of all, looking on the web I found this
function A() {}
function B(){}
B.prototype = new A() ;
B.prototype.constructor = B ;
This works, however when I use the prototype property of B it doesn't work anymore ( http://jsfiddle.net/jeanluca/eQBUx/ )
function A() {}
A.prototype.bar = function(){ return 'A'; }
function B() {}
B.prototype.bar = function(){ return 'B'; }
I realize you could do
function B(){ this.bar = function(){ ... } } ;
But I think this is definitely slower than defining it using the prototype. So how could I do inheritance in the second situation ?
Thnx
Here's your code:
function A() {}
A.prototype.bar = function(){ return 'A';}
function B() {}
B.prototype.bar = function(){ return 'B'; }
B.prototype = new A() ; // replaces B's "bar" with A's "bar
var b = new B ;
console.log(b.bar());
As you can see the problem is in your 6th line. You're first setting B.prototype.bar to a function in line 5 and then you immediately set B.prototype to new A in line 6 (effectively undoing what you did in line 5). The solution is to put line 6 before line 5:
function A() {}
A.prototype.bar = function(){ return 'A';}
function B() {}
B.prototype = new A() ; // now it will work
B.prototype.bar = function(){ return 'B'; }
var b = new B ;
console.log(b.bar());
See the demo for yourself: http://jsfiddle.net/eQBUx/1/
In addition I agree with Bergi: Stop using the new keyword.
Update: After reading your comment and understanding your problem in greater detail I would recommend you use my augment library for inheritance:
var A = Object.augment(function () {
this.constructor = function () {};
this.bar = function () {
return "A";
};
});
var B = A.augment(function (base) {
this.constructor = function () {};
this.bar = function () {
return "B" + base.bar.call(this);
};
});
var b = new B;
console.log(b.bar());
See the demo: http://jsfiddle.net/eQBUx/2/
Using this to assign properties breaks the prototype chain. It's very inefficient and you can't use it to get inheritance. So .. don't?
You're creating a property on a the prototype object which you completely replace afterwards. Do it the other way round, create the bar method on the new object. And don't use new!
function B() {}
// first create the prototype object
B.prototype = Object.create(A.prototype);
// then assign properties on it
B.prototype.bar = function(){ return 'B'; }

Javascript objection creation with function contructor

I was expecting the obj to be instanceof F1 ('this' in 'this.prop' refers to F1 object in the code snippet below, similarly I thought 'this' in 'return this' of C1 refers to F1 which is not the case. It refers to Global Window object), but in actuality it is an instanceof Window. Why is that ? could you please explain ?
function F1() {
this.prop = 5;
function C1() {
return this;
}
return C1();
}
var obj = new F1();
if you are just creating an instance of F1, then just do this:
function F1() {
this.prop = 5;
}
var obj = new F1();
you don't need to return anything.
the this inside C1 is not the same as this outside it. if you want to preserve this of the outside so that C1 can use it, store it into another variable
function F1() {
//preserve "this" from outside
var that = this;
this.prop = 5;
function C1() {
return that; //"that" is "this" of the outside
}
}

Can the object you create with a constructor function ever itself be a function?

I hope this question makes sense. Can I ever do something like the following:
function constructor_function() {...code...};
var a = new constructor_function();
a();
If a constructor returns an object, that will be the value of the new .. expression. A function is an object, so you do what you want:
function ConstructorFunction() {
return function () { alert("A function!"); };
}
var a = new ConstructorFunction();
a();
function Wrapper(constr, func) {
return function() {
var f = func();
constr.apply(f, arguments);
return f;
}
}
function ConstructorFunction() {
return function() {
console.log("A function");
}
}
function Constructor() {
this.foo = 42;
}
var MyFunction = Wrapper(Constructor, ConstructorFunction);
var o = MyFunction();
o(); // A function
console.log(o.foo); // 42
To both manipulate the this state as intended and have the object returned be a function is difficult to do without a lot of extra hoops to jump through.
This is about as easy I could make it. You have your standard Constructor function that manipulates this as an object. Then you have your ConstructorFunction which is the function you want the constructor to return. This must be a factor that returns a new function each time it's called.
You wrap the two together to get a function which returns an object which both has the returned function and the manipulation of state.
Live example
You can return a function from the constructor, but then it's not really a constructor. You can just use the function as a regular function, the new keyword is not needed:
function constructor_function() {
return function() { alert(42); }
};
var a = constructor_function();
a();
As a function is an object, you can even add properties to it:
function constructor_function() {
var t = function() { alert(42); }
t.size = 1337;
return t;
};
var a = constructor_function();
a();
alert(a.size);

Categories