国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

深入理解JavaScirpt的函數(shù)調(diào)用和"this"

bladefury / 1905人閱讀

摘要:簡單的函數(shù)調(diào)用顯而易見,一直用調(diào)用函數(shù)將會非常煩人。規(guī)范說幾乎總是被傳遞,但不在嚴格模式下時被調(diào)用函數(shù)應(yīng)該將其更改為全局對象。實際上,規(guī)范有一個和都使用的原語內(nèi)部稱為。

過去很多年里,我看到過太多關(guān)于JavaScript函數(shù)調(diào)用的混淆。尤其是,很多人抱怨函數(shù)調(diào)用中this的語義令人困惑。
在我看來,通過理解核心函數(shù)調(diào)用原語,然后將其他所有調(diào)用函數(shù)的方法視為在原語之上的語法糖,如此便可澄清很多這類疑惑。事實上,這正是ECMAScript規(guī)范對此的看法。在某些方面,這篇文章是規(guī)范的簡化,但基本思路是一樣的。

核心原語

首先,我們先看一下函數(shù)調(diào)用的核心原語,F(xiàn)unction對象的call方法[1]。調(diào)用方法方法相對簡單。

從參數(shù)1到末尾創(chuàng)建一個參數(shù)列表(argList)

第一個參數(shù)(參數(shù)0)是thisValue

通過將this的值設(shè)為thisValueargList作為其參數(shù)列表調(diào)用函數(shù)

舉例:

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

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

如你所見,我們通過將this設(shè)置為“Yehuda”和單個參數(shù)“world”來調(diào)用hello方法。這正是JavaScript中函數(shù)調(diào)用的核心原語。你可以認為所有其他方式的函數(shù)調(diào)用都可”去糖“得到這個原語。(“去糖”是指采用一種方便的語法并用更基本的核心原語來描述它)。

[1]在ES5規(guī)范中,call方法是用另一個更底層的原語來描述的,但它是在那個原語之上的簡單封裝,所以我在這里簡化了一下。有關(guān)更多信息,請參閱本文末尾。

簡單的函數(shù)調(diào)用

顯而易見,一直用call調(diào)用函數(shù)將會非常煩人。JavaScript允許我們直接使用括號語法hello("world")來調(diào)用函數(shù)。當我們這樣做時,調(diào)用“去糖”如下:

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

// this:
hello("world")

// desugars to:
hello.call(window, "world");

僅在使用嚴格模式[2]的ECMAScript 5中,此行為將改變:

// this:
hello("world")

// desugars to:
hello.call(undefined, "world");

簡短版本的說法是:fn(...args)這樣的函數(shù)調(diào)用和fn.call(window [ES5-strict: undefined], ...args)是一模一樣的
注意,對于行內(nèi)聲明的函數(shù)(function() {})()也是成立的:(function() {})()(function() {}).call(window [ES5-strict: undefined)是一模一樣的。

[2]事實上,我撒了一點小謊。ECMAScript 5規(guī)范說undefined(幾乎)總是被傳遞,但不在嚴格模式下時被調(diào)用函數(shù)應(yīng)該將其thisValue更改為全局對象。這允許嚴格模式下調(diào)用者避免破壞現(xiàn)有的非嚴格模式庫。

成員函數(shù)

調(diào)用方法的下一個非常普遍的方式是作為一個對象的一個成員 (person.hello())。在這種情況下,調(diào)用“去糖”如下:

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

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

// desugars to this:
person.hello.call(person, "world");

注意,hello方法在這種形式下是如何附加到對象上是無關(guān)緊要的。請記住,我們之前將hello定義為一個獨立函數(shù)。接下來我們看看如果動態(tài)地將其附加到對象上會發(fā)生什么:

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

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

person.hello("world") // still desugars to person.hello.call(person, "world")

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

注意,函數(shù)對其this值沒有一貫的定義,它總是在調(diào)用時根據(jù)調(diào)用者調(diào)用的方式進行設(shè)置。

使用Function.prototype.bind

因為引用this值一貫不變的函數(shù)有時是很方便的,人們歷來使用一個簡單的閉包技巧將函數(shù)轉(zhuǎn)換為this值一貫不變的對應(yīng)函數(shù):

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

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

boundHello("world");

盡管我們的boundHello調(diào)用仍然“去糖”為boundHello.call(window, "world"),但我們改變方向并使用我們的原語call方法將this值更改回我們想要的值。
我們做些調(diào)整可以把這個技巧變?yōu)橥ㄓ媒夥ǎ?/p>

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

