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

資訊專欄INFORMATION COLUMN

函數(shù)以及函數(shù)作用域詳解

ShowerSun / 1098人閱讀

摘要:閉包是一個(gè)擁有自由訪問另一個(gè)函數(shù)作用域的表達(dá)式通常是一個(gè)函數(shù)。意味著內(nèi)部函數(shù)擁有外部函數(shù)的作用域。所以通過函數(shù)構(gòu)造方式分構(gòu)造函數(shù)無論何時(shí)都是應(yīng)該被避免的。

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions_and_function_scope
Javascript 函數(shù) 函數(shù)作用域

概述

通常來說,函數(shù)就是一個(gè)可以被外部調(diào)用的(或者函數(shù)本身遞歸調(diào)用)的“子程序”。和程序本身一樣,一個(gè)函數(shù)的函數(shù)體是由一系列的語句組成的,函數(shù)可以接受函數(shù),也可以返回一個(gè)返回值。

在Javascript中函數(shù)也是對象,也可以像其他對象一樣,添加屬性和方法等。具體來講,它們是Function對象。

用法簡介

在Javascript中,每個(gè)函數(shù)其實(shí)都是一個(gè)Function對象,查看Function界面,了解Function屬性和方法。

要想返回一個(gè)返回值,函數(shù)必須使用return語句指定所要返回的值(使用new關(guān)鍵詞的構(gòu)造函數(shù)除外)。如果一個(gè)函數(shù)沒有return語句,則它默認(rèn)返回undefined。

調(diào)用函數(shù)時(shí),傳入函數(shù)的值為函數(shù)的實(shí)參,對應(yīng)位置的函數(shù)參數(shù)名為形參。如果實(shí)參是一個(gè)包含原始值(數(shù)字,字符串,布爾值)的變量,則就算函數(shù)在內(nèi)部改變了形參的值,返回后該實(shí)參的值也不會變壞。如果實(shí)參是一個(gè)對象引用,則對應(yīng)形參和實(shí)參會指向同一個(gè)對象,如果函數(shù)內(nèi)部形參引用對象的值發(fā)生了改變,則實(shí)參指向的引用對象的值也會改變:

/*定義函數(shù) myFunc*/
function myFunc(theObject) {
    theObject.brand = "Toyota";
}

/*
 *定義變量 mycar;
 *創(chuàng)建并初始化一個(gè)對象;
 *將對象的引用賦值給變量mycar;
 */
var mycar = {
    brand : "Honda",
    model : "Accord",
    year : 1998
};

window.alert(mycar.brand);  //彈出“Honda”

myFunc(mycar);

window.alert(mycar.brand);  //彈出“Toyota”

函數(shù)執(zhí)行時(shí),this不會指向正在運(yùn)行的函數(shù)本身,而是指向調(diào)用該函數(shù)的對象。如果你想在函數(shù)內(nèi)部獲取自身的引用,只能使用函數(shù)名或者arguments.callee屬性。

定義函數(shù)

定義函數(shù)一共有三種方法:

函數(shù)聲明(function語句)

有一個(gè)特別的語法來聲明函數(shù):

    function name([param,[param,[...param]]]) {
        //statements 
}

name
函數(shù)名

param
函數(shù)的參數(shù)名稱,一個(gè)函數(shù)最多有255個(gè)參數(shù)。

statements
函數(shù)體內(nèi)執(zhí)行的語句

函數(shù)表達(dá)式(function操作符)

函數(shù)表達(dá)式很函數(shù)聲明有著很多相同之處,他們甚至有著相同的語法:

function[name]([param,[param,[...param]]]) {
        //statements
}

name
可以省略

param
函數(shù)的參數(shù)名稱,一個(gè)函數(shù)最多有255個(gè)參數(shù)。

statements
函數(shù)體內(nèi)執(zhí)行的語句

Function構(gòu)造函數(shù)

和其他類型一樣,F(xiàn)unction對象可以使用new操作符來創(chuàng)建:

