理解JavaScript之this

ECNAScript规范中这样描述this:

this 关键字执行为当前执行环境的 ThisBinding。

MDN上这样描述this:

In most cases, the value of this is determined by how a function is called.

在绝大多数情况下,函数的调用方式决定了this的值。

在JavaScript中,this的指向是调用时决定的,而不是创建时决定的。this的不确定性是把双刃剑,一是函数调用时的对象不确定性,是js中函数的使用具有很大灵活性,每个对象都可以借用其他函数来完成功能。二是这也造成了this学习的一些迷惑性。

调用位置

调用位置就是函数在代码中被调用的位置,而不是声明的位置。

通过分析调用栈(到达当前执行位置多调用的所有函数)可以找到调用位置。

var obj = {
  foo: function () {}
};

var foo = obj.foo;

// 写法一
obj.foo()

// 写法二
foo()

上面的代码中,obj.foo()和foo()指向同一个函数,但是执行结果可能不一样,差异的原因,在于函数体内使用了this关键字,对obj.foo()来说,foo运行在obj的执行上下文中,this指向obj,对于foo()来说,foo()指向执行上下文,this指向执行上下文。因此,运行结果不一样。

全局上下文

在全局执行上下文中,this指向全局对象

  • this等价于window对象
  • var === this. === window

在非严格模式中,当this指向undefined时,它会被自动指向全局对象。在实际开发中,现在基本已经全部采用严格模式了,而最新的ES6,也是默认支持严格模式。

console.log(window === this); // true
var a = 1;
this.b = 2;
window.c = 3;
console.log(a + b + c); // 6

 

在浏览器里面,this等价于window对象,如果声明了全局变量,则全局变量会作为this的属性。

函数上下文

函数内部,this的值取决于函数被调用的方式,在函数执行过程中,this一旦被确定,就不可更改了。

如果调用者函数,被某一个对象所拥有,那么该函数在调用时,内部的this指向该对象。如果函数独立调用,那么该函数内部的this,则指向undefined。

直接调用

this指向全局变量

function foo(){
  return this;
}
console.log(foo() === window); // true

call()、apply()

this指向绑定的对象

var person = {
  name: "axuebin",
  age: 25
};
function say(job){
  console.log(this.name+":"+this.age+" "+job);
}
say.call(person,"FE"); // axuebin:25
say.apply(person,["FE"]); // axuebin:25

say()本身没有name、age属性,通过call()和apply()绑定到person对象上,输出的就是属于person的属性,此时this指向person。

call()和apply()从this的绑定角度上来说是一样的,唯一不同的是它们的第二个参数。

call(thisArg, arg1 ,arg2 ...);  //直接接收参数传递给函数
apply(thisArg, [arg1 ,arg2 ...]) //接收一个参数数组

bind()

this将永久绑定到bind的第一个参数。bind和call、apply有些相似。

var person = {
  name: "axuebin",
  age: 25
};
function say(){
  console.log(this.name+":"+this.age);
}
var f = say.bind(person);
console.log(f());
//bind()方法创建一个新的函数, 当这个新函数被调用时this键值为其提供的值,
//其参数列表前几项值为创建时指定的参数序列。
//fun.bind(thisArg[, arg1[, arg2[, ...]]])

箭头函数

所有的箭头函数都没有自己的this,都指向外层。

MDN对于箭头函数的描述:

An arrow function does not create its own this, the this value of the enclosing execution context is used.

箭头函数会捕获其所在上下文的this值,作为自己的this值。

function foo() {  
  setTimeout(()=>{
    console.log(this.a);
  },100)
}
var obj = {
  a: 2
}
foo.call(obj); //2

箭头函数常用语回调函数中,例如定时器中

作为对象的一个方法

this指向调用函数的对象

var person = {
  name: "axuebin",
  getName: function(){
    return this.name;
  }
}
console.log(person.getName()); // axuebin

作为一个构造函数

this被绑定到正在构造的新对象

通过构造函数创建一个对象其实执行这样几个步骤:

  1. 创建新对象
  2. 将this指向这个对象
  3. 给对象赋值(属性、方法)
  4. 返回this

所以this就是指向创建的这个对象上。

function Person(name){
  this.name = name;
  this.age = 25;
  this.say = function(){
    console.log(this.name + ":" + this.age);
  }
}
var person = new Person("axuebin");
console.log(person.name); // axuebin
person.say(); // axuebin:25

作为一个DOM事件处理函数

this指向触发事件的元素,也就是事件处理程序所绑定的DOM节点

var ele = document.getElementById("id");
ele.addEventListener("click",function(e){
  console.log(this);
  console.log(this === e.target); // true
})

HTML标签内敛时间处理函数

this指向所在的DOM元素

jQuery的this

在许多情况下JQuery的this都指向DOM元素节点。

总结

如果要判断一个函数的this绑定,就需要找到这个函数的直接调用位置。然后可以顺序按照下面四条规则来判断this的绑定对象:

  1. 由new调用:绑定到新创建的对象
  2. 由call或apply、bind调用:绑定到指定的对象
  3. 由上下文对象调用:绑定到上下文对象
  4. 默认:在严格模式下绑定到 undefined,否则绑定到全局对象。

注意:箭头函数不使用上面的绑定规则,根据外层作用域来决定this,继承外层函数调用的this绑定。没有外层函数,则是绑定到全局对象(浏览器中是window)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值