资讯专栏INFORMATION COLUMN

JavaScript 中this在不同调用模式中的差异

wuyangnju / 1018人阅读

摘要:的值为以此模式调用函数时,被绑定到全局对象。在传统的面向类的语言中,构造函数是类中的一些特殊方法,使用初始化类时会调用类中的构造函数。包括内置对象函数在内的所有函数都可以用来调用,这种函数调用被称为构造函数调用。

调用一个函数会暂停当前函数的执行,传递控制权和参数给新函数。除了声明时定义的形式参数,每个函数还接受两个附加参数: this 和 arguments。参数 this 的值取决于调用的模式。在JavaScript中一共有4中调用模式: 方法调用模式、函数调用模式、构造器调用模式和 apply 调用模式。

方法调用模式(隐式绑定)

当一个函数被保存为对象的一个属性时,我们称它为一个方法。当一个方法被调用时,this 被绑定到该对象。如果调用表达式包含一个提取属性的动作(即包含一个 .点表达式或[subscript]下标表达式),那么它就是被当做一个方法来调用。

// 创建 myObject 对象,有一个 value 属性和一个 increment 方法
// increment 方法接受一个可选的参数。如果参数不是数字,那么默认使用数字1

var myObject = {
    value: 0,
    increment: function (inc){
        this.value += typeof inc === "number" ? inc : 1;
    }
};

myObject.increment();
document.writeln(myObject.value);   // 1

myObject.increment(2);
document.writeln(myObject.value);   // 3

方法可以使用 this 访问自己所属的对象,所以它能从对象中取值货对对象进行修改。 this 到对象的绑定发生在调用的时候。

函数调用模式(默认绑定)

当一个函数并非一个对象的属性时,它就是被当做一个函数来调用的。

var sum = add(3,4);   // sum 的值为7

以此模式调用函数时,this 被绑定到全局对象。这是语言设计上的一个错误。若正确,那么当内部函数被调用时,this 应该仍然绑定到外部函数的 this 变量。这样设计的后果就是方法不能利用内部函数来帮助它工作,因为内部函数的 this 被绑定了错误的值,不能共享该方法对对象的访问权。

解决方案: 如果该方法定义一个便令并给它赋值为 this,那么内部函数就可以通过那个变量访问到 this。按照约定,把那个变量命名为 that:

// 给 myObject 增加一个 double 方法

myObject.double = function () {
    var that = this;   // 解决方法
    
    var helper = function () {
        that.value = add(that.value, that.value);
    };
    
    helper();   // 以函数的形式调用helper
};

// 以方法的形式调用 double

myObject.double();
document.writeln(myObject.value);   // 6

如果使用严格模式(strict mode),那么全局对象无法使用默认绑定,this 会绑定到undefined

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

var a = 2;

foo();   // TypeError: this is undefined

这里有一个微妙但是非常中亚偶的细节,虽然 this 的绑定规则完全取决于调用位置,但是只有 foo() 运行在非 strict mode 下时,默认绑定才能绑定到全局对象;严格模式下与 foo() 的调用位置无关:

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

var a = 2;

(function(){
    "use strict";
    
    foo();   // 2
})();
构造器调用模式

如果在一个函数前面带上 new 来调用,那么背地里将会创建一个连接到该函数的 prototype 成员的新对象,同时 this 会被绑定到那个新对象上。

首先,我们来了解一下构造函数。在传统的面向类的语言中,“构造函数”是类中的一些特殊方法,使用 new 初始化类时会调用类中的构造函数。通常的形式为:

something = new MyClass(..);

JavaScript也有一个 new 操作符,使用方法看起来和那些面向类的语言一样,但 JavaScript 中的 new 机制实际上和面向类语言完全不同。
在 JavaScript 中,构造函数只是一些使用 new 操作符时被调用的函数。它们不属于某个类,也不会实例化一个类。实际上,它们甚至都不能说是一种特殊的函数类型,它们只是被 new 操作符调用的普通函数而已。包括内置对象函数在内的所有函数都可以用 new 来调用,这种函数调用被称为构造函数调用。实际上并不存在所谓的构造函数,只有对于函数的构造调用。
使用 new 来调用函数,会自动执行以下操作:

创建(或者说构造)一个全新的对象。