[new] Function (arg1, arg2, ... argN, functionBody)

arg1, arg2, ... argN
一個(gè)或多個(gè)變量名稱,來作為函數(shù)的形參名.類型為字符串,值必須為一個(gè)合法的JavaScript標(biāo)識符,例如Function("x", "y","alert(x+y)"),或者逗號連接的多個(gè)標(biāo)識符,例如Function("x,y","alert(x+y)")

functionBody
一個(gè)字符串,包含了組成函數(shù)的函數(shù)體的一條或多條語句.
即使不使用new操作符,直接調(diào)用Function函數(shù),效果也是一樣的,仍然可以正常創(chuàng)建一個(gè)函數(shù).

注意: 不推薦使用Function構(gòu)造函數(shù)來創(chuàng)建函數(shù).因?yàn)樵谶@種情況下,函數(shù)體必須由一個(gè)字符串來指定.這樣會阻止一些JS引擎做程序優(yōu)化,還會引起一些其他問題.

arguments對象

在函數(shù)內(nèi)部,你可以使用arguments對象獲取到該函數(shù)的所有傳入?yún)?shù). 查看 arguments.

作用域和函數(shù)堆棧

調(diào)用其他函數(shù)時(shí)的作用域部分和函數(shù)部分

遞歸

函數(shù)能指向并引用它自己,有三種引用方法引用函數(shù)它自己:

通過函數(shù)名

arguments.callee

指向該函數(shù)的變量

考慮到一下的函數(shù)定義:

var foo = function bar() {
    //statements
}

在這個(gè)函數(shù)內(nèi)部,下面就是上面所說的三種:

bar()

arguments.callee

foo()

一個(gè)函數(shù)調(diào)用它自己叫做遞歸函數(shù)。在某些方面,遞歸函數(shù)像一個(gè)循環(huán)(loop),同樣的代碼多次執(zhí)行同時(shí)有一個(gè)控制語句(為了避免無限循環(huán)),比如下面的循環(huán):

var x = 0;
while (x < 10){
    x++
};
console.log(x);    //輸出10

能變換為迭代函數(shù)并調(diào)用該函數(shù):

function loop(x) {
    if(x>=10){console.log(x);}
    else{loop(x+1);}
}
loop(0);    //返回10

然而,一些算法并不是簡單的迭代循環(huán)。比如,獲得DOM節(jié)點(diǎn)使用遞歸就更方便:

function walkTree(node) {
    if (node == null) return;
    for(var i = 0; i < node.childNodes.length; i++){
        walkTree(node.childNodes[i]);
    }
}

比較這些循環(huán)方程,每一個(gè)遞歸調(diào)用都會調(diào)用更多的調(diào)用。
將遞歸算法轉(zhuǎn)換成非遞歸算法大多是能實(shí)現(xiàn)的,但是經(jīng)常邏輯會變得更加復(fù)雜并且要使用更多的堆棧,事實(shí)上,遞歸本身就使用堆棧:函數(shù)堆棧。
這種類似堆棧的行為能在下圖中看到:

function foo(i){
    if(i<0) return;
    console.log("begin: " + i);
    foo(i - 1);
    console.log("end: " + i);
}
foo(3);
嵌套函數(shù)和閉包

你可以將一個(gè)函數(shù)嵌套在另一個(gè)函數(shù)內(nèi)部,被嵌套函數(shù)只是他外部函數(shù)的一個(gè)私有函數(shù),這種情況我們將它叫做閉包。

閉包是一個(gè)擁有自由訪問另一個(gè)函數(shù)作用域的表達(dá)式(通常是一個(gè)函數(shù))。

當(dāng)一個(gè)被嵌套函數(shù)是一個(gè)閉包時(shí),意味著一個(gè)被嵌套函數(shù)能繼承它的外部函數(shù)的參數(shù)(arguments)和變量(variables)。意味著內(nèi)部函數(shù)擁有外部函數(shù)的作用域。
總而言之:

內(nèi)部函數(shù)能擁有訪問外部函數(shù)的語句

