深入js——this

this

this是与执行上下文绑定的,每个执行上下文都有一个this;执行上下文有3种:全局执行上下文、函数执行上下文和eval执行上下文,因此this也有3种,全局执行上下文中的this、函数执行上下文中的this和eval执行上下文中的this。eval我们很少使用,因此这里我们只讨论全局执行上下文中的this、函数执行上下文中的this。

全局执行上下文的this

在全局执行上下文中,this指向全局对象,因此在浏览器环境中,this执行window。

函数执行上下文的this

函数执行上下文的this有些复杂,主要是因为它与作用域不同,不是静态绑定到一个函数的,而是与函数如何被调用有关,也就是说一个函数每次的this可能不一样。

这里尤其要记住,不要混淆作用域和this,这两者可以说没有任何关系,作用域是在函数定义时就确定的,而this是在函数调用时确定的。

JavaScript中共有以下4种函数调用方式:

  • 对象调用方法方式;
  • 函数调用方式;
  • apply/call方式;
  • 构造函数方式;

对象调用方法方式

当一个函数被保存为对象的一个属性时,我们称此函数为方法。使用对象来调用其内部的一个方法,该方法的 this 是指向对象本身的

var obj ={
  value:3,
  dosth:function(){
    return this.value;//通过obj.do()调用时,this指向obj
  }
}
console.log(obj.dosth());//3

函数调用方式

当一个函数并非一个对象的属性时,那么它就是被当做一个函数来调用的。此时,相当于再全局环境中调用此函数,this指向全局对象

var dosth = function(){
  return this.value;
}
console.log(dosth());//undefined
var value= 2;
console.log(dosth());//2

通过call/apply方式

apply/call是最直观的可以看出this指向的调用模式,在apply/call中指定的第一个参数就是要绑定给this的值

var value = 2;
var obj ={value:3}
obj.double = function(){
  var helper = function(){
    this.value = this.value*2;
  }
 helper.call(obj);//改变调用方式
}
obj.double();
console.log("obj的value值为:"+obj.value+",window的value值为:"+value);//obj的value值为:6,window的value值为:2

不过要注意,在非严格模式下,当第一个参数为null或undefined时,this将指向window。

构造函数方式

当一个函数采用new操作符调用时,它就成为构造函数。也就是说,构造函数只是普通函数,只是在new的那一刻,其被成为构造函数。通过new操作符调用一个函数时,new操作符背后干了4件事:

  • 创建一个空对象obj
  • 将obj的原型指向构造函数(这样obj就可以访问到构造函数原型中的属性)
  • 使用call,改变构造函数this的指向到obj,并执行构造函数代码(这样obj就可以访问到构造函数中的属性)
  • 返回新对象

因此,构造函数中的this就是新对象本身

嵌套函数中的this不会从外层函数中继承

这可以算是一个JavaScript的设计问题,也就是当采用上文提到的第2种调用方式——函数调用方式时,this始终指向window,这会导致内部函数调用时this无法指向外部函数的this(很多情况下我们是希望指向外部函数的this)。

var obj ={value:3}
obj.double = function(){
  var helper = function(){
    this.value = this.value*2;
  }
  helper();
}
obj.double();
console.log("obj的value值为:"+obj.value+",window的value值为:"+value);//obj的value值为:3,window的value值为:4

可以发现,执行了obj.double()后,obj.value值并没有变化,而全局变量value的值*2了。因为helper虽然在obj.double内部,但其采用函数模式调用时,this指向的是window而不是obj。解决这个问题也很简单:

  • 方案一:将this赋值给其他变量保存
var value = 2;
var obj ={value:3}
obj.double = function(){
  var that = this;//将this赋值给that
  var helper = function(){
    that.value = that.value*2;
  }
  helper();
}
obj.double();
console.log("obj的value值为:"+obj.value+",window的value值为:"+value);//obj的value值为:6,window的value值为:2

此方法采用一个变量that来保存this,这样helper函数里使用that时其实就与this无关了,就是在使用一个普通的变量。其实,这个方法的的本质是把 this 体系转换为了作用域的体系

  • 方案二:es6的箭头函数
var value = 2;
var obj ={value:3}
obj.double = function(){
  var helper = () => {
    this.value = this.value*2;
  }
  helper();
}
obj.double();
console.log("obj的value值为:"+obj.value+",window的value值为:"+value);//obj的value值为:6,window的value值为:2

ES6中的箭头函数并不会创建其自身的执行上下文,所以箭头函数中的this取决于它的外部函数

posted @ 2020-01-19 15:25  小丸子的城堡  阅读(184)  评论(0编辑  收藏  举报