亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

Functions

sydMobile / 2712人閱讀

摘要:如果我們把這樣的定義放在全局代碼中,解析器會(huì)把函數(shù)當(dāng)作聲明,因?yàn)樗躁P(guān)鍵字開頭,在第一種情況中,我們會(huì)得到,因?yàn)槲覀內(nèi)鄙俸瘮?shù)名。

原文

ECMA-262-3 in detail. Chapter 5. Functions.

簡介

在這篇文章中,我們將討論一個(gè)ESCMAScript對(duì)象,函數(shù)。我們將討論不同類型的函數(shù),每個(gè)類型是如何影響環(huán)境中的變量對(duì)象(variables object)以及內(nèi)部的作用域的。我們將回答以下經(jīng)常會(huì)出現(xiàn)的問題,“下面的函數(shù)有什么不同嗎?”[譯者注:當(dāng)進(jìn)入一個(gè)函數(shù)時(shí),會(huì)創(chuàng)建一個(gè)對(duì)象,里面保存了函數(shù)運(yùn)行需要的各種變量]

var foo = function () {
  ...
};
function foo() {
  ...
}
(function () {
  ...
})();
函數(shù)類型 函數(shù)聲明

函數(shù)聲明(Funcation Declaration),縮寫FD,是一個(gè)函數(shù):

必須擁有一個(gè)名字

在源碼中的位置,要么在程序級(jí)別,要么在其他函數(shù)體的體內(nèi)

在進(jìn)入上下文時(shí)創(chuàng)建

會(huì)影響變量對(duì)象

用以下方式聲明

function exampleFunc() {
  ...
}

這個(gè)類型的函數(shù)的主要特點(diǎn)是它影響變量對(duì)象(它們被存在環(huán)境的變量對(duì)象中)。這導(dǎo)致了第二個(gè)重要的點(diǎn),在代碼執(zhí)行期間,他們已經(jīng)被用了,因?yàn)楫?dāng)一進(jìn)入環(huán)境后,函數(shù)聲明就被保存在環(huán)境的變量對(duì)象中,在代碼開始執(zhí)行之前。例如函數(shù)可以被調(diào)用在它被聲明之前,從源碼的角度看過去

foo();
  
function foo() {
  console.log("foo");
}
// function can be declared:
// 1) directly in the global context
function globalFD() {
  // 2) or inside the body
  // of another function
  function innerFD() {}
}

函數(shù)聲明要么出現(xiàn)在全局環(huán)境中,要么出現(xiàn)在其他函數(shù)體內(nèi)。

函數(shù)表達(dá)式

函數(shù)表達(dá)式(Function Expression),縮寫FE,是一個(gè)函數(shù)

在源碼中可以在表達(dá)式位置被定義

可以選擇不要名字

對(duì)環(huán)境的變量對(duì)象沒有影響

在代碼執(zhí)行的階段被創(chuàng)建

常見的賦值表達(dá)式

var foo = function () {
  ...
};

也可以給函數(shù)個(gè)名字

var foo = function _foo() {
  ...
};

在這值得注意的是,在函數(shù)表達(dá)式的外面通過變量foo訪問函數(shù),而在函數(shù)內(nèi)部,例如遞歸調(diào)用,用_foo訪問。函數(shù)表達(dá)式總在表達(dá)式的位置,例如以下的例子都是函數(shù)表達(dá)式

// in parentheses (grouping operator) can be only an expression
(function foo() {});
 
// in the array initialiser – also only expressions
[function bar() {}];
 
// comma also operates with expressions 
1, function baz() {}; 

函數(shù)表達(dá)式在代碼執(zhí)行的階段才會(huì)創(chuàng)建,并不會(huì)被存在環(huán)境變量對(duì)象中

// FE is not available neither before the definition
// (because it is created at code execution phase),
  
console.log(foo); // "foo" is not defined
  
(function foo() {});
  
// nor after, because it is not in the VO
  
console.log(foo);  // "foo" is not defined

為什么需要函數(shù)表達(dá)式?是為了不污染環(huán)境變量對(duì)象,同時(shí)作為其他函數(shù)的參數(shù)。

function foo(callback) {
  callback();
}
  
foo(function bar() {
  console.log("foo.bar");
});
  
foo(function baz() {
  console.log("foo.baz");
});