这个新对象会被执行[[原型]]连接

这个新对象会绑定到函数调用的 this

如果函数没有返回其他对象,那么 new 表达式中的函数会自动返回这个新对象

// 创建一个名为 Quo 构造器函数。它构造一个带有 status 属性的对象

var Quo = function (string) {
    this.status = string;
};

// 给 Quo 的所有实例提供一个名为 get_status 的公共方法

Quo.prototype.get_status = function () {
    return this.status;
};

// 构造一个 Quo 实例

var myQuo = new Quo("confused");
document.writeln(myQuo.get_status());   // confused
Apply 调用模式

apply 方法让我们构建一个参数数组传递给调用函数,也允许我们选择 this 的值。apply 方法接收两个参数,第一个是要绑定给 this 的值,第二个就是一个参数数组。

// 构造一个包含两个数字的数组,并将它们相加

var array = [3,4];
var sum = add.apply(null,array);   // 7

// 构造一个包含 status 成员的对象

var statusObject = {
    status: "A-OK";
};

// statusObject 并没有继承自 Quo.prototype,但我们可以在 statusObject 上调用 get_statuse 方法,尽管statusObject 并没有一个名为 get_status 的方法

var status = Quo.prototype.get_status.apply(statusObject);   // A-OK

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

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

相关文章

  • JavaScript this 讲解

    摘要:作为方法进行调用,该上下文是方法的拥有者作为全局函数调用,其上下文永远是也就是说,该函数是的一个方法作为构造器进行调用时,其上下文对象则是新创建的对象实例。 精确把握 JavaScript 中的 this this 是 JavaScript 中的一个关键字,当一个函数被调用时,除了传入函数的显式参数以外,名为 this 的隐式参数也被传入了函数。this 参数指向了一个自动生成的内部对...

    zhangwang 评论0 收藏0
  • 功能性组件和Classes有什么不同

    摘要:函数组件与类有何不同有一段时间,规范的答案是类可以访问更多功能如状态。那么功能性函数和类是否又根本的区别函数组件捕获的值。假设功能组件不存在。在我到目前为止看到的所有情况中,由于错误地假设功能不会改变或总是相同,所以会出现陈旧的封闭问题。 React函数组件与React类有何不同? 有一段时间,规范的答案是类可以访问更多功能(如状态)。但是自从有了Hook后,这个答案变得不唯一了。 也...

    lmxdawn 评论0 收藏0
  • 功能性组件和Classes有什么不同

    摘要:函数组件与类有何不同有一段时间,规范的答案是类可以访问更多功能如状态。那么功能性函数和类是否又根本的区别函数组件捕获的值。假设功能组件不存在。在我到目前为止看到的所有情况中,由于错误地假设功能不会改变或总是相同,所以会出现陈旧的封闭问题。 React函数组件与React类有何不同? 有一段时间,规范的答案是类可以访问更多功能(如状态)。但是自从有了Hook后,这个答案变得不唯一了。 也...

    GitCafe 评论0 收藏0
  • 功能性组件和Classes有什么不同

    摘要:函数组件与类有何不同有一段时间,规范的答案是类可以访问更多功能如状态。那么功能性函数和类是否又根本的区别函数组件捕获的值。假设功能组件不存在。在我到目前为止看到的所有情况中,由于错误地假设功能不会改变或总是相同,所以会出现陈旧的封闭问题。 React函数组件与React类有何不同? 有一段时间,规范的答案是类可以访问更多功能(如状态)。但是自从有了Hook后,这个答案变得不唯一了。 也...

    peixn 评论0 收藏0
  • 设计模式——工厂模式

    摘要:简单工厂模式创建单一的对象示例描述工厂模式主要是为了创建对象实例或者类簇抽象工厂关心的是最终产出创建的对象而不关心创建的过程在出现多个类的时候每次创建需要找到对应的类往往比较麻烦这时候通常使用一个函数进行封装来创建所需要的对象这样就无需关注 简单工厂模式(创建单一的对象) 示例1 描述 工厂模式主要是为了创建对象实例或者类簇(抽象工厂), 关心的是最终产出(创建)的对象, 而不关心创建...

    Moxmi 评论0 收藏0

发表评论

0条评论

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