资讯专栏INFORMATION COLUMN

理解Javascript方法的调用和“this”

ad6623 / 3210人阅读

摘要:过去的几年,我看过很多人对方法的调用满是迷惑。事实上,这也是说明的作用。这就是方法调用的本质。简单的方法调用显然用调用方法非常的麻烦。注意上面的规则同样适用于的方法调用。成员方法下一个常遇到的调用方法的情况是调用一个对象的方法。

过去的几年,我看过很多人对javascript方法的调用满是迷惑。尤其是对方法里的this的语义抱怨颇多。

在我(作者)看来,只要弄清楚了方法的本质,上面的以后自然清晰。事实上,这也是ECMAScript说明的作用。在某种意义上这篇文章是说明文档的简写版,但是核心内容是一致的。

核心本质

首先,我们方法调用的本质是一个方法的call方法[1]。它是如下运作的。

创建一个参数列表(argList),包含了从头到尾的全部参数

第一个参数是thisValue

调动方法。把this作为thisValueargList作为参数列表。

比如:

function hello(thing) {
    console.log(this + " says hello " + thing);
}

hello.call("Yehuda", "world"); // => Yehuda says hello world

就如所看到的,我们调用了hello方法,this的值是Yehuda而一个多带带的参数是"world"。这就是javascript方法调用的本质。你可以把所有其他的方法调用都看做是方便版。

简单的方法调用

显然用call调用方法非常的麻烦。Javascript允许我们这样调用方法:hello("world")。当我们这样调用的时候实际上是这样的:

function hello(thing) {
    console.log("Hello " + thing);
}

// this;
hello("world");

// 等于
hello.call(window, "world");

这个行为会在使用strick mode[2]的时候发生改变:

// this:
hello("world");

// 等于
hello.call(undefined, "world");

上面的例子简单来说就是:一个方法的调用,比如:fn(...args)其实和fn.call(window[ES5-strict: undefined], ...args)

注意:上面的规则同样适用于inline的方法调用。(function(){})()(function() {}).call(window [ES5-strict:undefined])

成员方法

下一个常遇到的调用方法的情况是调用一个对象的方法(person.hello())。在这个情况下,调用的顺序是:

var person = {
    name: "Brendan Eich",
    hello: function(thing) {
        console.log(this + " says hello " + thing);
    }
};

// this
person.hello("world");

//等于
person.hello.call(person, "world");

注意:其实hello方法是如何绑定到对象上的。记住我们之前是如何把hello方法定义为一个多带带的方法的。我们来看看如果方法是动态绑定到对象上的会发生什么:

function hello(thing) {
    console.log(this + " says hello " + thing);
}