內(nèi)部的函數(shù)定義了一個(gè)閉包:內(nèi)部函數(shù)能使用外部函數(shù)的參數(shù)(arguments)和變量(variables),但是外部函數(shù)不能使用內(nèi)部函數(shù)的參數(shù)(arguments)和變量(variables)。
下例演示一個(gè)函數(shù)閉包:

function addSquares(a,b){
    function square(x){
        return x*x;
        }
    return square(a)+square(b);
}
console.log(addSquares(1,2));      //返回5

由于內(nèi)部函數(shù)形成了一個(gè)閉包,你可以把內(nèi)部函數(shù)當(dāng)作返回值返回:

function outSide(x){
    function inSide(y){
        return x + y;
    }
    return inSide;
}
fnInside = outSide(1);
console.log(fnInside(2));       //返回3
console.log(outSide(2)(10));       //返回12
變量的保存

注意,x變量是如何在inside函數(shù)返回后被保存的。一個(gè)閉包必須保存它的作用域中的參數(shù)和變量。每一次調(diào)用有可能提供不同的參數(shù),這樣一個(gè)新的閉包都會在外層調(diào)用時(shí)被創(chuàng)建,只有當(dāng)要返回的內(nèi)部函數(shù)不再被訪問時(shí)內(nèi)存才會被清空。
這和保存來自其他對象的引用沒有區(qū)別,但是后一種情況更加少見因?yàn)橐粋€(gè)函數(shù)不會直接設(shè)置引用并且不能檢查它們。

多層嵌套

函數(shù)能多層嵌套,A函數(shù)中B函數(shù),B函數(shù)中包含C函數(shù)。在這個(gè)函數(shù)里B和C都是閉包。因此B函數(shù)能訪問A函數(shù),C函數(shù)能訪問B函數(shù)。并且,C函數(shù)也能訪問A函數(shù)。這樣看,閉包能包含多層嵌套。它們遞歸的包含外層的作用域,這種情況我們稱之為作用域鏈。
例子如下:

function A(x){
    function B(y){
        function C(z){
            console.log(x + y + z);
        }
        C(2);
    }
    B(6);
}
A(1);

此例中C能訪問B中y和A中的x,這些之所以能成立是因?yàn)椋?/p>

1.B為A的閉包,B能訪問A的變量和參數(shù)。
2.C為B的閉包
3.因?yàn)锽包含A的作用域,所以C也包含A的作用域。換言之,C包含B和A的作用域鏈。

然而反過來卻不行,A不能訪問B,B也不能訪問C

命名沖突

當(dāng)閉包中兩個(gè)變量或者參數(shù)擁有相同的名字,這種情況叫做命名沖突。越內(nèi)層的函數(shù)擁有越高的優(yōu)先權(quán),最內(nèi)層的作用域擁有最高的優(yōu)先權(quán),最外層的作用域的優(yōu)先權(quán)最低。作用域鏈的原理如此。作用域最前端是最內(nèi)層的作用域,最后是最外層。考慮如下例子

function outside(){
    var x = 10;
    function inside(x){
    return x;
    }
    return inside;
}
result = outside()(20);       //返回20

上例中的命名沖突發(fā)生在return的x是返回inside里的參數(shù)x還是外層代碼的x,此處的作用域鏈為(inside,outside,全局),然而內(nèi)層的x優(yōu)先級比外層的x優(yōu)先級高,于是返回的是內(nèi)層的x。

函數(shù)構(gòu)造器vs.函數(shù)聲明vs.函數(shù)表達(dá)式

比較如下:
1.用函數(shù)構(gòu)造器構(gòu)造函數(shù)并添加參數(shù):

var multiply = new Function("x", "y", "return x*y;");

2.函數(shù)聲明:

function multiply(x, y) {
    return x*y; 
}

3.函數(shù)表達(dá)式:

var multiply = function(x, y) {
    return x*y;
}

4.函數(shù)命名表達(dá)式

var multiply = function func_name(x, y) {
    return x*y;
}

