this
-
执行上下文环境: 变量环境、词法环境、外部环境、this
-
javascript的执行上下文环境:
- 全局执行上下文:任何不在函数内部的代码都在全局上下文中,它会执行两件事:创建一个全局的window对象(浏览器的情况下),并且设置this的值等于这个全局对象。一个程序中只会有一个全局执行上下文。
- 函数执行上下文:每次当函数被调用时,就会为该函数创建一个新的上下文环境。每个函数都有自己的执行上下文,但是只有在函数被调用时才会被创建。函数上下文可以有任意多个。
- eval执行上下文:执行eval函数内部的代码时,同样会创建一个执行上下文,但是由于javascript开发者无法访问到它,因此我们在这里忽略它。
-
执行上下文栈
- 一个全局上下文和无数个函数上下文组成了一个执行上下文栈。
- 一个函数的执行上下文,在函数执行完毕后,会被移出执行上下文栈。
-
函数this的指向
this 是javascript的一个关键字,多数情况下this指向调用他的对象 【首先,this指向的应该是一个对象(函数执行上下文对象)。其次,这个对像指向的是调用他的对象,如果调用他的不是对象或者对象不存在,则会指向全局对象】
-
作为对象的方法调用([隐式绑定])
- 当函数作为对象的方法被调用时,this指向该对象
- 列子:
var obj = { a: 1, getA: function() { alert(this === obj); // true alert(this.a); // 1 } }; obj.getA();
-
作为普通函数调用([默认绑定])
- 当函数不作为对象的属性被调用时,也就是我们常说的普通函数方式,此时的this总是指向全局对象。在浏览器的javascript里,这个全局对象是window对象。
- 列子:
window.name = 'globalName'; var getName = function() { return this.name; }; console.log(getName()); // globalName
-
构造器调用([new绑定])
- 当用new运算符调用函数时,该函数总会返回一个对象,通常情况下,构造器里的this就指向返回的这个对象。
- 列子:
var MyClass = function() { this.name = 'sven'; }; var obj = new MyClass(); console.log(obj.name); // sven
-
Function.prototype.call或Function.prototype.apply调用,Function.prototype.bind调用([显式绑定])
- call和apply可以动态的改变传入函数的this
- bind方法会创建一个新函数,称为绑定函数,当调用这个绑定函数时,绑定函数会以创建它时传入 bind()方法的第一个参数作为 this,传入 bind() 方法的第二个以及以后的参数加上绑定函数运行时本身的参数按照顺序作为原函数的参数来调用原函数。
- 列子:
var obj1 = { name: 'sven', getName: function() { return this.name; } }; var obj2 = { name: 'anne' }; console.log(obj1.getName()); // sven console.log(obj1.getName.call(obj2)); // anne
-
ES6箭头函数
- 箭头函数的this指向定义时所在的对象,而不是执行时所在的对象。
- 列子:
var name = 'globalName'; var obj = { name: 'sven', getName: () => { return this.name; } }; console.log(obj.getName()); // globalName
-
this的指向优先级
- new绑定 > 显式绑定 > 隐式绑定 > 默认绑定
- 列子:
var name = 'globalName'; var obj1 = { name: 'sven', getName: function() { return this.name; } }; var obj2 = { name: 'anne' }; console.log(obj1.getName()); // sven console.log(obj1.getName.call(obj2)); // anne console.log(obj1.getName.apply(obj2)); // anne console.log(obj1.getName.bind(obj2)()); // anne console.log(new obj1.getName()); // obj1 console.log(new obj1.getName.call(obj2)); // obj2 console.log(new obj1.getName.apply(obj2)); // obj2 console.log(new obj1.getName.bind(obj2)()); // obj2 ```
-
特殊的this指向
-
间接调用
- 间接调用中的this指向全局对象
- 列子:
var name = 'globalName'; var obj = { name: 'sven', getName: function() { return this.name; } }; var getName = obj.getName; console.log(getName()); // globalName
-
被忽略的this
- 当函数被当作参数传递,并且被别的函数所调用时,this指向全局对象
- 列子:
var name = 'globalName'; var obj = { name: 'sven', getName: function() { return this.name; } }; var getName = obj.getName; var obj2 = { name: 'anne', getName: function() { return getName(); } }; console.log(obj2.getName()); // globalName
-
setTimeout()
中的thissetTimeout()
中的this指向全局对象- 列子:
var name = 'globalName'; var obj = { name: 'sven', getName: function() { setTimeout(function(){ console.log(this.name); // globalName }, 1000); } }; obj.getName(); var obj2 = { name:'anne', getName:function(){ setTimeout(()=>{ console.log(this.name); // anne },1000) } } obj2.getName();
-
addEventListener()
中的thisaddEventListener()
中的this指向绑定事件的元素- 列子:
var name = 'globalName'; var obj = { name: 'sven', getName: function() { document.addEventListener('click', function() { console.log(this.name); // globalName }, false); } }; obj.getName();
-
立即执行函数
- 立即执行函数中的this指向全局对象
- 列子:
var name = 'globalName'; var obj = { name: 'sven', getName: function() { (function() { console.log(this.name); // globalName })(); } }; obj.getName();
-
-
this的指向总结
- this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象。
- 在js中,函数的执行有4种方式,即函数调用模式、方法调用模式、构造器调用模式和apply调用模式。不同的调用方式,this的指向不同。
- 优先级:new绑定 > 显式绑定 > 隐式绑定 > 默认绑定
- 间接调用中的this指向全局对象
- 被忽略的this指向全局对象
- setTimeout中的this指向全局对象
- addEventListener中的this指向绑定事件的元素
- 立即执行函数中的this指向全局对象
- 箭头函数的this指向定义时所在的对象,而不是执行时所在的对象。