person = {name: "Brendan Eich};
person.hello = hello;

person.hello("world"); //等于person.hello.call(person, "hello");

hello("world"); // "[object DOMWindow]world"

注意方法里的this并不是一成不变的。它总是在被调用的时候被赋值。

使用Function.prototype.bind

如果this的值可以保持不变的话,那就方便多了。一个常用的方法就是使用闭包来让一个方法的this不再改变:

var person = {
    name: "Brenda Eich",
    hello: function(thing) {
        console.log(this.name + " says hello " + thing);
    }
}

var boundHello = function(thing) {return person.hello.call(person, thing);}

boundHello("world");

虽然我们的boundHello的调用的本质还是boundHello.call(window, "world"),我们来看看bind是如何运作的:

var bind = function(func, thisValue) {
    return function() {
        return func.apply(thisValue, aguments);
    }
}

var boundHello = bind(person.hello, person);

boundHello("world");    // "Brendan Eich says hello world"

为了理解上面的例子,你只需要知道两个事实。一、arguments是一个类似于数组的对象,它代表了全部传入方法的参数。二、apply方法和call方法本质上是一样的,只不过类数组的参数代替了逐个列出的参数。

我们的bind方法只是返回了一个新的方法。当它被调用的时候,我们的新方法调用了传入的方法,设置了this的值。同时其他的参数也传入进来。

因为这个基本上就是一个非常通用的模型。ES5给所有的Function都引入了一个新的bind。这个bind是这样工作的:

var boundHello = person.hello.bind(person);
boundHello("world");

这个在你想把一个方法作为回调传入的时候非常有用:

var person = {
    name: "Alex Russell",
    hello: function() {
        console.log(this.name + " says hello world");
    }
}

$("#some-div").click(person.hello.bind(person));

// 当div被点击的时候,"Alex Russell says hello world"就会出现

这确实显得很笨拙,TC39(指定新的ECMAScript标准的组织)还在制定更加优雅的,向后兼容的方法。

关于jQuery

因为jQuery用了非常的多的匿名方法,它内部调用了call方法来设置回调的this值。比如,所有回调都被用call方法设置了当前的元素为this值,而不是用window作为this的值。

这一点非常有用,因为匿名方法作为回调并不是特别有用,但是它会给刚接触Javascript的人一种this非常奇怪的印象:总之就是经常改变,难以推断。

如果你能把一个方法的调用顺其自然的理解为func.call(thisValue, ...args)的调用方式,那就可以轻而易举的理解Javascript里this的值了。

原文链接:http://yehudakatz.com/2011/08...

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

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

相关文章

  • javascriptthis理解

    摘要:的关键字总是让人捉摸不透,关键字代表函数运行时,自动生成的一个内部对象,只能在函数内部使用,因为函数的调用场景不同,的指向也不同。其实只要理解语言的特性就很好理解。个人对中的关键字的理解如上,如有不正,望指正,谢谢。 javascript的this关键字总是让人捉摸不透,this关键字代表函数运行时,自动生成的一个内部对象,只能在函数内部使用,因为函数的调用场景不同,this的指向也不...

    jimhs 评论0 收藏0
  • 理解 JavaScript this 关键字

    摘要:原文许多人被中的关键字给困扰住了,我想混乱的根源来自人们理所当然地认为中的应该像中的或中的一样工作。尽管有点难理解,但它的原理并不神秘。在浏览器中,全局对象是对象。运算符创建一个新对象并且设置函数中的指向调用函数的新对象。 原文:Understanding the this keyword in JavaScript 许多人被JavaScript中的this关键字给困扰住了,我想混乱的...

    jayzou 评论0 收藏0
  • 理解 JavaScript call()/apply()/bind()

    摘要:理解文章中已经比较全面的分析了在中的指向问题,用一句话来总结就是的指向一定是在执行时决定的,指向被调用函数的对象。与和直接执行原函数不同的是,返回的是一个新函数。这个新函数包裹了原函数,并且绑定了的指向为传入的。 理解 JavaScript this 文章中已经比较全面的分析了 this 在 JavaScript 中的指向问题,用一句话来总结就是:this 的指向一定是在执行时决定的,...

    duan199226 评论0 收藏0
  • 【译】javascriptthis关键词理解

    摘要:在中,当使用关键字调用函数构造函数时,函数构造函数中也有这个概念,但是它不是惟一的规则,而且常常可以引用来自不同执行上下文的不同对象。因此,我们使用调用函数,可以看到这是对象,并且的属性是正常的。 一直以来,javascript里边的this都是一个很难理解的东西,之前看的最多的就是阮一峰老师关于this的理解: http://www.ruanyifeng.com/blo... htt...

    tainzhi 评论0 收藏0
  • js基本操作-this理解

    摘要:基本操作理解写在前面在面向对象的语言中,关键字的含义是明确且具体的,即指代当前对象。一般在编译期确定下来,或称为编译期绑定。全局范围内当在全部范围内使用,它将会指向全局对象。输出浏览器中运行的脚本,这个全局对象是。 js基本操作-this理解 写在前面 在面向对象的语言中,this关键字的含义是明确且具体的,即指代当前对象。一般在编译期确定下来,或称为编译期绑定。而在 JavaScr...

    Steven 评论0 收藏0

发表评论

0条评论

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