函數(shù)表達(dá)式被賦值給了個(gè)變量,我們可以通過該變量來訪問它

var foo = function () {
  console.log("foo");
};
  
foo();

還可以創(chuàng)建封閉的作用域,對(duì)外隱藏內(nèi)部數(shù)據(jù)。

var foo = {};
  
(function initialize() {
  
  var x = 10;
  
  foo.bar = function () {
    console.log(x);
  };
  
})();
  
foo.bar(); // 10;
  
console.log(x); // "x" is not defined

我們可以看到foo.bar通過[[Scope]]可以訪問函數(shù)initialize內(nèi)部變量x,與此同時(shí),x不能被外界直接訪問。這個(gè)策略經(jīng)常被用來創(chuàng)建私有變量和隱藏輔助實(shí)體。通常initialize函數(shù)表達(dá)式的名字是被忽略的。

(function () {
  
  // initializing scope
  
})();

這有個(gè)函數(shù)表達(dá)式,根據(jù)運(yùn)行情況來創(chuàng)建,且不污染環(huán)境變量對(duì)象。

var foo = 10;
  
var bar = (foo % 2 == 0
  ? function () { console.log(0); }
  : function () { console.log(1); }
);
  
bar(); // 0

注意,ES5中有bind函數(shù),鎖定this的值。

var boundFn = function () {
  return this.x;
}.bind({x: 10});
 
boundFn(); // 10
boundFn.call({x: 20}); // still 10

這通常在事件監(jiān)聽,或延遲函數(shù)(setTimeout)中被使用。

括號(hào)問題

根據(jù)規(guī)范,表達(dá)式聲明(expression statement),不能以{開始,這會(huì)被當(dāng)作塊,也不能以關(guān)鍵字function開始,會(huì)被當(dāng)作函數(shù)聲明。所以,如果我們想定義一個(gè)函數(shù),用下面的方式(以function關(guān)鍵字開頭)立馬調(diào)用。

function () {
  ...
}();
 
// or even with a name
 
function foo() {
  ...
}();

我們處理函數(shù)聲明,同時(shí)會(huì)產(chǎn)生解析錯(cuò)誤。如果我們把這樣的定義放在全局代碼中,解析器會(huì)把函數(shù)當(dāng)作聲明,因?yàn)樗?b>function關(guān)鍵字開頭,在第一種情況中,我們會(huì)得到SyntaxError,因?yàn)槲覀內(nèi)鄙俸瘮?shù)名。在第二個(gè)情況中,我們確實(shí)有了函數(shù)名,函數(shù)聲明應(yīng)該被正常的創(chuàng)建。但是我們有另一個(gè)語法錯(cuò)誤,一個(gè)組操作符中沒有表達(dá)式。所以在這個(gè)場合下,括號(hào)只是函數(shù)聲明后面的組操作符,而不是函數(shù)調(diào)用。

// "foo" is a function declaration
// and is created on entering the context
 
console.log(foo); // function
 
function foo(x) {
  console.log(x);
}(1); // and this is just a grouping operator, not a call!
 
foo(10); // and this is already a call, 10
// function declaration
function foo(x) {
  console.log(x);
}
 
// a grouping operator
// with the expression
(1);
 
// another grouping operator with
// another (function) expression
(function () {});
 
// also - the expression inside
("foo");
 
// etc

如果我們?cè)谡Z句中有函數(shù)聲明,也會(huì)報(bào)錯(cuò)

if (true) function foo() {console.log(1)}

我們?nèi)绾蝿?chuàng)建一個(gè)函數(shù)立刻調(diào)用它?它應(yīng)該是個(gè)函數(shù)表達(dá)式,創(chuàng)建函數(shù)表達(dá)式最簡單的操作就是組操作符。如此,一個(gè)函數(shù)會(huì)在執(zhí)行時(shí)創(chuàng)建,調(diào)用,移除,如果沒有引用指向它。

(function foo(x) {
  console.log(x);
})(1); // OK, it"s a call, not a grouping operator, 1

注意在下面的例子中,括號(hào)已經(jīng)不需要了,因?yàn)楹瘮?shù)已經(jīng)在表達(dá)式的位置了,解析器知道把它當(dāng)作函數(shù)表達(dá)式,在執(zhí)行的時(shí)候被創(chuàng)建。