上面的代碼大約都是干的同樣的事情,除了一些微妙的區(qū)別:

函數(shù)名和函數(shù)指定的變量名是有區(qū)別的:

函數(shù)名是不能改變的,函數(shù)指定變量名是可以改變的

函數(shù)名的使用只能和函數(shù)體一起使用,如果嘗試在函數(shù)體外使用函數(shù)名的話會報(bào)錯(cuò)error或者返回undefined。比如:

y = function x(){};
alert(x);

另一方面,函數(shù)指定變量名(比如最后一例中的multiply)只被它自身(變量名)的作用域所約束,這個(gè)作用域一定包含函數(shù)聲明的作用域。

如同以上四個(gè)例子所示,函數(shù)名與函數(shù)指定變量名不同。它們彼此之間沒有關(guān)聯(lián)。

函數(shù)聲明同樣會創(chuàng)建一個(gè)和函數(shù)名一樣的變量。不像那些在函數(shù)表達(dá)式中定義的那樣,在函數(shù)聲明中定義的函數(shù)能在它們定義的作用域中通過它們的命名被訪問:

function x(){
}
console.log(x);   //返回function(){};

接下來的例子會展示函數(shù)名和函數(shù)指定變量是如何無關(guān)的。即使函數(shù)名被指定給了其他的變量名,返回的仍然是函數(shù)名:

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

一個(gè)由“new Function()”創(chuàng)建的新函數(shù)是沒有函數(shù)名的。在spiderMonkey的javascript引擎中,如果函數(shù)名為“anonymous”序列化的函數(shù)將會顯示,比如下例中使用“console.log(new Function())”的輸出:

function anonymous(){};
console.log(new Function());  //返回“function anonymous(){}” 

不像函數(shù)表達(dá)式定義的函數(shù)調(diào)用必須在函數(shù)表達(dá)式后面,函數(shù)聲明的函數(shù)調(diào)用可以在函數(shù)的前面,如下:

foo();
function foo(){
    alert("FOOO");
}

函數(shù)表達(dá)式中定義的函數(shù)會繼承當(dāng)前的作用域。就是說該函數(shù)是一個(gè)閉包。而使用Function創(chuàng)建的函數(shù)不會繼承任何的作用域除了全局作用域(所有的函數(shù)都會繼承)。

函數(shù)表達(dá)式和函數(shù)聲明定義的函數(shù)只會解析一次,但那些使用Function構(gòu)造的卻不是。就是說,通過new Function方式構(gòu)建函數(shù)時(shí)內(nèi)部的字符每一次都會重解析,函數(shù)本身不會重分析,于是函數(shù)表達(dá)式比“new Function(...)”這種方式要快。所以通過函數(shù)構(gòu)造方式分構(gòu)造函數(shù)無論何時(shí)都是應(yīng)該被避免的。這應(yīng)該被記下來,然而,函數(shù)表達(dá)式和函數(shù)聲明嵌套在通過函數(shù)構(gòu)造器構(gòu)造的中且立即執(zhí)行就不會重復(fù)解析多次,如下例:

