JavaScript this探究

关于javascript的this讲解的文章已经多如牛毛了,我本人在开发过程中也用到过很多次。这次趁有空,整理一下关于this的一系列问题:包括this的指向,严格模式和非严格模式下的区别,什么情况下可以改变this的指向以及在ES6下箭头函数中this的指向。

一.严格模式下this的指向

严格模式下:

function aa(){
    'use strict';
     console.log(this)   //undefined
}
aa();  

非严格模式下:

function aa(){
    console.log(this)   //window
}
aa();  

二.this的指向

MDN中对this的解释如下:

在绝大多数情况下,函数的调用方式决定了this的值。this不能在执行期间被赋值,并且在每次函数被调用时this的值也可能会不同。

简单点来说,this的指向在声明时是未定义的,只有在它被调用时才会被赋值,要搞清楚它到底指向什么,只要搞清楚到底谁调用它即可。

下面有几种情况可以帮助我们加快理解this的指向问题:

1.第一种情况:

function aa(){
  console.log(this)   //window
}
aa();

此时是window对象调用了aa()函数,所以this指向window。

2.第二种情况

var test = {
  aa:"hello",  
  bb:function(){
    console.log(this.aa)  //"hello"
  }
}
test.bb();

此时是test对象调用了this,所以this此时指向的bb对象中的aa;

var test = {
  aa:"hello",  
  bb:function(){
    console.log(this)  //test (object)
  }
}
test.bb();

此时就很清晰的能看到this指向的test对象。

3.第三种情况

var test = {
  aa:"hello",  
  bb:{
    aa:'hello2',
    cc:function(){
        console.log(this.aa)  //"hello2"
     }
  }
}
test.bb.cc();

此时调用cc中this的对象是bb,而不是test,所以this指向的是bb。

以上三个例子已经比较清晰的解释了this的指向问题:
谁最后调用了this,谁就是this指向的对象。

三.什么情况下this的指向会被改变

这些情况大致可以分为两类:

1.关键字类。主要有new,return
2.函数类。 主要有call,apply,bind

第一类.关键字类
我们先看new的例子:

function aa(){
   this.name = "Tom"    
}

var bb = aa(); //bb is undefined;
var bb = new aa();
console.log(bb.name)  //"Tom"

new关键字的关键在于实例化了构造函数aa()。使它的函数能够顺利的拿到里面的name。

return的例子:

function aa(){
   this.name = "Tom";
   return {};
}
var bb = new aa();
console.log(bb.name)  //undefined

当return的内容是一个对象时,则this会指向这个对象。

function aa(){
   this.name = "Tom";
   return 'aaa';
}
var bb = new aa();
console.log(bb.name)  //"Tom"

当return的内容是一个非对象时,则this的指向不会发生改变。

第二类.函数类

1.call()函数
老规矩,先关门放MDN。

call() 方法调用一个函数,其具有一个指定的this值和分别地提供的参数(参数的列表)。

简单来说就是可以通过call()函数来指定你想调用的this所造的环境,同时还可以追加多个参数。
以下是MDN上的官方示例:

function Product(name, price) {
  this.name = name;
  this.price = price;
}

function Food(name, price) {
  Product.call(this, name, price);
  this.category = 'food';
}

console.log(new Food('cheese', 5).name);
// expected output: "cheese"

如果没有调用call()函数,最后打印的应该是food,调用后才会改成cheese。如果觉得上面的例子还不够清晰,我们可以再看一个,如果觉得ok了,请跳过。

var aa = {
   name:"tom",
   bb:function(x, y){
        console.log(this.name);  //"tom"
        console.log(x,y);  // 1,2
   }
}

var b = aa.bb
b.call(aa);
b.call(aa,1,2)

2.apply函数

apply() 方法调用一个具有给定this值的函数,以及作为一个数组(或类似数组对象)提供的参数。
该方法的作用和 apply()方法类似,只有一个区别,就是call()方法接受的是若干个参数的列表,而apply()方法接受的是一个包含多个参数的数组。

var aa = {
   name:"tom",
   bb:function(x, y){
        console.log(this.name);  //"tom"
        console.log(x,y);  // 1,2
   }
}
var b = aa.bb
b.apply(aa,[1,2])

3.bind函数

bind()方法创建一个新的函数, 当这个新函数被调用时其this置为提供的值,其参数列表前几项置为创建时指定的参数序列。

var module = {
  x: 42,
  getX: function() {
    return this.x;
  }
}

var unboundGetX = module.getX;
console.log(unboundGetX()); // The function gets invoked at the global scope
// expected output: undefined

var boundGetX = unboundGetX.bind(module);
console.log(boundGetX());
// expected output: 42

需要注意的是,bind函数与apply和call都有所不同,不同之处在于bind不是立即执行的。

bind() 函数会创建一个新绑定函数,绑定函数与被调函数具有相同的函数体(在 ECMAScript 5 中)。

我们看一个例子:

var aa = {
    name:"tom",
    bb:function(){
        console.log(this.name)
    }
}

var cc = aa.bb;
var dd = cc.bind(aa);
console.log(dd);  //type function aa()
dd(); // "tom"

三.ES6箭头函数中的this

箭头函数与其他函数区别很大,我们直接看MDN:

箭头函数表达式的语法比函数表达式更短,并且没有自己的this,arguments,super或 new.target。

function Person(){
  this.age = 0;

  setInterval(() => {
    this.age++; // |this| 正确地指向person 对象
  }, 1000);
}

var p = new Person();

当然,通过相关函数也不能改变=>中的this指向。

通过 call 或 apply 调用
由于 箭头函数没有自己的this指针,通过 call() 或 apply() 方法调用一个函数时,只能传递参数(不能绑定this—译者注),他们的第一个参数会被忽略。(这种现象对于bind方法同样成立—译者注)

总结一下,在箭头函数中,是没有它自己的this的,它只会从自己的作用域链的上一层继承this。
我们来看例子:

var obj = {
    fn:()=>{
        console.log(this)  //window
    }
};
obj.fn();

再看一个:

function obj(){
  let aa = ()=>{
    console.log(this);
  }
  aa();
}

obj() // window
var bb = new obj(); //obj type object

第二个例子中,new obj()后之所以打印出了obj(),是因为new关键字绑定了this到返回的新的对象object中。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章