likes
comments
collection
share

this: 这给我指哪来了?

作者站长头像
站长
· 阅读数 20

前言:为什么要有this?

在 JavaScript 中,this 的指向是一个较为复杂但又非常重要的概念。this 的具体指向并非固定不变,而是根据函数调用的方式和上下文来动态确定。

那么,为什么要有this?答案是为了让对象中的函数有能力访问对象自己的属性,this可以显著的提升代码质量,减少上下文参数的传递。

疑问

奇怪,当同一段代码分别在Node上和浏览器上分别输出了不同的答案,你到底该相信谁呢?

function foo(){
    console.log(this.a);
}

var a = 1;

foo();

this: 这给我指哪来了?

如图可见,在Node上和浏览器上的输出分别是undefined1

实际上它们都没有错,只是因为这两种环境下this的词法作用域不同,在Node中this指向的是一个空对象,而在浏览器环境中 this 指向的是全局对象 window

this的绑定规则

1. 默认绑定:

当一个函数独立调用,不带任何修饰符的时候 :函数在哪个词法作用下生效,函数中的this就指向哪里 -- (只要是默认绑定,this一定指向window)

function foo(){
    console.log(this);  // 指向window
}
foo();  // 此时的foo就为独立调用

那么如果在此情况下,函数嵌套调用呢?

function foo(){
    console.log(this);  // 指向window
}

function bar(){
    foo();
}

function baz(){
    bar();
}
bar();  // 此时的bar为独立调用

答案依旧不变,只要你遵守默认绑定规则,this就一定指向window

2. 隐式绑定:

当函数的引用有上下文对象时(当函数被某个对象所拥有时),函数的this指向引用它的对象。

var obj = {
    a:1,
    foo: foo    // obj隐式绑定了foo
}

function foo(){
    console.log(this.a);  //指向obj
}

obj.foo(); //输出为1

this: 这给我指哪来了?

3.隐式丢失

当一个函数被多个对象链式调用时,函数的this指向就近的那个对象。

var obj = {
    a:1,
    foo:foo    // obj隐式绑定foo
}

var obj2 = {
    a:2,
    obj:obj
}

function foo(){
    console.log(this.a);  //指向obj,因为就近对象为obj
}

obj2.obj.foo();  //输出为1

可能你会看到obj2嵌套了obj,便误以为this指向的就为obj2,但实际上this的指向采取的是就近原则,先被哪个对象绑定,就指向哪个对象。

4.显示绑定

除去以上的绑定规则外,还有一种更为蛮横的绑定方法,那就是用callapplybind去强制规定this的指向。

call

var obj = {
    a:1
}
function foo(){
    console.log(this.a);
}
foo.call(obj); //输出为1   因为通过call指定了this值

需要注意的是此时的执行过程是把foo函数当成对象,然后去调用call来使用。

另外此时的call也具备传参功能:

var obj = {
    a:1
}
function foo(x,y){
    console.log(this.a,x+y);
}
foo.call(obj,1,2); // 输出为1 3 

apply

apply的用法与call基本相同,唯一不同之处在于apply在接受参数时是以数组形式整体的接受,在传参时要加上[]将参数包括起来:

var obj = {
    a:1
}
function foo(x,y){
    console.log(this.a,x+y);
}
foo.apply(obj,[1,2]); // 输出为1 3 

bind

bind的特殊之处在于它会创建一个新的函数,并将这个函数与指定的上下文绑定在一起,需要注意的是:它在接收参数时为零散的接收,可以由bind接收,也可以由返回的函数体接收,或者两个人同时接收。

var obj = {
    a:1
}
function foo(x,y){
    console.log(this.a,x+y);
}
var A = foo.bind(obj,1,2);
A();  // 输出1 3
this: 这给我指哪来了?

new绑定

new绑定是一种构造函数创建实例对象时自然进行的绑定,简单来说就是构造函数内的this统一都指向构造函数自己创建的实例对象。

function Person(){
    this.name = '香蕉'
}
let p = new Person();
console.log(p.name);  // 输出为 '香蕉'
function Person(){
    name = '香蕉' 
}
let p = new Person();
console.log(p.name);  // 输出为undefined

正常代码输出为香蕉,但是一旦去除去除Person中的this,输出则变为undefined,这是因为函数Person中的this指向实例对象p,此处的this为什么会指向实例对象P呢? 以下是 let p = new Person() 的执行过程:

this: 这给我指哪来了?

由此可见,在执行过程中浏览器会将构造函数Person中的this的指向指到对象p上去。

特殊:箭头函数

箭头函数不绑定自己的this,它会捕获其所在上下文的this值作为自己的this值。这意味着在箭头函数中,this的值是在定义函数时确定的,而非调用时。

var obj = {
    a:1,
    foo:function(){
        //this
        const fn =()=>{
            console.log(this.a);  // 输出1
        }
        fn() 
}}
obj.foo()

结束

看完这篇文章,相信无论以后this被指到哪里去,我们都能找到它。

转载自:https://juejin.cn/post/7397639310721630242
评论
请登录