一句话总结:this的指向是在调用时确定的。
1,全局环境的this
function fn1(){
console.log(this);
}
function fn2(){
'use strict'
console.log(this)
}
fn1(); // window
fn2(); // undefined
1,在非严格模式下,this指向window。
2,在严格模式下,this指向undefined。
const fn = {
bar: 10,
bs: function(){
console.log(this);
console.log(this.bar);
}
}
var f = fn.bs;
f();
// window
// undefined
这里的this仍然指向window。因为f函数是在全局环境window下执行的。
如果改为如下形式会怎样?
const fn = {
bar: 10,
bs: function(){
console.log(this);
console.log(this.bar);
}
}
fn.bs(); // 10;
这里的this指向最后调用它的对象。在fn.bs()语句中,this指向fn对象。
如果this是被上一级的对象所调用,那么this指向的就是上一级的对象,否则指向全局环境。
2,上下文对象中调用的this
const foo = {
name: '千钧',
fn: function(){
return this;
}
};
console.log(foo.fn() === foo); // true
再看如下代码,当存在复杂嵌套关系时,this会指向最后调用它的对象。
const foo = {
name: '千钧',
obj:{
name: 'Lucy',
fn: function(){
return this.name;
}
}
}
console.log(foo.obj.fn()); // Lucy
再看更高阶的题目,看看如下代码的运行结果
const fn1 = {
text: 'fn1',
fn: function(){
return this.text;
}
}
const fn2 = {
text: 'fn2',
fn: function(){
return fn1.fn();
}
}
const fn3 = {
text: 'fn3',
fn: function(){
var fns = fn1.fn
return fns();
}
}
console.log(fn1.fn()); // fn1
console.log(fn2.fn()); // fn1
console.log(fn3.fn()); // undefined
fn3.fn()的this指向了window。
那么如何让fn2.fn()返回fn2呢?
const fn1 = {
text: 'fn1',
fn: function(){
return this.text;
}
}
const fn2 = {
text: 'fn2',
fn: fn1.fn
}
console.log(fn2.fn()); // fn2
3,通过bind、call、apply改变this指向
常见的问题就是bind、call、apply的区别,可以参考此文
用一句话来总结:它们是用来改变相关函数this指向的,但是call和apply是直接进行相关函数调用的;bind不会执行相关函数,而是返回一个新的函数,并绑定了新的this指向,可以手动调用。
const fn = function () {
console.log(this, arguments);
}
const target = {};
fn.call(target, 'arg1','arg2');
const target = {};
fn.apply(target, ['arg1', 'arg2']);
const target = {};
fn.bind(target, 'arg1', 'arg2');
以上三段代码是等价的。
我们再看看如下代码的执行结果:
const foo = {
name: 'fs',
fn: function(){
console.log(this.name);
}
};
const bar = {
name: '千钧'
};
console.log(foo.fn.call(bar)); // '千钧'
4,构造函数和this
function Fn(){
this.bar = 'qianjun';
};
const foo = new Fn();
console.log(foo.bar); // 'qianjun'
new操作符做的事情是什么?
- 创建一个新的对象。
- 将构造函数的this指向这个新的对象。
- 为这个对象添加属性、方法等。
- 最终返回新的对象。
需要注意的是,如果构造函数中出现了显示return的情况,可以分为两种情况:
1,构造函数显示返回一个值,且为对象,那么this就指向这个对象。
function Fn(){
this.user = 'qianjun';
const o = {};
return o;
}
const foo = new Fn();
console.log(foo.user); // undefined,因为foo为{}
2,如果返回不是一个对象(返回基本类型),this仍指向实例。
function Fn(){
this.user = 'qianjun';
return 1;
};
const foo = new Fn();
console.log(foo.user); // qianjun
5,箭头函数中的this
在箭头函数中,this的指向是由外层(函数或者全局)作用域来决定的。
const foo = {
fn: function(){
setTimeout(function(){
console.log(this);
})
}
}
console.log(foo.fn()); // window
如果需要这个函数指向foo,可以使用箭头函数
const foo = {
fn: function(){
setTimeout(() => {
console.log(this);
})
}
}
console.log(foo.fn()); // {fn: ƒ}
6,this优先级
显式绑定:call、apply、bind、new对this进行绑定的情况称为显示绑定。
隐式绑定:通过调用关系确定的this指向称为隐式绑定。
call、apply的绑定一般来说优先级更高。
new绑定的优先级比bind高。
箭头函数的绑定无法被修改。