本文已参与好文召集令活动,点击查看:后端、大前端双赛道投稿,2万元奖池等你挑战! javascript
使用 JavaScript 开发的时候,不少开发者多多少少会被 this 的指向搞蒙圈,可是实际上,关于 this 的指向,记住最核心的一句话:哪一个对象调用函数,函数里面的 this 指向哪一个对象。前端
下面咱们针对这几种状况,举例并说明原理:java
// 声明位置
var test = function(){
console.log(this.x)
}
var x = "2";
var obj = {
x:"1",
fn:test,
}
// 调用位置
obj.fn(); // 1
test(); // 2
复制代码
以上代码,能够看到,this 指向调用它所在方法的对象,test 方法在 obj 对象下,因此 this 指向 obj,test 在window 对象下,因此 this 指向 window。也能够看出来:this和声明位置无关,和调用位置有关。后端
可是下面这个状况得注意数组
let obj1={
a:222
};
let obj2={
a:111,
fn:function(){
console.log(this.a);
}
}
obj1.fn = obj2.fn;
obj1.fn(); // 222
复制代码
这个不难理解,虽然 obj1.fn 是从 obj2.fn 赋值而来,可是调用函数的是obj1,因此 this 指向 obj1。markdown
var a = 1;
function fn1(){
console.log(this.a); // 1
}
fn1();
window.b = 2;
function fn2(){
console.log(this.b); // 2
}
fn2();
//能够理解为 window.fn();
复制代码
匿名函数,setTimeout:app
(function(){
console.log(this); // window
})();
setTimeout(() => {
console.log(this); // window
}, 0);
setTimeout(function(){
console.log(this); // window
}, 0);
复制代码
var flag = undefined;
function Fn(){
flag = this;
}
var obj = new Fn();
console.log(flag === obj); // true
复制代码
这个 this 指向 obj,内部原理仍是用 apply 把 this 指向obj的,回忆下JavaScript中 new 一个对象过程详解。函数
call 和 apply 的做用,彻底同样,惟一的区别:参数; call 接收的参数不固定,第一个参数是函数体内 this 的指向,第二个参数如下是依次传入的参数。 apply接收两个参数,第一个参数也是函数体内 this 的指向。第二个参数是一个集合对象(数组或者类数组)oop
var obj = {
name:'111',
getName:function(){
console.log(this.name)
}
};
var otherObj = {
name:'222',
};
var name = '333';
obj.getName(); // 111
obj.getName.call(); // 333
obj.getName.call(otherObj); // 222
obj.getName.apply(); // 333
obj.getName.apply(otherObj); // 222
obj.getName.bind(this)(); // 333
obj.getName.bind(otherObj)();// 222
复制代码
关于 ES6 中的箭头函数,官方的解释是: 箭头函数里面的 this 是上下文( context ), 外部做用域的 this 就是箭头函数内的 this。post
判断箭头函数的 this:
技巧:它的外层没有函数,this 是 window;外层有函数,看外层函数的 this 是谁,它的 this 就是谁。
外层函数多是常规函数多是箭头函数,判断外层的 this 要根据函数种类用不一样方法:
外层函数是常规函数就看外层函数是被谁调用的;
外层是箭头函数就根据刚才说的技巧来判断;
let obj={
a:222,
fn:function(){
setTimeout(()=>{console.log(this.a)});
}
};
obj.fn(); // 222
复制代码
var name = 'window';
var A = {
name: 'A',
sayHello: () => {
console.log(this.name)
}
}
A.sayHello(); // 输出的是window,根据刚才讲的规则就能够判断
// 那如何改形成永远绑定A呢:
var name = 'window';
var A = {
name: 'A',
sayHello: function(){
var s = () => console.log(this.name)
return s//返回箭头函数s
}
}
var sayHello = A.sayHello();
sayHello();// 输出A
复制代码
var globalObject = this;
var foo = (() => this);
console.log(foo() === globalObject); // true
var obj = {foo: foo};
console.log(foo.call(obj) === globalObject); // true
foo = foo.bind(obj);
console.log(foo() === globalObject); // true
复制代码
非严格模式下,this 默认指向全局对象 window;
// 非严格模式
function f1(){
return this;
}
console.log(f1() === window); // true
复制代码
严格模式下, this 为undefined;
// 严格模式
"use strict";
var fn2 = function(){
return this
}
console.log(fn2() == undefined); // true
复制代码