成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

JavaScript函數(shù)(arguments,this)的理解

seanHai / 2958人閱讀

摘要:除語法不同外,兩者的區(qū)別在于解析器讀取的順序。解析器會(huì)事先讀取函數(shù)聲明,即使你把函數(shù)聲明放在代碼的末端也沒關(guān)系。修改對(duì)象將可能導(dǎo)致命名參數(shù)失去意義。其實(shí)除允許匿名函數(shù)遞歸調(diào)用自身外,并沒有什么太大用處。

javaScript因?yàn)槠湔Z法松散,導(dǎo)致函數(shù)(尤其是this)看似簡(jiǎn)單,其實(shí)里面花頭很多。本篇介紹一下JavaScript函數(shù)及其調(diào)用方法。
? 函數(shù)聲明和函數(shù)表達(dá)式
? arguments
? this
? this補(bǔ)充說明

函數(shù)聲明和函數(shù)表達(dá)式
JavaScript里對(duì)象字面量產(chǎn)生的對(duì)象將被連接到Object.prototype,函數(shù)對(duì)象將被連接到Function.prototype(但該對(duì)象本身也連接到Object.prototype)。先看一下函數(shù)聲明和函數(shù)表達(dá)式(分匿名和命名):

function count(a,b){ return a*b; }              //函數(shù)聲明
var d1 = function(n) { return n*2; };           //匿名函數(shù)表達(dá)式
var d2 = function double(n) { return n*2; };    //命名函數(shù)表達(dá)式

console.log(count(3,4));    //12
console.log(d1(3));         //6
console.log(d2(3));         //6
console.log(double(3));    //error,double未定義

上面代碼可以看出函數(shù)聲明和函數(shù)表達(dá)式在后續(xù)的調(diào)用中,效果是沒有差別的。除語法不同外,兩者的區(qū)別在于JS解析器讀取的順序。

解析器會(huì)事先讀取函數(shù)聲明,即使你把函數(shù)聲明放在代碼的末端也沒關(guān)系。而對(duì)于函數(shù)表達(dá)式,同其它基本類型的變量一樣,只有在執(zhí)行到該行語句時(shí)才解析。因此用函數(shù)表達(dá)式時(shí),必須確保它在調(diào)用語句之前,否則會(huì)報(bào)錯(cuò)。
再看匿名和命名函數(shù)表達(dá)式的區(qū)別。上例中命名函數(shù)表達(dá)式將函數(shù)綁定到變量d2上,而非變量double上,因此double(3);會(huì)出現(xiàn)未定義error。

那命名函數(shù)表達(dá)式有什么用呢?比如上面的變量double有什么用呢?函數(shù)名double可用于在函數(shù)內(nèi)部做遞歸,但可惜仍舊沒必要,因?yàn)樽兞縟2同樣也可以在函數(shù)內(nèi)部遞歸。因此命名函數(shù)表達(dá)式真正的作用在于調(diào)試,JavaScript環(huán)境提供對(duì)Error對(duì)象的棧追蹤功能,可以用double進(jìn)行棧追蹤。

但命名函數(shù)表達(dá)式仍舊有很多問題,類似with一樣。因此通常推薦用匿名函數(shù)表達(dá)式,不推薦用命名函數(shù)表達(dá)式:

var d1 = function(n) { return n*2; };           //Yes,推薦
var d2 = function double(n) { return n*2; };    //No,不推薦

arguments
每個(gè)函數(shù)都接受2個(gè)附加參數(shù):this和arguments。先看arguments。JS的函數(shù)參數(shù)其實(shí)就是個(gè)類似數(shù)組的arguments對(duì)象,是對(duì)形參的一個(gè)映射,但是值是通過索引來獲取的。因此JS的函數(shù)天然支持可變參數(shù)。
arguments對(duì)象看似像數(shù)組,但請(qǐng)不要使用arguments.shift()等方法來修改arguments。修改arguments對(duì)象將可能導(dǎo)致命名參數(shù)失去意義。