var foo = {
  
  bar: function (x) {
    return x % 2 != 0 ? "yes" : "no";
  }(1)
  
};
  
console.log(foo.bar); // "yes"

正如我們所見,foo.bar是一個(gè)字符串而不是函數(shù),函數(shù)在初始化屬性時(shí)就被調(diào)用了。括號(hào)是需要的,如果我們想立刻調(diào)用函數(shù)在創(chuàng)建它后,而函數(shù)并不在表達(dá)式的位置,如果函數(shù)已經(jīng)在表達(dá)式的位置,括號(hào)就不需要了。除了括號(hào),還有其他轉(zhuǎn)換函數(shù)表達(dá)式的方法

1, function () {
  console.log("anonymous function is called");
}();
 
// or this one
!function () {
  console.log("ECMAScript");
}();
 
// and any other manual
// transformation
(function () {})();
(function () {}());
實(shí)現(xiàn)擴(kuò)展: Function Statement
if (true) {
  
  function foo() {
    console.log(0);
  }
  
} else {
  
  function foo() {
    console.log(1);
  }
  
}
  
foo(); // 1 or 0 ? test in different implementations

這里要說的是,根據(jù)規(guī)范,這種語法構(gòu)造是不正確的。因?yàn)楹瘮?shù)聲明不能出現(xiàn)在代碼塊中,而這里有if/else的代碼塊,函數(shù)聲明只能出現(xiàn)在程序級(jí)別(program level)或其他函數(shù)體內(nèi)。然而在規(guī)范的錯(cuò)誤處理中,允許了這種實(shí)現(xiàn)擴(kuò)展。但是有各自不同的實(shí)現(xiàn)方式。if/else是希望我們能根據(jù)運(yùn)行時(shí)的情況,來創(chuàng)建函數(shù),這暗示了把它們當(dāng)作函數(shù)表達(dá)式,實(shí)際上,主要的實(shí)現(xiàn)中,在進(jìn)入上下文時(shí),就會(huì)創(chuàng)建函數(shù)聲明,因?yàn)樗鼈兺?,所以最后一個(gè)會(huì)被調(diào)用,所以打印1。然后spidermonkey(一種js引擎)以不同的方式實(shí)現(xiàn)這個(gè)。

有名字的函數(shù)表達(dá)式的特點(diǎn) (NFE)

如果函數(shù)表達(dá)式有名字(named function expression),縮寫NFE。由定義可知,函數(shù)表達(dá)式并不影響環(huán)境的變量對(duì)象。然后,函數(shù)表達(dá)式有時(shí)候需要在遞歸中調(diào)用自己。

(function foo(bar) {
  
  if (bar) {
    return;
  }
  
  foo(true); // "foo" name is available
  
})();
  
// but from the outside, correctly, is not
  
foo(); // "foo" is not defined

當(dāng)解釋器在代碼執(zhí)行的過程中遇到有名字的函數(shù)表達(dá)式,在創(chuàng)建函數(shù)表達(dá)式之前,解釋器創(chuàng)建了一個(gè)輔助特殊的對(duì)象,把它加在當(dāng)前的作用域鏈前面。然后它創(chuàng)建函數(shù)表達(dá)式,函數(shù)獲得[[Scope]]屬性。在那之后,有名字的函數(shù)表達(dá)式被作為一個(gè)屬性,添加到了特殊的對(duì)象上,對(duì)象的值是函數(shù)表達(dá)式的引用。最后一步是從父作用域鏈中移除特殊的對(duì)象。

specialObject = {};
  
Scope = specialObject + Scope;
  
foo = new FunctionExpression;
foo.[[Scope]] = Scope;
specialObject.foo = foo; // {DontDelete}, {ReadOnly}
  
delete Scope[0]; // remove specialObject from the front of scope chain
NFE and SpiderMonkey

[譯者注:講述SpiderMonkey(Mozilla火狐c(diǎn)/c++)引擎如何處理有名函數(shù)表達(dá)式,不譯了]
[譯者注:講述Rhino(Mozilla java)引擎如何處理有名函數(shù)表達(dá)式,不譯了]

NFE and JScript

[譯者注:講述JScript(微軟)引擎如何處理有名函數(shù)表達(dá)式,不譯了]