var boundHello = bind(person.hello, person);
boundHello("world") // "Brendan Eich says hello world"

為了理解這一點,您只需要兩個額外的知識。首先,arguments是一個類Array對象,它表示傳遞給函數(shù)的所有參數(shù)。其次,apply方法的工作原理和call原語除了它采用類Array對象而不是一次列出一個參數(shù)之外完全一樣。
我們的bind方法簡單地返回一個新函數(shù)。當它被調(diào)用時,我們的新函數(shù)只是調(diào)用傳入的原始函數(shù),并將原始值設(shè)置為其this值,當然它也傳遞參數(shù)。
因為這是一個有點常見的習(xí)慣用法,ES5在所有Function對象上引入了一個新方法bind,實現(xiàn)了此行為:

var boundHello = person.hello.bind(person);
boundHello("world") // "Brendan Eich says hello world"

當您需要將原始函數(shù)作為回調(diào)傳遞時,此方法將非常有用:

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

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

// when the div is clicked, "Alex Russell says hello world" is printed

確實,這有點笨,TC39(負責ECMAScript下一版本的委員會)將繼續(xù)致力于一個更優(yōu)雅、向后兼容的解決方案。

面向jQuery

由于jQuery中大量使用匿名回調(diào)函數(shù),因此它在內(nèi)部使用call方法將這些回調(diào)的this值設(shè)置為更有用的值。舉個例子,在所有事件處理程序中(如不進行特殊干預(yù)),jQuery不接收window作為其this值,而是通過把設(shè)置事件處理程序的元素作為它第一個參數(shù)在回調(diào)函數(shù)上調(diào)用call
這非常有用,因為匿名回調(diào)函數(shù)中的默認this的值并不是特別有用,除了它給初學(xué)者對javascript的一種印象,this通常是一個奇怪的,經(jīng)常變動至于難以解釋的概念。
如果你理解了將“含糖”函數(shù)調(diào)用轉(zhuǎn)換為“已去糖”的func.call(thisValue, ...args)的基本規(guī)則,那么你應(yīng)該能夠在并不是那么危險的JavaScriptthis水域中航行。

PS:我撒謊的部分

在個別地方,我從規(guī)范的確切措辭中略微簡化了事實。可能最嚴重的欺騙是我稱呼func.call為原語的說法。實際上,規(guī)范有一個func.call[obj.]func()都使用的原語(內(nèi)部稱為[[Call]])。
然而,還是看一下func.call的定義吧:

如果IsCallable(func)值為false,則拋出TypeError異常

argList為一個空的List

如果使用多個參數(shù)調(diào)用此方法,則從arg1開始,從左往右將每個參數(shù)追加為argList的最后一個元素

提供thisArg作為this的值,并將argList作為參數(shù)列表,返回調(diào)用func的內(nèi)部方法[[Call]]的結(jié)果

如你所見,此定義本質(zhì)上是一種很簡單的JavaScript語義綁定到原語[[Call]]操作。
如果你看一下調(diào)用函數(shù)的定義,前七個步驟設(shè)置thisValueargList,最后一步是:“提供thisArg作為this的值,并將列表argList作為參數(shù)值,返回調(diào)用func的內(nèi)部方法[[Call]]的結(jié)果。”
一旦確定了argListthisValue,它基本上是相同的措辭。
我在稱call是一個原語時作了一些欺騙,但其含義基本上與我在文章開頭提出的規(guī)范和引用的章節(jié)是一樣的。
還有一些我沒有在這里介紹的其他案例(最值得注意的是with)。