例如person(name, age),參數(shù)name是arguments[0]的別名,age是arguments[1]的別名,如果用shift移除arguments后,name仍舊是arguments[0]的別名,age仍舊是arguments[1]的別名,函數(shù)開始失控。
因此,如果你無論如何要修改arguments,需要先將arguments對(duì)象轉(zhuǎn)化為真正的數(shù)組:
var args = [].slice.call(arguments);

之后對(duì)args對(duì)象進(jìn)行shift()等操作。這也常見于獲取可變參數(shù)值,同樣需要上述那樣將arguments對(duì)象轉(zhuǎn)化為真正的數(shù)組。
另外每個(gè)arguments對(duì)象都有兩個(gè)額外的屬性:arguments.callee和arguments.caller。前者指向使用該arguments對(duì)象被調(diào)用的函數(shù)。后者指向調(diào)用該arguments對(duì)象的函數(shù)。

其實(shí)arguments.callee除允許匿名函數(shù)遞歸調(diào)用自身外,并沒有什么太大用處。但可惜用函數(shù)名也能實(shí)現(xiàn)遞歸,所以它真沒什么用處:

//用arguments.callee來遞歸
var factorial = (function(n) {
    return (n <= 1) ? 1 : (n * arguments.callee(n - 1));    //遞歸
});

//但也可以直接用函數(shù)名來遞歸
function factorial(n) {

return (n <= 1) ? 1 : (n * factorial(n - 1));    

}
用arguments.caller可以跟蹤棧信息,但它不可靠,如果某函數(shù)在棧中出現(xiàn)了不止一次,很容易陷入死循環(huán),大多數(shù)環(huán)境已經(jīng)移除了此特性。
JS嚴(yán)格模式下禁止使用arguments.callee和arguments.caller,因此這兩個(gè)屬性就不多廢話了。
this
arguments介紹完后,再來看看this。在JS中this取決于調(diào)用的方式,不同的函數(shù)調(diào)用方式,this綁定的對(duì)象也不同。有4種調(diào)用方式:
? 方法調(diào)用
? 函數(shù)調(diào)用
? 構(gòu)造器調(diào)用
? apply / call / bind調(diào)用
方法調(diào)用:當(dāng)函數(shù)作為對(duì)象方法時(shí),函數(shù)里的this被綁定到該var myNum = {

value: 0,
increment: function(inc) {  //函數(shù)作為對(duì)象方法
    this.value += inc;
}

};
myNum.increment(2);
console.log(myNum.value); //2,this被綁定到myNum用:函數(shù)非對(duì)象方法時(shí),this被綁定到全局對(duì)象window。這其實(shí)是語言設(shè)計(jì)上的一個(gè)錯(cuò)誤(或曰特性),導(dǎo)致this不能調(diào)用內(nèi)部函數(shù)。要調(diào)用內(nèi)部函數(shù),可以將that = this保存起來。
function double(n){ return n*2; } //普通函數(shù),this綁定到全局對(duì)象window

//錯(cuò)誤的例子
myNum.count = function() {

var helper = function() {
    this.value = double(this.value);
};
helper();

}
myNum.count();
console.log(myNum.value); //value不變

//正確的例子:
myNum.count = function() {

var that = this;       
var helper = function() {
    that.value = double(that.value);   //現(xiàn)在參數(shù)是myNum.value
};
helper();

}
myNum.count();
console.log(myNum.value); //4

錯(cuò)誤的例子中,期望this綁定的是對(duì)象myNum,但由于double是普通函數(shù),因此this綁定的是window,而window顯然沒有value。即helper里this是window,因此double(this.value);不會(huì)被執(zhí)行。最終myNum的value值并沒有變。
正確的例子在對(duì)象myNum方法里,this綁定的是myNum對(duì)象,因此先用that將this保存起來。然后在內(nèi)部傳遞的都是that,回避了helper函數(shù)內(nèi)this發(fā)生改變的問題。這里寫代碼片
構(gòu)造函數(shù)調(diào)用:用new調(diào)用構(gòu)造函數(shù),會(huì)先創(chuàng)建一個(gè)連接到構(gòu)造函數(shù)的prototype的新對(duì)象,再將this會(huì)綁定到該新對(duì)象

