var obj = {
say: function() {
function _say() {
console.log(this);
}
return _say.bind(obj);
}()
};
obj.say();
the code result is log out the global or window, I want to know why the bind method doesn't bind 'this' to the obj object context?
During assignment the variable obj still does not have any value. As such, your call to bind is equivalent to .bind(undefined) which behaves the way you observed.
To be more specific, this referring to window is because of OrdinaryCallBindThis doing the following steps (non strict mode):
[...]
If thisArgument is undefined or null, then
[...]
Let thisValue be globalEnvRec.[[GlobalThisValue]].
You can check in the chrome debugger that [[BoundThis]] is indeed undefined after your call.
You are invoking the function immediately. Remove parenthesis following say function. If you are expecting to call the function without two consecutive parenthesis obj.say()() use .call() instead of .bind()
var obj = {
say: function() {
function _say() {
console.log(this);
}
return _say.call(this);
}
};
obj.say();
Related
In this code, the callback function receives the scope of the new Thing object (as the commend shows, Thing is logged.) Use of an arrow function causes it to log the window object.
I'd like to be able to access the scope of the literal object in that callback function, ideally without referring to it from the global object. Is there some way to do this?
function Thing(fun){
this.funThing = fun
}
let literal = {
thing: new Thing(function(){
console.log(this)
})
}
literal.thing.funThing() // Thing {funThing: ƒ}
You could use a getter instead, main difference here would be that upon each access the thing would be recreated, but well, that you could overcome in a different way ;)
And yes, I changed it to an arrow function here, but I could have bound the callback function as well
function Thing(fun){
this.funThing = fun
}
let literal = {
get thing() {
return new Thing(() => {
console.log(this)
});
}
}
literal.thing.funThing()
Solution of lcepickle works fine. Another way is to bind the callback function with the literal object, but in this case you have to define it before calling new Thing constructor. So, you can add the thing attribute after the definition of literal object:
function Thing(fun){
this.funThing = fun
}
let literal = { }
literal.thing = new Thing(function(){
console.log(this)
}.bind(literal))
literal.thing.funThing()
You could bind the anonymous callback function to the scope of the literal object.
function Thing(fun){
this.funThing = fun
}
literal = {
thing: new Thing(function(){
console.log(this)
}.bind(this.literal))
}
literal.thing.funThing()
I thought this was suppose to trigger a bug when calling a function from within a function using the keyword this. Running Chrome 37.0
S = function () {
this.x = "test";
this.test1 = function () {
console.log("test1");
this.test2();
};
this.test2 = function () {
console.log(this); // output is s object, thought 'this' suppose to be global?
console.log("test2");
};
};
s = new S();
s.test1();
Edit:
I mixed it up with this code:
s = function () {
console.log(this);
var t = function () {
console.log(this);
};
t();
};
x = new s();
Calling a function as part of an expression where you get the function reference from an object property calls the function with this set to the object you got the property from.
So your code:
s.test1();
...will call test1 setting this equal to the object referenced by s, because the call is part of an expression getting the test1 function reference from a property on the object s refers to.
Then in test1, when you do:
this.test2();
...it calls test2 setting this equal to the object referenced by this, because the call is part of an expression getting the test2 function reference from a property on the object this refers to.
Where you'd run into a problem with this not being set correctly would be if you didn't call test1 or test2 via an object property, like this:
var f = s.test1;
f();
Then, within the call to test1, this would be the global object (in loose mode) or undefined (in strict mode). The same sort of thing happens when passing a function as an argument:
foo(s.test1);
If foo calls the function its first argument relates to, we get the same thing (this = global object or undefined).
Since you're not doing that, though, that doesn't happen.
The key thing here is how the function is called, not where it's defined (inside another function or not).
More on this in How Does The this Keyword Work? here on SO, and in Mythical methods and You must remember this on my blog.
Unfortunately .bind has been giving me grief when creating more complex closures.
I am quite interested in why .bind seems to work differently once you nest functions.
For example :
function t(){
t = t.bind({}); //correctly assigns *this* to t
function nested_t(){
nested_t = nested_t.bind({}); // fails to assign *this* to nested_t
return nested_t;
}
return nested_t();
}
//CASE ONE
alert(t());
// alerts the whole function t instead of nested_t
//CASE TWO
aleft(t.call(t));
// alerts the global object (window)
In both cases I was expecting a behavior like this:
function t(){
var nested_t = function nested_t(){
return this;
};
return nested_t.call(nested_t);
}
alert(t.call(t));
If someone could explain the behavior of .bind in the first (and/or) second case it would be much appreciated!
So, i'm not entirely reproducing your issue here (both cases return the global object), but i'll try and explain the code as i see it.
function t(){
t = t.bind({}); //correctly assigns *this* to t
function nested_t(){
nested_t = nested_t.bind({}); // fails to assign *this* to nested_t
return this;
}
return nested_t();
}
//CASE ONE
alert(t());
Let's take it step by step.
First, the function t() is defined. Then, upon call, it gets overwritten with a clean context. However, i don't see any usage of this context.
Now, a nested function (nested_t) is defined. Upon call, it is overwritten with a clean context. It then returns the context it had when it was called.
Back to t(). You then return the result of nested_t(), not nested_t itself. In the original function call, nested_t is still being called with global context.
Therefore, when you run t(), it returns the global object.
How your code works
It's very unclear, what your code is trying to do. You can find the documentation for .bind() here. It looks like you might be somehow misunderstanding what this is and how to use it. Anyway, what happens when you run your code is this:
A t function is created in global scope.
[case one] The t function is called.
Global scope t is replaced with a new value (original t bound to a specific context - anonymous empty object), which doesn't affect the current call in any way. Also, while the global t is overwritten, the local t is behaving as read-only. You can check it out by trying the following code: (function foo () { return (function bar () { bar = window.bar = 'baz'; return bar; })(); })() and comparing return value with window.bar.
The same thing happens with nested_t in the nested context (instead of global context).
Result of nested_t call is returned. nested_t returns the context it was called with, which was window, as no context was specified. Specifically, it was not called with an empty object context, because the .bind() inside didn't affect the call itself.
[case two] The exact same thing happens once again. Now you're just calling t with itself as context. Since t doesn't use its context (this) anywhere in its code, nothing really changes.
What your misconceptions might be
Basically, you're mixing up two things - function instance and function call context. A function is a "first-class citizen" in JavaScript - it's an object and you can assign values to its properties.
function foo () {
foo.property = 'value';
}
foo(); // foo.property is assigned a value
This has nothing to do with function call context. When you call a function a context is assigned to that call, which can be accessed using this (inside function body)
function foo () {
this.property = 'value';
}
var object = {};
foo.call(object); // object.property is assigned a value
When you use .bind(), you just create a new function with the same code, that is locked to a specific context.
function foo () {
this.property = 'value';
}
var fixedContext = {},
object = {};
bar = foo.bind(fixedContext);
foo.call(object); // fixedContext.property is set instead of object.property
But in this case, there are also function instances foo and bar, which can also be assigned properties, and which have nothing to do with contexts of calls of those functions.
Let's look at how bind works. First, one level of nesting:
var foo = function() { return this.x; };
alert(foo()); // undefined
alert(foo.bind({x: 42})()); // 42
Now we can add the next level of nesting:
var bar = function() { return foo.bind(this)(); };
alert(bar()); // undefined
alert(bar.bind({x: 42})());
We pass our this context to foo with - guess what? - bind. There is nothing different about the way bind works between scopes. The only difference is that we've already bound this within bar, and so the body of bar is free to re-bind this within foo.
As a couple of commenters have noted, functions that overwrite themselves are a huge code smell. There is no reason to do this; you can bind context to your functions when you call them.
I highly, highly recommend reading the documentation on bind, and trying to understand it to the point where you can write a basic version of Function.prototype.bind from scratch.
Consider the following code:
function A() {}
A.prototype.go = function() {
console.log(this); //A { go=function()}
var f = function() {
console.log(this); //Window
};
f();
}
var a = new A();
a.go();
Why does 'this' inside function 'f' refers to the global scope? Why it is not the scope of function 'A' ?
JavaScript has a different concept of what the special name this refers to
than most other programming languages do. There are exactly five different
ways in which the value of this can be bound in the language.
The Global Scope
this;
When using this in global scope, it will simply refer to the global object.
Calling a Function
foo();
Here, this will again refer to the global object.
ES5 Note: In strict mode, the global case no longer exists.
this will instead have the value of undefined in that case.
Calling a Method
test.foo();
In this example, this will refer to test.
Calling a Constructor
new foo();
A function call that is preceded by the new keyword acts as
a constructor. Inside the function, this will refer
to a newly created Object.
Explicit Setting of this
function foo(a, b, c) {}
var bar = {};
foo.apply(bar, [1, 2, 3]); // array will expand to the below
foo.call(bar, 1, 2, 3); // results in a = 1, b = 2, c = 3
When using the call or apply methods of Function.prototype, the value of
this inside the called function gets explicitly set to the first argument
of the corresponding function call.
As a result, in the above example the method case does not apply, and this
inside of foo will be set to bar.
Note: this cannot be used to refer to the object inside of an Object
literal. So var obj = {me: this} will not result in me referring to
obj, since this only gets bound by one of the five listed cases.
Common Pitfalls
While most of these cases make sense, the first one is to be considered another
mis-design of the language because it never has any practical use.
Foo.method = function() {
function test() {
// this is set to the global object
}
test();
}
A common misconception is that this inside of test refers to Foo; while in
fact, it does not.
In order to gain access to Foo from within test, it is necessary to create a
local variable inside of method which refers to Foo.
Foo.method = function() {
var that = this;
function test() {
// Use that instead of this here
}
test();
}
that is just a normal variable name, but it is commonly used for the reference to an
outer this. In combination with closures, it can also
be used to pass this values around.
Assigning Methods
Another thing that does not work in JavaScript is function aliasing, which is
assigning a method to a variable.
var test = someObject.methodTest;
test();
Due to the first case, test now acts like a plain function call; therefore,
this inside it will no longer refer to someObject.
While the late binding of this might seem like a bad idea at first, in
fact, it is what makes prototypal inheritance work.
function Foo() {}
Foo.prototype.method = function() {};
function Bar() {}
Bar.prototype = Foo.prototype;
new Bar().method();
When method gets called on a instance of Bar, this will now refer to that
very instance.
Disclaimer: Shamelessy stolen from my own resources at http://bonsaiden.github.com/JavaScript-Garden/#function.this
The reason why is you are invoking f as a function and not a method. When invoked as a function this is set to window during the execution of the target
// Method invocation. Invoking a member (go) of an object (a). Hence
// inside "go" this === a
a.go();
// Function invocation. Invoking a function directly and not as a member
// of an object. Hence inside "f" this === window
f();
// Function invocation.
var example = a.go;
example();
The scope of all functions is window.
To circumvent that, you can do this:
function A() {}
A.prototype.go = function() {
var self = this;
console.log(self); //A { go=function()}
var f = function() {
console.log(self); //A { go=function()}
};
f();
}
Because function f() is not called without any object reference. Try,
f.apply(this);
Can anybody explain to me why A is true and B is false? I would have expected B to be true as well.
function MyObject() {
};
MyObject.prototype.test = function () {
console.log("A", this instanceof MyObject);
(function () {
console.log("B", this instanceof MyObject);
}());
}
new MyObject().test();
update:
since ecmascript-6 you can use arrow functions which would make it easy to refer to MyObject like this:
function MyObject() {
};
MyObject.prototype.test = function () {
console.log("A", this instanceof MyObject);
(() => {//a change is here, which will have the effect of the next line resulting in true
console.log("B", this instanceof MyObject);
})(); //and here is a change
}
new MyObject().test();
Inside of your anonymous function this is the global object.
Inside of test, this is the instance of MyObject on which the method was invoked.
Whenever you call a function like this:
someFunction(); // called function invocation
this is always the global object, or undefined in strict mode (unless someFunction was created with bind** — see below)
Whenever you call a function like this
foo.someMethod(); //called method invocation
this is set to foo
**EcmaScript5 defines a bind function that allows you to create a function that has a pre-set value for this
So this
var obj = { a: 12 };
var someFunction = (function () { alert(this.a); }).bind(obj);
someFunction();
Causes someFucntion to be invoked with this equal to obj, and alerts 12. I bring this up only to note that this is a potential exception to the rule I mentioned about functions invoked as
someFunction();
always having this equal to the global object (or undefined in strict mode)
this is special. It refers to the object that the function is being called on behalf of (most commonly via dot syntax).
So, in the case of A, the function is being called on behalf of a new MyObject object. B is in a different function that isn't explicitly being called on behalf of any object, so this defaults to the global object (window).
In other words, this changes depending on how the function is called, not where or how it is defined. The fact that you're using an anonymous function (defined inside another function) is coincidental and has no effect on the value of this.
In the anonymous function, this is bound to the global object (window in a browser environment).
There are various ways of accessing the instance:
var self = this;
(function () {
console.log("B", self instanceof MyObject);
}());
or
(function () {
console.log("B", this instanceof MyObject);
}).call(this);
this is set based on how you call the function.
Your anonymous function is a normal function call, so this is the global object.
You could write (function() { ... }).call(this) to explicitly call it with your this.