资讯专栏INFORMATION COLUMN

全面解析this

Y3G / 860人阅读

摘要:在严格模式下,对象的函数中的指向调用函数的对象实例显式绑定,,通过可以把的绑定到上。间接引用最容易在赋值时发生返回目标函数的引用词法之前介绍的种绑定规则可以包含所有正常的函数,但是中介绍了一种无法使用这些规则的特殊函数类型箭头函数。

this到底指向什么?
this关键词是javaScript中最复杂的机制之一,一般有两个误区:
1.this指向函数自身;
2.this指向函数的作用域;

this是指向调用位置,调用位置就是函数在代码中被调用的位置(而不是声明的位置),this的绑定规则主要有4条,我们在使用时能判断它属于哪种规则即可;

1.默认绑定

首先介绍最常用的函数调用类型:独立函数调用,可以理解为这是一条在无法应用其他规则的默认规则,非严格模式下,this指向全局对象,即window

var a = 2;
function foo(){
    var a = 1;
    console.log(this.a)
}
foo(); 



// 2
很明显这里的this指向window对象,但严格模式下呢?
var a = 1;
function foo(){
    "use strict"
    console.log(this.a)
}
foo(); 



// TypeError:this is undefined
严格模式下函数中的this指向undefined
"use strict";
 
console.log(this === window); // false? // true?
this.a = 9804;
console.log(window.a); // undefined?  // 9804?




// true
// 9804

但全局中的this指向window

2.隐式绑定

先看一段代码

function foo(){
    console.log(this.a)
}
var a = 1;
var obj = {
    a:2,
    foo:foo
}
obj.foo(); // ?



// 2
当函数引用有上下文对象时,隐式绑定规则会把函数调用中的this绑定到这个上下文对象,可以记住一点:谁调用绑到谁身上。

再看一段代码:

function foo(){
    console.log(this.a)
}
var obj2 = {
    a:42,
    foo:foo
}
var obj1 = {
    a:2,
    obj2:obj2
}
obj1.obj2.foo(); // ?



 // 42
对象属性引用链中只有上一层或者最后一层才起作用。
"use strict";
 
var o = new Object();
o.a = "obj.a";
o.f5 = function(){
    return this.a;
}
console.log(o.f5());// ?



// obj.a

在严格模式下,对象的函数中的this指向调用函数的对象实例

3.显式绑定
apply,call,bind
function foo(){
    console.log(this.a)
}
var a = 1;
var obj = {
    a:2
}
foo.call(obj);// ?



// 2
通过foo.call()可以把foo的this绑定到obj上。
var obj1 = {
    a: 1,
    b: 2,
    caculate: function(c,d){
        return this.a + this.b + c + d;
    }
};
var obj2 = {
    a: 10,
    b: 20,
};
console.log( obj1.caculate(3,4) ); // ?
console.log( obj1.caculate.call( obj2, 3, 4 ) ); // ?
console.log( obj1.caculate.apply( obj2, [30, 40] ) ); // ?



// 10
// 37
// 100
call 和 apply 的用法唯一的不同就是传参的方式不同,参见上面两种调用方式

(1)硬绑定
看下面代码:

var a = 1;
function foo(){
    console.log(this.a)
}
var obj = {
    a:2
}
var bar = function(){
    foo.call(obj)
}
bar();// ?
setTimeout(bar,100);// ?
//硬绑定的bar不可能再修改它的this
bar.call(window); // ?



// 2
// 2
// 2
无论何时调用bar函数,都会手动obj上调用foo,这种就是一种显示的强制绑定,即硬绑定。硬绑定的典型场景就是创建一个包裹函数
由于硬绑定是一种常用的模式,所以ES5提供的内置的方法Function.prototype.bind,它的用法如下:
function foo(something){
    console.log(this.a ,something);
    return this.a + something
}
var obj = {
    a:2
}
var bar = foo.bind(obj);
var b = bar(3);
console.log(b);



// 2 3
// 5
bind(..)会返回一个硬编码的新函数,它会把你指定的参数设置为this的上下文并调用原始函数,但是Ta是永久绑定,一旦绑定不会在改变:
4.new绑定

当用 new 运算符调用函数时,该函数总会返回一个对象,通常情况下,如果构造器不显式地返回任何数据,或者是返回一个非对象类型的数据,构造器里的 this 就指向返回的这个对象,

var MyClass = function(){
    this.name = "sven";
    return "anne"; // 返回 string 类型
};
var obj = new MyClass();
console.log(obj)  // ?
console.log(obj.name); // ?



// {name: "sven"}
// 输出: sven
var MyClass = function(){
    this.name = "sven";
    return { // 显式地返回一个对象
        name: "anne"
    }
};
var obj = new MyClass();
console.log( obj);   // ?



// 输出: {name: "anne"}
"use strict";
 
console.log("严格模式");
console.log("构造函数中的this");
function constru(){
    this.a = "constru-a";
    this.f2 = function(){
        console.log(this.b);
        return this.a;
    }
}
var o2 = new constru(); // ?
o2.b = "o2-b";
console.log(o2.f2()); // ?



// o2-b
// constru-a
在严格模式下,构造函数中的this指向构造函数创建的对象实例
四种绑定规则的优先级
new绑定>显式绑定>隐式绑定>默认绑定
被忽略的this