通過函數(shù)構(gòu)造器創(chuàng)建函數(shù)

由函數(shù)構(gòu)造器構(gòu)造的函數(shù),它的[[Scope]]只包括全局對(duì)象。

var x = 10;
  
function foo() {
  
  var x = 20;
  var y = 30;
  
  var bar = new Function("console.log(x); console.log(y);");
  
  bar(); // 10, "y" is not defined
  
}
函數(shù)創(chuàng)建算法
F = new NativeObject();
  
// property [[Class]] is "Function"
F.[[Class]] = "Function"
  
// a prototype of a function object
F.[[Prototype]] = Function.prototype
  
// reference to function itself
// [[Call]] is activated by call expression F()
// and creates a new execution context
F.[[Call]] = 
  
// built in general constructor of objects
// [[Construct]] is activated via "new" keyword
// and it is the one who allocates memory for new
// objects; then it calls F.[[Call]]
// to initialize created objects passing as
// "this" value newly created object 
F.[[Construct]] = internalConstructor
  
// scope chain of the current context
// i.e. context which creates function F
F.[[Scope]] = activeContext.Scope
// if this functions is created 
// via new Function(...), then
F.[[Scope]] = globalContext.Scope
  
// number of formal parameters
F.length = countParameters
  
// a prototype of created by F objects
__objectPrototype = new Object();
__objectPrototype.constructor = F // {DontEnum}, is not enumerable in loops
F.prototype = __objectPrototype
  
return F

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/89625.html

相關(guān)文章

  • Javascript anonymous functions

    Javascript anonymous functions Anonymous functions are functions that are dynamically declared at runtime. They’re called anonymous functions because they aren’t given a name in the same way as no...

    劉福 評(píng)論0 收藏0
  • Study Blazor .NET(四)數(shù)據(jù)綁定

    摘要:下面是支持的事件參數(shù)方法方法這里是組件間雙向綁定的另一種方法,我們可以基于任何事件方法的執(zhí)行手動(dòng)觸發(fā)一個(gè),在中,用內(nèi)置函數(shù)手動(dòng)觸發(fā)屬性,同時(shí)回調(diào)父組件中相應(yīng)的方法,在父組件中,通過通知狀態(tài)已經(jīng)改變。翻譯自:Study Blazor .NET,轉(zhuǎn)載請(qǐng)注明。數(shù)據(jù)綁定單向綁定在blazor中單向綁定簡單而直接,無需UI刷新或渲染。下面示例展示了單向數(shù)據(jù)綁定://Counter.razor@page...

    incredible 評(píng)論0 收藏0
  • Flask注冊(cè)視圖函數(shù)

    摘要:鍵是函數(shù)名,值是函數(shù)對(duì)象,函數(shù)名也用于生成。注冊(cè)一個(gè)視圖函數(shù),用裝飾器。獲取儲(chǔ)存視圖函數(shù)字典中的函數(shù)對(duì)象視圖函數(shù)類中的字典儲(chǔ)存了注冊(cè)的視圖函數(shù)名和視圖函數(shù)對(duì)象。輸出視圖函數(shù)視圖函數(shù)名重復(fù)修改解決 那天莫名其妙出了個(gè)錯(cuò)。。就順便看了看Flask路由 在flask存儲(chǔ)路由函數(shù)是以函數(shù)名為鍵,函數(shù)對(duì)象為值 class Flask: def __init__(self, *args, ...

    2bdenny 評(píng)論0 收藏0
  • 【underscore 源碼解讀】Array Functions 相關(guān)源碼拾遺 & 小結(jié)

    摘要:最近開始看源碼,并將源碼解讀放在了我的計(jì)劃中。將轉(zhuǎn)為數(shù)組同時(shí)去掉第一個(gè)元素之后便可以調(diào)用方法總結(jié)數(shù)組的擴(kuò)展方法就解讀到這里了,相關(guān)源碼可以參考這部分。放個(gè)預(yù)告,下一篇會(huì)暫緩下,講下相關(guān)的東西,敬請(qǐng)期待。 Why underscore 最近開始看 underscore.js 源碼,并將 underscore.js 源碼解讀 放在了我的 2016 計(jì)劃中。 閱讀一些著名框架類庫的源碼,就好...

    SimpleTriangle 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<