var name = 'global';
var obj = {
name: 'local',
foo: function(){
this.name = 'foo';
console.log(this.name);
}.bind(window)
};
var bar = new obj.foo();
setTimeout(function() {
console.log(window.name);
}, 0);
console.log(bar.name);
var bar3 = bar2 = bar;
bar2.name = 'foo2';
console.log(bar3.name);
这个题的整体出题质量还是挺高的,首先咱们来把涉及到的知识罗列一下:
bind
是显式绑定,会修改this
指向,但bind()
函数不会立即执行函数,会返回一个新函数setTimeout
是异步任务,同步任务执行完毕后才会执行异步任务- 绑定优先级: new绑定 > 显式绑定 > 隐式绑定 > 默认绑定
解析
obj.foo
将它的this
通过bind
显式的绑定为window
,但bind
不会立即执行var bar = new obj.foo()
:new
绑定优先级大于bind
,因此bind
失效了,此时this
指向new
实例,因此obj.foo
内部的console
打印foo
bar
是new obj.foo()
的实例,console.log(bar.name)
打印foo
setTimeout
异步任务,等到同步执行完毕再来调用它的回调bar3 = bar2 = bar
,将bar2,bar3,bar
的地址都指向bar
所指向的空间。bar2.name = 'foo2'
,修改地址指向堆内存的值console.log(bar3.name)
: 由于三个变量指向同一块地址,bar3
修改了name
,bar3
也随之改变,打印foo2
setTimeout
的回调执行,打印global
foo
foo
foo2
global
修改1:去除new绑定
var name = 'global';
var obj = {
name: 'local',
foo: function(){
this.name = 'foo';
console.log(this.name);
}.bind(window)
};
obj.foo();
setTimeout(function() {
console.log(this.name);
}, 0);
console.log(name);
obj.foo
没有做修改,它的this
通过bind
显式的绑定为window
,但bind
不会立即执行obj.foo()
执行,显式绑定优先级大于隐式绑定,因此此时foo
函数this -> window
this.name
相当于window.name
,修改了全局的name
变量值,打印foo
setTimeout
回调等同步代码执行完毕- 全局的
name
已经修改为foo
,打印foo
- 执行
setTimeout
的回调,默认绑定,打印foo
foo
foo
foo
修改2:bind改为call
var name = 'global';
var obj = {
name: 'local',
foo: function(){
this.name = 'foo';
console.log(this.name);
}
};
obj.foo.call(window);
var bar = new obj.foo();
setTimeout(function() {
console.log(window.name);
}, 0);
console.log(bar.name);
var bar3 = bar2 = bar;
bar2.name = 'foo2';
console.log(bar3.name);
call
与 bind
的区别就在于 call
函数会立即执行
因此 obj.foo.call(window)
会立即执行函数,同时也修改了全局的 name
值。其他部分与上面所讲类似,不多做赘述了。
foo
foo
foo
foo2
foo
原文牛客最新前端笔试题解析(一) this指向题目解析及扩展 - 掘金
绑定的优先级:new绑定>显式绑定>隐式绑定>默认绑定 (解释上面bind为什么遇到new之后this就没改变成功)
插一嘴:当对象有自己的属性并继承了具有相同名称的属性时,自己的优先级大于继承的优先级