如果你把null或者undefined作为this的绑定对象传入call、apply或者bind,这些值在调用时会被忽略,实际应用的是默认绑定规则:

function foo(){
    console.log(this.a)
}
var a = 2;
foo.call(null); // ?



// 2
间接引用

另一个需要注意的是,你有可能无意的创建一个函数的“间接引用”,这种情况下,调用函数会应用默认规则。间接引用最容易在赋值时发生:

function foo() {
    console.log(this.a);
  }
  var a = 2;
  var o = { a: 3, foo: foo};
  var p = { a: 4 };

  o.foo();
  (p.foo = o.foo)(); // 返回目标函数的引用




//3
//2
this词法

之前介绍的4种绑定规则可以包含所有正常的函数,但是ES6中介绍了一种无法使用这些规则的特殊函数类型:箭头函数
箭头函数this的定义:箭头函数中的this是在定义函数的时候绑定,而不是在执行函数的时候绑定。

function foo(){
    //返回一个箭头函数
    return (a) => {
        //this继承自foo()
        console.log(this.a)
    }
}
var obj1 = {
    a:2
}
var obj2 = {
    a:3
}
var bar = foo.call(obj1);
bar.call(obj2); // ?



// 2, 不是3
foo()内部创建的箭头函数会捕获调用时foo()的this,由于foo()的this绑定到obj1,bar(引用箭头函数)的this也会绑定到obj1,箭头函数的绑定无法被修改
小结
1.由new调用?绑定到新创建的对象。
2.由call或者apply(或者bind)调用?绑定到指定的对象。
3.由上下文对象调用?绑定到那个上下文对象。
4.默认:在严格模式下绑定到undefined,否则绑定到全局对象。
ES6中的箭头函数并不会用这4种绑定规则,而是根据词法作用域来决定this,具体来说,箭头函数会继承外层函数调用的this绑定。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/105700.html

相关文章

  • 全面解析JS中的this

    摘要:当我们不想再对象内部间接包含引用函数,而像在某个对象上强制调用函数。我们可以用中内置的和的方法来实现,这两个方法的第一个参数是一个对象,是给准备的,接着再调用函数时将其绑定到。 this是什么 在javascript中,每个执行上下文可以抽象成一组对象showImg(https://segmentfault.com/img/bVuKR7); 而this是与执行上下文相关的特殊对象,任何...

    calx 评论0 收藏0
  • 关于this全面解析(下)

    摘要:关于的全棉解析上的文章地址判断函数是否在中调用绑定如果是的话绑定的是新创建的对象。显而易见,这种方式可能会导致许多难以分析和追踪的。默认在严格模式下绑定到,否则绑定到全局对象。 关于this的全棉解析(上)的文章地址 判断this 函数是否在new中调用(new绑定)?如果是的话this绑定的是新创建的对象。 bar = new foo() 函数是否通过call、apply(显式绑定...

    philadelphia 评论0 收藏0
  • 关于this全面解析(上)

    摘要:关于的全面解析下页面链接的调用位置调用位置就是函数在代码中被调用的位置而不是声明的位置,寻找调用位置就是寻找函数被调用的位置,最重要的是分析调用栈就是为了到达当前执行位置所调用的所有函数。因此,调用函数时被绑定到这个对象上,所以和是一样的。 关于this的全面解析(下)页面链接 this的调用位置 调用位置就是函数在代码中被调用的位置(而不是声明的位置),寻找调用位置就是寻找函数被调用...

    caige 评论0 收藏0
  • 【进阶3-1期】JavaScript深入之史上最全--5种this绑定全面解析

    摘要:在严格模式下调用函数则不影响默认绑定。回调函数丢失绑定是非常常见的。因为直接指定的绑定对象,称之为显示绑定。调用时强制把的绑定到上显示绑定无法解决丢失绑定问题。 (关注福利,关注本公众号回复[资料]领取优质前端视频,包括Vue、React、Node源码和实战、面试指导) 本周正式开始前端进阶的第三期,本周的主题是this全面解析,今天是第9天。 本计划一共28期,每期重点攻克一个面试重...

    xavier 评论0 收藏0
  • this全面解析(二)

    摘要:在传统的面向类的语言中,构造函数是类中的一些特殊方法,使用初始化类是会调用类中的构造函数。 在上一节中我们详细介绍了this的两种绑定方式,默认绑定和隐式绑定,在这一节我们继续介绍this的另外两种绑定方式显示绑定和new绑定。那么,我们要解决的问题当然就是上一节中我们提到的:this丢失! 显式绑定 在隐式绑定中,我们必须在一个对象的内部包含一个指向函数的属性,并通过这个属性间接引用...

    iflove 评论0 收藏0
  • this全面解析(一)

    摘要:调用栈就是为了到达当前执行位置所调用的所有函数。由于无法控制回调函数的执行方式,因此就没有办法控制调用位置得到期望的绑定,下一节我们会介绍如何通过固定来修复这个问题。 在《你不知道的this》中我们排除了对于this的错误理解,并且明白了每个函数的this是在调用时绑定的,完全取决于函数的调用位置。在本节中我们主要介绍一下几个主要内容: 什么是调用位置 绑定规则 this词法 调用...

    darry 评论0 收藏0

发表评论

0条评论

Y3G

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<