原文地址

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/96465.html

相關(guān)文章

  • 學(xué)習(xí)js中'this'關(guān)鍵字

      在JavaScript中‘this’關(guān)鍵字是一個非常重要的概念,我們雖然知道它重要,但它也十分的晦澀難懂,也給我們學(xué)習(xí)造成不小的困擾。  什么是'this'關(guān)鍵字  'this'關(guān)鍵字是為每個執(zhí)行上下文(每個函數(shù))創(chuàng)建的一個特殊變量;所以一般來說,在使用'this'關(guān)鍵字的函數(shù)中,'this'永遠是取其所有者的值。總結(jié)一句話是該函...

    3403771864 評論0 收藏0
  • 一道JS面試題所引發(fā)"血案",透過現(xiàn)象尋本質(zhì),再從本質(zhì)看現(xiàn)象

    摘要:一看這二逼就是周杰倫的死忠粉看看控制臺輸出,確實沒錯就是對象。從根本上來說,作用域是基于函數(shù)的,而執(zhí)行環(huán)境是基于對象的例如全局執(zhí)行環(huán)境即全局對象。全局對象全局屬性和函數(shù)可用于所有內(nèi)建的對象。全局對象只是一個對象,而不是類。 覺得本人寫的不算很爛的話,可以登錄關(guān)注一下我的GitHub博客,博客會堅持寫下去。 今天同學(xué)去面試,做了兩道面試題,全部做錯了,發(fā)過來給我看,我一眼就看出來了,因為...

    QiShare 評論0 收藏0
  • ahooks useRequest源碼深入解讀

      大家會發(fā)現(xiàn),自從 React v16.8 推出了 Hooks API,前端框架圈并開啟了新的邏輯復(fù)用的時代,從此無需在意 HOC 的無限套娃導(dǎo)致性能差的問題,同時也解決了 mixin 的可閱讀性差的問題。這里也有對于 React 最大的變化是函數(shù)式組件可以有自己的狀態(tài),扁平化的邏輯組織方式,更加友好地支持 TS 類型聲明。  在運用Hooks的時候,除了 React 官方提供的,同時也支持我們...

    3403771864 評論0 收藏0
  • 深入理解Redis 數(shù)據(jù)結(jié)構(gòu)—簡單動態(tài)字符串sds

    摘要:本文主要介紹的數(shù)據(jù)結(jié)構(gòu)簡單動態(tài)字符串簡稱。遵守字符串以空字符串結(jié)尾的慣例,保存的空字符串一個字節(jié)空間不計算在的屬性里面。添加空字符串到字符串末尾等操作,都是由函數(shù)自動完成的,所以這個空字符對于使用者來說完全是透明的。Redis是用ANSI C語言編寫的,它是一個高性能的key-value數(shù)據(jù)庫,它可以作用在數(shù)據(jù)庫、緩存和消息中間件。其中 Redis 鍵值對中的鍵都是 string 類型,而鍵...

    番茄西紅柿 評論0 收藏2637
  • 【譯】使用"BinaryAST"加快JavaScript腳本解析速度?

    摘要:是提出并積極開發(fā)的一種新的在線格式,旨在加快解析速度,同時保持原始的語義不變。它的實現(xiàn)方式是使用有效的二進制來表示代碼和數(shù)據(jù)結(jié)構(gòu),并且存儲和提供額外的信息來提前指導(dǎo)解析器工作。提升依賴于提升所有聲明變量函數(shù)類。 原文:Faster script loading with BinaryAST?本文首發(fā)于公眾號:符合預(yù)期的CoyPan JavaScirpt的冷啟動 web應(yīng)用的表現(xiàn),越來...

    Hujiawei 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<