this的原理
JavaScript 中的
this
是一个特殊的关键字,其值在函数被调用时绑定的。this
的值取决于函数的调用方式,它不是在函数创建时绑定的,而是在运行时基于函数的执行环境动态绑定的。
正如上面所讲,this 是在运行时绑定的,它的上下文取决于函数调用时的各个条件。在 JavaScript 中函数的调用有以下几种方式:
- 默认绑定规则
- 隐式绑定规则
- 显式绑定规则
- 构造函数中的
this
- 箭头函数中的
this
下面我们按照调用方式不同,分别讨论 this 的含义
默认绑定规则
在默认绑定规则中,独立函数调用时,this指向全局对象; 函数在哪个词法作用域中生效,this指向哪里
例如:
javascript
function foo(){
var a=1;
console.log(this.a); //此时this指向window
}
foo();//undefined
在上面的例子中foo
函数作为独立函数被调用,,因此this指默认绑定到全局(window)对象上,所以this.a
的值指向的就是全局变量中a
的值,因此输出结果是undefined。
又如:
scss
var b=2;
function foo(){
var b=1;
function bar(){
console.log(this.b);//此时this依然指向window
}
bar()
}
foo() //在node下为undefined,在浏览器中为2
通过这个例子我们可以知道,即使bar函数定义在了foo
函数中,可是bar
在foo
中并没有进行调用,而是在window中进行的调用。因此我们就可以理解独立函数调用时,this指向全局对象的含义了。
隐式绑定规则
隐式绑定规则指的是当函数作为对象的方法被调用时,函数内部的 this
默认指向调用该方法的对象。 例如:
javascript
let obj={
speak: 'hello',
say: function(){
console.log(this.speak); // this指向obj
}
}
obj.say(); //hello
在上面的例子中say
函数作为obj
对象的方法进行调用,因此函数内部的 this
指向了 obj
对象,可以通过 this.speak
访问 obj
对象中的 speak
属性。 又如下一个例子:
javascript
function foo(){
console.log(this.a); // this指向obj
}
var obj ={
a: 1,
foo: foo
}
var obj2={
a: 2,
obj: obj
}
obj2.obj.foo();// 1
通过这个例子我们可以看出此时foo
函数是作为obj
对象的方法进行调用的,尽管obj2调用了obj但是任然输出的是obj
中的a
,所以当函数被多个对象链式调用时,this指向引用函数的那个对象。
显式绑定规则
显式绑定是通过使用 call
, apply
, bind
方法,可以手动指定函数执行时的 this
值的一种方法。 例如:
scss
function foo(x,y){
console.log(this.a,x+y);//thi指向obj
}
var obj = {
a: 1,
};
foo.call(obj,4,5) // 1,9
foo.apply(obj,[4,5]) // 1,9 接收参数需要使用数组接收
let bar=foo.bind(obj,4,5)() // 1,9 返回一个函数,需要手动调用
通过以上例子,我们可以看到this
通过 call
, apply
, bind
方法,被绑定到了obj
上。但是需要注意的是,apply
方法它接收的参数是作为一个数组传递,而不是一个一个地传递参数。bind()
方法会创建一个新函数,并将函数中的 this
绑定到指定的对象,但并不会立即执行该函数。而是返回一个绑定了指定上下文的新函数,稍后可以被调用。
构造函数中的 this
当使用 new
关键字调用构造函数时,this
将指向新创建的实例对象。 例如:
ini
var a=1;
function foo(){
this.a=2;
this.b=3;
}
var obj=new foo(); //new的时候,this指向实例对象
console.log(obj.a,obj.b); //2,3
通过上面的例子我们可以看出,foo
是一个构造函数,当使用new
创建一个obj
实例对象时,this
指向了新创建的obj
对象,通过 this.a
和 this.b
,初始化了 obj
对象的属性。
箭头函数中的 this
在箭头函数中,this
是根据词法作用域来确定的,而不是在函数调用时确定的。箭头函数没有自己的 this
,它会捕获函数定义时所处的上下文的 this
值。 例如:
javascript
var obj ={
a:1
}
function foo(){
var bar=()=>{
console.log(this)//输出结果为{a:1} 此时this指向obj
}
bar()
}
foo.call(obj)//箭头函数里面没有this,所以this指向的是外层的this
通过上面的例子我们可以看出,此时this
指向的是obj
,因此我们可以得出箭头函数的this
指向定义时所在的对象,而不是使用时所在的对象,箭头函数没有this
,写在箭头函数中的this
也是它外层普通函数的this
。
总结
通过以上例子,我们可以得出:
- 默认绑定规则: 当函数独立调用时,
this
默认指向全局对象(在浏览器环境下是window
对象)或者在node模式下是undefined
。- 隐式绑定规则: 当函数作为对象的方法调用时,
this
指向调用该方法的对象。- 显式绑定规则: 使用
call
,apply
,bind
方法,可以手动指定函数执行时的this
值。- 构造函数中的
this
: 使用new
关键字调用构造函数时,this
指向新创建的实例对象。- 箭头函数中的
this
: 箭头函数没有自己的this
,它会捕获函数定义时所处的上下文的this
值。