var foo = (new Function("var bar="fooo!";
return(function(){
	alert("bar");
})"))();
foo();

函數(shù)聲明通常會很輕易的變成函數(shù)表達(dá)式,函數(shù)聲明不再是函數(shù)聲明的原因可能是因?yàn)樗鼭M足以下兩個(gè)條件:
1.變成了表達(dá)式的一部分。
2.它不再是函數(shù)的“資源元素”,一個(gè)“資源元素”是腳本或者函數(shù)中的一段非嵌套語句:

var x = 0;                  //資源元素
if (x == 0) {               //資源元素
    x = 10;                 //不是資源元素
    function boo() {}       //不是資源元素
}
function foo(){              //資源元素
    var y = 20;              //資源元素
    function bar() {}           //資源元素
    while(y == 10){             //資源元素
        function blah(){}      //不是資源元素
        y++;                   //不是資源元素
    }
}

例如:

//函數(shù)聲明
function foo(){}

//函數(shù)表達(dá)式
(function bar(){})

//函數(shù)表達(dá)式
var x = function hello(){}
if(x){
    //函數(shù)表達(dá)式
    function hello(){}
}
//函數(shù)聲明
function a(){
    //函數(shù)聲明
    function b(){}
    if(0) {
        //函數(shù)表達(dá)式
        function c(){}
    }
}
條件執(zhí)行函數(shù)

函數(shù)可以定義在條件語句里通過普通的function語句和new Function語句。但請注意以下這種情況ECMAScript5中不再允許出現(xiàn)函數(shù)語句,所以這個(gè)特性在跨瀏覽器中并不能表現(xiàn)的很好,你不能再編程中完全依賴它。
在下面的代碼中,這個(gè)zero函數(shù)永遠(yuǎn)都不能定義和執(zhí)行。因?yàn)閕f(0)永遠(yuǎn)都返回false;

if(0) {
    function zero(){
        document.writeln("This is a zero.");
    }
}

如果這個(gè)條件發(fā)生改變,if(1)那么zero就會被定義。

注意:盡管這一類函數(shù)看上去就像是函數(shù)聲明,但是它實(shí)際上是函數(shù)表達(dá)式。因?yàn)樗话谄渌臈l件語句中。看函數(shù)表達(dá)式和函數(shù)聲明有何不同.

注意:一些javascript的解析器,不包括SpiderMonkey,錯(cuò)誤的把命名函數(shù)表達(dá)式當(dāng)成了函數(shù)定義。這樣會導(dǎo)致zero會被定義即使if返回的是false。安全的方法是將匿名函數(shù)指定給變量:

if(0) {
    var zero = function(){
        document.writeln("This is zero.");
    }
}   
函數(shù)和事件處理程序

在JavaScript中, DOM事件處理程序只能是函數(shù)(相反的,其他DOM規(guī)范的綁定語言還可以使用一個(gè)包含handleEvent方法的對象做為事件處理程序)(譯者注:這句話已經(jīng)過時(shí),目前在大部分非IE[6,7,8]的瀏覽器中,都已經(jīng)支持一個(gè)對象作為事件處理程序). 在事件被觸發(fā)時(shí),該函數(shù)會被調(diào)用,一個(gè) event 對象會作為第一個(gè)也是唯一的一個(gè)參數(shù)傳入該函數(shù).像其他參數(shù)一樣,如果不需要使用該event對象, 則對應(yīng)的形參可以省略.

通常的HTML事件對象包括:window(Window對象,包括frames),document(HTMLdocument對象和elements(各種元素對象)。在HTMLDOM中,事件對象擁有時(shí)間處理程序?qū)傩裕@個(gè)屬性通常是小寫的有on前綴的,比如:onfocus。一個(gè)更加靈活的添加事件對象的方法有DOM2級事件。

注意:事件是DOM的一部分,而不是javascript的一部分。

下例會個(gè)window對象的onfocus事件綁定一個(gè)函數(shù):

window.onfocus = function() {
    document.body.style.backgroundColor = "blue";
}

如果函數(shù)綁定到了變量上,那么可以將事件指向該變量。如下:

var setBgColor = new Function("document.body.style.backgroundColor = "while" ");

你可以像如下的方法那樣使用它們:
1.給DOM的事件屬性指向變量:

document.form1.colorbutton.onclick = setBgColor;

2.HTML標(biāo)簽屬性:

上例在執(zhí)行過程中的效果如下代碼:

document.form1.colorbutton.onclick = function onclick(){
    setBgColor();
}

注意:怎樣在HTML中調(diào)用一個(gè)onclick返回事件的屬性。可以像如下這樣使用:


就像其他的參數(shù)參考的函數(shù)一樣,事件處理程序同樣是方法,在函數(shù)中返回的this對象會指向調(diào)用該方法的對象。比如:

window.onfocus