var Name = function(n) { 
    this.name = n; 
}
Name.prototype.getName = function() {
    return this.name;
}
var myName = new Name("Jack");      //this綁定到myName對(duì)象
console.log(myName.getName());          //Jack
apply / call / bind調(diào)用:允許我們自己綁定想要的this
var friend = {
    name: "Betty"
};
console.log(Name.prototype.getName.apply(friend));    //Betty
console.log(Name.prototype.getName.call(friend));     //Betty
console.log(Name.prototype.getName.bind(friend)());   //Betty

this補(bǔ)充說明
這一節(jié)并無任何新的內(nèi)容,只不過對(duì)this進(jìn)一步補(bǔ)充說明一下。我們知道對(duì)象都有prototype俗稱原型對(duì)象。那prototype里的this綁定誰呢?其實(shí)原則沒有變,從上面構(gòu)造函數(shù)調(diào)用的例子就能看出this仍舊是綁定調(diào)用的對(duì)象。
為了更清晰一點(diǎn),將上面構(gòu)造函數(shù)調(diào)用的例子稍微改一下:

var Name = function() {};
Name.prototype =  {
    name: "(not set)",
    setName: function(n) {
        this.name = n;
    }
}

var myName = new Name();
console.log(myName.name);                   //(not set)
console.log(myName.hasOwnProperty("name"));    //false
console.log(myName.hasOwnProperty("setName"));   //false

myName.setName("Jack");
console.log(myName.name);                       //Jack
console.log(myName.hasOwnProperty("name"));    //true
console.log(myName.hasOwnProperty("setName"));   //false

先看第一段結(jié)果代碼,Name本身沒有任何屬性,name和setName是在它的原型prototype中定義的。因此用hasOwnProperty來檢查全是false。這與我們的預(yù)想完全一致,沒什么可奇怪的。
再看第二段結(jié)果代碼,由于執(zhí)行了myName.setName("Jack");。原型prototype中的this不是綁定原型對(duì)象,而是綁定調(diào)用的對(duì)象。即setName中的this綁定的是對(duì)象myName,會(huì)給對(duì)象增加一個(gè)name屬性。所以hasOwnProperty("name")會(huì)為true。

self補(bǔ)充說明

這個(gè)非常簡(jiǎn)單。我們知道,打開任何一個(gè)網(wǎng)頁,瀏覽器會(huì)首先創(chuàng)建一個(gè)窗口,這個(gè)窗口就是一個(gè)window對(duì)象,也是js運(yùn)行所依附的全局環(huán)境對(duì)象和全局作用域?qū)ο?。self 指窗口本身,它返回的對(duì)象跟window對(duì)象是一模一樣的。也正因?yàn)槿绱?,window對(duì)象的常用方法和函數(shù)都可以用self代替window。舉個(gè)例子,常見的寫法如“self.close();”,把它放在標(biāo)記中:“關(guān)閉窗口”,單擊“關(guān)閉窗口”鏈接,當(dāng)前頁面關(guān)閉。

明白這些原理后,再回過頭看看以前不明白的代碼里this,that,self等就輕松多了。

更多資源上:去轉(zhuǎn)盤;或者加我的QQ群參與js,css的討論學(xué)習(xí)(QQ群:512245829)

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

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

