this的指向
用一句话概括:this永远指向最后调用函数的对象
this可以理解为JS的动态作用域,而JS默认的静态作用域是在函数创建的时候就决定了。
var name = "windowsName";
function a() {
var name = "Cherry";
console.log(this.name); // windowsName
console.log("inner:" + this); // inner: Window
}
a();
console.log("outer:" + this) // outer: Window复制代
最后调用a的地方a(),前面没有调用的对象那么就是全局对象 window,这就相当于是 window.a()。如果使用严格模式的话,全局对象就是 undefined,那么就会报错 Uncaught TypeError: Cannot read property 'name' of undefined。
var name = "windowsName";
var a = {
name: "Cherry",
fn : function () {
console.log(this.name); // Cherry
}
}
a.fn();//Cherry
window.a.fn();//Cherry,最后调用的对象为a
a.fn()与window.a.fn()最后调用对象为a,所以this指向a
var name = "windowsName";
var a = {
// name: "Cherry",
fn : function () {
console.log(this.name); // undefined
}
}
window.a.fn();
最后调用对象为a,只会在a中查找,不会往上继续查找
var name = "windowsName";
var a = {
name : null,
// name: "Cherry",
fn : function () {
console.log(this.name); // windowsName
}
}
var f = a.fn;
f();
最后调用对象为window
var name = "windowsName";
function fn() {
var name = 'Cherry';
innerFunction();
function innerFunction() {
console.log(this.name); // windowsName
}
}
fn()
this优先级
- 第一层:世界尽头(全局)
优先级最低,在默认情况下是全局,浏览器里就是window,在严格模式下就是undefined
function showThis(){
console.log(this);
}
function showThisWithStrict(){
'use strict';
console.log(this);
}
showThis();//window
showThisWithStrict();//undefined
- 第二层:点石成金(.操作符)
说白了就是找函数前面的.操作符,如果用到this的函数属于某个上下文对象,那么这个上下文对象绑定到this。
遵循上文所说的"this指向最后调用它的对象"
var boss = {
name: 'boss',
returnThis () {
return this
}
}
boss.returnThis() === boss // true
遵循this指向最后调用它的对象:
var boss1 = {
name: 'boss1',
returnThis () {
return this
}
}
var boss2 = {
name: 'boss2',
returnThis () {
return boss1.returnThis()
}
}
var boss3 = {
name: 'boss3',
returnThis () {
var returnThis = boss1.returnThis
return returnThis()
}
}
// boss1
boss1.returnThis()
// boss1,实际上是调用boss1.returnThis()指向boss1
boss2.returnThis()
// undefined或window,实际上是window.returnThis()
boss3.returnThis()
把this绑定到boss2:
var boss1 = {
name:'boss1',
returnThis(){
return this
}
}
var boss2 = {
name:'boss2',
returnThis: boss1.returnThis
}
boss2.returnThis()//boss2
- 第三层:指腹为婚(call和apply)
Object.prototype.call和Object.prototype.apply,它们可以通过参数指定this。
由于函数的构造函数是function Function(),而Function.prototype是对象,即Function.prototype.proto === Object.prototype,所以函数(函数也是对象)拥有call和apply方法
function returnThis(){
return this;
}
var boss1 = { name: "boss1" };
returnThis();//window
returnThis.call(boss1);//boss1
returnThis.apply(boss1);//boss1
- 第四层:海誓山盟(bind)
Object.prototype.bind,会提供一个新函数来进行永久的this绑定,call和apply不能修改。
function returnThis(){
console.log(this.name);
}
var boss1 = { name:'boss1' };
//绑定this为boss1,并返回这个绑定后的函数
var bindBoss1ReturnThis = returnThis.bind(boss1);
bindBoss1ReturnThis();//boss1
var boss2 = { name:'boss2' };
bindBoss1ReturnThis.call(boss2);//boss1
bindBoss1ReturnThis.apply(boss2);//boss1
bindBoss1ReturnThis.bind(boss2)();//boss1
- 第五层:内有乾坤(new)
当我们使用new constructor实例化一个对象时,就会自动绑定this到对象上。会覆盖掉bind绑定的this。
function showThis(){
console.log(this);
}
new showThis(); //showThis实例
showThis(); //window
var boss1 = { name:'boss1' }
var boss1ShowThis = showThis.bind(boss1);
boss1ShowThis();//boss1
new boss1ShowThis(); //showThis实例
- 第六层:军令如山(箭头函数)
箭头函数里的this,被封印到当前词法作用域之中,称作Lexical This,在代码运行前就可以确定。
箭头函数的作用就相当于把this这个原本为动态作用域的,改成静态作用域,在函数创建时就能够通过箭头函数把this确定下来。
箭头函数中没有this绑定,必须通过查找作用域链(静态作用域的特性)来决定其值,如果箭头函数被非箭头函数包含,则this绑定的是最近一层非箭头函数的this,否则,this为undefined
其余五层的this都是动态作用域,不会根据作用域链向上找,只会根据当前上下文对象的this查找,箭头函数的this,在函数创建的时候就已经确定,为最近的不为箭头函数的this
var name = "windowsName";
var a = {
name : "Cherry",
func1: function () {
console.log(this.name)
},
func2: function () {
setTimeout( () => {
this.func1()
},100);
}
};
a.func2() // Cherry
var returnThis = () => this
returnThis() // window
new returnThis() // TypeError
var boss1 = {
name: 'boss1',
returnThis () {
var func = () => this
return func()
}
}
returnThis.call(boss1) // still window
var boss1returnThis = returnThis.bind(boss1)
boss1returnThis() // still window
boss1.returnThis() // boss1
var boss2 = {
name: 'boss2',
returnThis: boss1.returnThis
}
boss2.returnThis() // boss2
最近的不为箭头函数的this,依旧遵循上述规则,是动态作用域:
boss1.returnThis.call(window),修改了returnThis的this指向,在执行returnThis的时候,创造箭头函数func,此时this绑定为returnThis的this,当前returnThis的this为window,所以func中的this也指向window.
this的特殊情况
在"," "=" "||"操作符的情况下,this指向为全局
var value = 1;
var foo = {
value: 2,
bar: function () {
return this.value;
}
}
//示例1
console.log(foo.bar()); // 2
//示例2
console.log((foo.bar)()); // 2
//示例3
console.log((foo.bar = foo.bar)()); // 1
//示例4
console.log((false || foo.bar)()); // 1
//示例5
console.log((foo.bar, foo.bar)()); // 1