上例中在onfocus上綁定的事件處理程序的this對象就會指向window對象。
給事件綁定的有傳參的事件處理程序,必須被包含在其他的函數(shù)中:

document.form1.button1.onclick = function(){
    setBgColor("some color");
}
函數(shù)的局部變量

arguments:一個(gè)"類數(shù)組"的對象,包含了傳入當(dāng)前函數(shù)的所有實(shí)參;
arguments.callee:指向當(dāng)前函數(shù);
arguments.caller:指向調(diào)用當(dāng)前函數(shù)的函數(shù),請使用arguments.callee.caller代替;
arguments.length:arguments對象的中元素的個(gè)數(shù)。

同步于個(gè)人博客:http://penouc.com

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

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

相關(guān)文章

  • 閉包詳解

    摘要:函數(shù)中的閉包閉包是指有權(quán)訪問另一個(gè)函數(shù)作用域中的變量的函數(shù)。理解閉包預(yù)與變量此時(shí)返回注意觀察下面的輸出內(nèi)容,理解函數(shù)的調(diào)用時(shí)刻和把的賦值給變量時(shí)刻這個(gè)函數(shù)會返回長度為的函數(shù)數(shù)組。 Javascript函數(shù)中的閉包 閉包是指有權(quán)訪問另一個(gè)函數(shù)作用域中的變量的函數(shù)。創(chuàng)建閉包的常見方式就是,在一個(gè)函數(shù)的內(nèi)部創(chuàng)建另一個(gè)函數(shù)。 有關(guān)創(chuàng)建作用域鏈以及作用域鏈有什么作用的細(xì)節(jié)對于徹底理解閉包至關(guān)重...

    lunaticf 評論0 收藏0
  • JavaScript的作用詳解

    摘要:而閉包的神奇之處正是可以阻止這件事情的發(fā)生。事實(shí)上內(nèi)部作用域依然存在,因此沒有被回收頻繁使用閉包可能導(dǎo)致內(nèi)存泄漏。拜所聲明的位置所賜,它擁有涵蓋內(nèi)部作用域的閉包,使得該作用域能夠一直存活,以供在之后任何時(shí)間進(jìn)行引用。 作用域 作用域(scope),程序設(shè)計(jì)概念,通常來說,一段程序代碼中所用到的變量并不總是有效/可用的,而限定這個(gè)變量的可用性的代碼范圍就是這個(gè)變量的作用域。通俗一點(diǎn)就是我...

    cnio 評論0 收藏0
  • 詳解js中的閉包

    摘要:定義函數(shù)的時(shí)候,為什么的值重新從開始了因?yàn)橛忠淮芜\(yùn)行了函數(shù),生成一個(gè)新的的活動(dòng)對象,所以的作用域鏈引用的是一個(gè)新的值。 前言 在js中,閉包是一個(gè)很重要又相當(dāng)不容易完全理解的要點(diǎn),網(wǎng)上關(guān)于講解閉包的文章非常多,但是并不是非常容易讀懂,在這里以《javascript高級程序設(shè)計(jì)》里面的理論為基礎(chǔ)。用拆分的方式,深入講解一下對于閉包的理解,如果有不對請指正。 寫在閉包之前 閉包的內(nèi)部細(xì)節(jié),...

    chaosx110 評論0 收藏0
  • JavaScript深入淺出

    摘要:理解的函數(shù)基礎(chǔ)要搞好深入淺出原型使用原型模型,雖然這經(jīng)常被當(dāng)作缺點(diǎn)提及,但是只要善于運(yùn)用,其實(shí)基于原型的繼承模型比傳統(tǒng)的類繼承還要強(qiáng)大。中文指南基本操作指南二繼續(xù)熟悉的幾對方法,包括,,。商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請注明出處。 怎樣使用 this 因?yàn)楸救藢儆趥吻岸耍虼宋闹兄豢炊?8 成左右,希望能夠給大家?guī)韼椭?...(據(jù)說是阿里的前端妹子寫的) this 的值到底...

    blair 評論0 收藏0

發(fā)表評論

0條評論

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