一、js默认绑定
在全局声明的对象或者函数都会被认为是window对象下的,这时候默认this是绑定到全局作用域下的window对象下
function foo(){
console.log(this.a);
}
var a=2;
foo();
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
return function(){
return this.name;
};
} };
alert(object.getNameFunc()()); //"The Window"
由于getNameFunc函数返回一个函数,因此这个函数会立即执行,函数会搜索this和argument,只能搜索到活动对象为止,不能访问外部函数这两个变量。执行变成
var func = object.getNameFunc(); func(); //这个func结果在全局作用域执行了,没在object活动作用域执行
从而导致最终调用函数的执行环境是window
我们使用闭包可以改进如下代码
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
var that = this;
return function(){
return that.name;
};
}
};
alert(object.getNameFunc()()); //"My Object"
二、隐式绑定
当函数引用时候存在上下文的时候会产生隐式绑定 this总是指向调用该函数的对象,就是看点前面的变量是谁,this就指向谁(看执行函数前面有没有点)
var a=3;
function foo(){
console.log(this.a);
}
var obj={
a:2,
foo:foo
}
foo(); //3
obj.foo(); //2
三、显式绑定
显示绑定就是常用的call,apply,bind函数强制绑定this的指向
具体实现方式可以参考 call,apply、bind实现原理这篇文章
四、new绑定
function lala(a){
this.a=a;
}
foo(4);
var obj=new lala(2);
console.log(a); // 4
console.log(obj.a); // 2
new的源代码中会将传入的构造函数的prototype赋值给一个新new出来的object对象的-proto-属性上,同时会使用apply去改变this指向将传入的构造函数的this指向改变到新new出来的object对象上面去 从而实现构造函数的继承,将传入的一些属性继承下来,实现原理如下
function objectFactory() {
var obj = new Object();
var [Constructor, ...args] = [ ...arguments];
obj.__proto__ = Constructor.prototype;
Constructor.apply(obj, args);
return obj;
};
五、
但是在settimeout里面就有所不同,这是由于setTimeout()调用的代码运行在与所在函数完全分离的执行环境上。这会导致这些代码中包含的 this 关键字会在
非严格模式下指向 window (或全局)对象
严格模式指向undefined
那么需要使用箭头函数绑定this,看下面🌰
var obj={
num:3,
fn:function(){
setTimeout(function(){
console.log(this.num);
});
}
}
obj.fn();//undefined
var obj1={
num:4,
fn:function(){
setTimeout(() => {
console.log(this.num);
});
}
}
obj1.fn();//4
箭头函数没有自己的this,是继承来的,箭头函数的this指向的是谁调用箭头函数的外层function,箭头函数的this就是指向该对象,如果箭头函数没有外层函数,则指向window。这样可以方便地让我们在 setTimeout ,setInterval中方便的使用this。此问题也可以使用bind来绑定this,或者将this存在一个变量来调用
var c = {
lala: 2,
fun: () => {
console.log(this, '//////'); // 这里的this指向window 箭头函数外层没有function
this.lala++;
console.log(this.lala);
}
}
c.fun();
c.fun();
var c = {
lala: 2,
fun: function() {
return () => {
console.log(this, '//////'); // 这里的this指向c 因为箭头函数外层有function,这个function是c调用
this.lala++;
console.log(this.lala);
}
}
}
c.fun()();
c.fun()();