用call来解释this很形象,但是不是那么严谨,详情看补充1;
了解this的本质
比较严谨的解释:一个函数可以在多个环境中执行,函数执行时允许访问环境中的其他变量,this会指向调用函数的那个环境;
比较易懂的解释:
- 函数调用时都指定了它的外部环境,这里用call来展示外部环境:
- fn(x);,可以理解为fn.call(undefined,x);这里fn中的this就是undefined;
- obj.fn(); 可以理解为obj.fn.call(obj,x);这里fn中的this就是obj;
call函数的第一个参数就是指定的外部环境,就是this
想要知道一个函数中的this是谁,大部分情况下可以去函数调用栈中找上一个函数看到。
this的绑定规则
1.默认绑定
- 像fn();
- 严格模式下等价于fn.call(undefined);
- 非严格模式下等价于fn.call(全局对象);这个全局对象在浏览器中是window,node中是global;
2.隐氏绑定
- 像obj.fn();等价于fn.call(obj),obj作为一个上下文对象隐性传递到了fn中;
- 这个传递是隐性的,我们观察不到的。
3.显示绑定
- 像fn.call(context); fn在执行时,this就是context;
- 这个绑定很明显,是我们可以观察、并且控制的。
- 显示绑定很常用,这里贴一个bind方法的极简实现
function bind(fn, obj) {
return function() {
return fn.apply( obj, arguments );
};
}
4.new绑定
- js中的new操作符和其他语言的new机制完全不一样。
- new执行的操作用伪代码表达一下:
// 执行new Foo()时发生的操作
var obj = {}; // 创建空对象
obj.__proto__ = Foo.prototype; // 连接到foo的原型,继承机制
Foo.call(obj); // 绑定成上下文,并执行foo
return obj; // foo中如果没有return的话,return obj这个对象回去
补充1:this被忽略的情况,用call做例子不严谨的原因
- 当把null或undefined作为this传入call、apply、bind时,实际应用的是默认绑定规则;
// 非严格模式
function foo() {
console.log( this.a );
}
var a = 2;
foo.call( null ); // 2
补充2:一个结合this、声明提升、全局局部变量的例子:
var a=10;
function test(){
a=5;
alert(a);
alert(this.a);
var a;
alert(this.a);
alert(a);
}
执行test()和new test() 结果是什么
答案:
alert的内容:test(): 5,10,10,5
new test():5,undefined,undefined,5
补充3:this丢失(优先级)
// 用一个简单的例子开个头
// obj.fn是一种隐性绑定,将fn中的this指向obj
// 但是this又被context覆盖了,这种this丢失可以引申出优先级的问题。
obj.fn.call(context)
补充4:箭头函数
箭头函数的this继承上层函数
var obj = {
say: function () {
setTimeout(() => {
console.log(this) //obj
}, 0)
}
}
补充5
立即执行函数执行时,obj还是undefined
var obj = {
say: function () {
function _say() {
console.log(this) //window or global
}
return _say.bind(obj)
}()
}
obj.say()
补充6
var length = 10;
function fn() {
console.log(this.length);
}
var obj = {
length: 5,
method: function(fn) {
fn();
arguments[0](); // arguments.0()
}
};
obj.method(fn, 1);
// 10 2
补充7
var a=10;
var foo={
a:20,
bar:function(){
var a=30;
return this.a;
}
}
foo.bar()
(foo.bar)()
(foo.bar=foo.bar)()
(foo.bar,foo.bar)()
// 20 20 10 10
补充8
var num = 1;
function codequn(){
'use strict';
console.log('codequn: ',this.num++);
}
function codequn2(){
console.log('codequn2: ',++this.num);
}
(function(){
'use strict';
codequn2();
})();
codequn();
// codequn2: 2
// Cannot read property 'num' of undefined
补充9
箭头函数中的this是定义时所在对象的this,而不是执行时
const debounce = function(fn, time) {
let timeout = null
return function() {
const _self = this
clearTimeout(timeout)
timeout = setTimeout(()=>{
console.log(this === _self) //true
fn.call(this, ...arguments)
}, time)
}
}
参考:
《你不知道的javascript上卷》;
https://www.zhihu.com/questio...;
http://www.ruanyifeng.com/blo...;
https://developer.mozilla.org...;
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。