相關(guān)文章

  • javascript高級(jí)程序設(shè)計(jì)》函數(shù)調(diào)用模式 & this深度理解

    在上一篇文章(《javascript高級(jí)程序設(shè)計(jì)》筆記:Function類型)中稍微提及了一下函數(shù)對(duì)象的屬性—this,在這篇文章中有深入的說明: 函數(shù)的三種簡(jiǎn)單調(diào)用模式 1 函數(shù)模式 定義的函數(shù),如果單獨(dú)調(diào)用,不將其與任何對(duì)象關(guān)聯(lián),那么就是函數(shù)調(diào)用模式 function fn(num1, num2) { console.log(this); } // 直接在全局調(diào)用 fn();// w...

    wyk1184 評(píng)論0 收藏0
  • JavaScript函數(shù)(二)

    摘要:目錄函數(shù)的聲明函數(shù)的屬性和方法函數(shù)的作用域閉包知識(shí)點(diǎn)小結(jié)關(guān)于函數(shù),可以從以下個(gè)方面去理解首先,數(shù)據(jù)類型上看函數(shù)在中是一種數(shù)據(jù)類型,是對(duì)象的一種其次,從功能上看函數(shù)本質(zhì)上是一段反復(fù)調(diào)用的代碼塊最后,從地位上看函數(shù)在中和其他基本數(shù)據(jù)類型一樣,可 目錄 1.函數(shù)的聲明 2.函數(shù)的屬性和方法 3.函數(shù)的作用域 4.閉包知識(shí)點(diǎn) 5.小結(jié) 關(guān)于函數(shù),可以從以下3個(gè)方面去理解:首先,數(shù)據(jù)類型上看:...

    用戶84 評(píng)論0 收藏0
  • js基本操作-this理解

    摘要:基本操作理解寫在前面在面向?qū)ο蟮恼Z言中,關(guān)鍵字的含義是明確且具體的,即指代當(dāng)前對(duì)象。一般在編譯期確定下來,或稱為編譯期綁定。全局范圍內(nèi)當(dāng)在全部范圍內(nèi)使用,它將會(huì)指向全局對(duì)象。輸出瀏覽器中運(yùn)行的腳本,這個(gè)全局對(duì)象是。 js基本操作-this理解 寫在前面 在面向?qū)ο蟮恼Z言中,this關(guān)鍵字的含義是明確且具體的,即指代當(dāng)前對(duì)象。一般在編譯期確定下來,或稱為編譯期綁定。而在 JavaScr...

    Steven 評(píng)論0 收藏0
  • 理解 JavaScript call()/apply()/bind()

    摘要:理解文章中已經(jīng)比較全面的分析了在中的指向問題,用一句話來總結(jié)就是的指向一定是在執(zhí)行時(shí)決定的,指向被調(diào)用函數(shù)的對(duì)象。與和直接執(zhí)行原函數(shù)不同的是,返回的是一個(gè)新函數(shù)。這個(gè)新函數(shù)包裹了原函數(shù),并且綁定了的指向?yàn)閭魅氲摹? 理解 JavaScript this 文章中已經(jīng)比較全面的分析了 this 在 JavaScript 中的指向問題,用一句話來總結(jié)就是:this 的指向一定是在執(zhí)行時(shí)決定的,...

    duan199226 評(píng)論0 收藏0
  • JavaScript基礎(chǔ)系列---執(zhí)行環(huán)境與作用域鏈

    摘要:延長(zhǎng)作用域鏈下面兩種語句可以在作用域鏈的前端臨時(shí)增加一個(gè)變量對(duì)象以延長(zhǎng)作用域鏈, 問題 今天看筆記發(fā)現(xiàn)自己之前記了一個(gè)關(guān)于同名標(biāo)識(shí)符優(yōu)先級(jí)的內(nèi)容,具體是下面這樣的: 形參優(yōu)先級(jí)高于當(dāng)前函數(shù)名,低于內(nèi)部函數(shù)名 形參優(yōu)先級(jí)高于arguments 形參優(yōu)先級(jí)高于只聲明卻未賦值的局部變量,但是低于聲明且賦值的局部變量 函數(shù)和變量都會(huì)聲明提升,函數(shù)名和變量名同名時(shí),函數(shù)名的優(yōu)先級(jí)要高。執(zhí)行代...

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

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

0條評(píng)論

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