前端基础整理之this

428 阅读3分钟

一句话总结: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高。

箭头函数的绑定无法被修改。