一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

Javascript中的函數(shù)、this以及原型

 Tehero 2015-05-27

關(guān)于函數(shù)

     在Javascript中函數(shù)實(shí)際上就是一個(gè)對(duì)象,具有引用類型的特征,所以你可以將函數(shù)直接傳遞給變量,這個(gè)變量將表示指向函數(shù)“對(duì)象"的指針,例如:

function test(message){
          alert(message);
     }
     var f = test;
     f('hello world');
你也可以直接將函數(shù)申明賦值給變量:
var f = function(message){
          alert(message);     
     };
     f('hello world');

     在這種情況下,函數(shù)申明中可以省略函數(shù)名稱,因?yàn)榇藭r(shí)名稱已經(jīng)沒有任何意義,我們可直接通過變量f來調(diào)用函數(shù)。

     通過Function類型,我們可以更好地理解函數(shù)即對(duì)象:

var f = new Function("message","alert(message);");
     f('hello world');

關(guān)于this

     this可以看成調(diào)用函數(shù)的實(shí)際作用域上下文。比較以下函數(shù)的執(zhí)行結(jié)果:

復(fù)制代碼
function test(){
          this.property = 'hello world';

     }
     test();
     alert(window.property);   //由于在全局范圍內(nèi)調(diào)用,test函數(shù)中的this實(shí)際指向全局對(duì)象(window)

     var obj = {};
     test.call(obj);      //通過call第一個(gè)參數(shù)指定執(zhí)行上下文范圍,所以test函數(shù)中this指向obj實(shí)例。
     alert(obj.property);      

     var obj2 = {};
     obj2.test2 = test;      //將obj2實(shí)例方法test指向 全局test方法
     obj2.test2();            //由于是在obj2上調(diào)用test方法,所以test函數(shù)中的this也指向了obj2實(shí)例
     alert(obj2.property);
復(fù)制代碼

定義類型

     在Javascript中可以定義構(gòu)造函數(shù),構(gòu)造函數(shù)與一般函數(shù)沒有任何區(qū)別,在創(chuàng)建實(shí)例時(shí),如果我們使用了new關(guān)鍵字,那么這個(gè)函數(shù)就具有構(gòu)造函數(shù)的特性,否則就是一般函數(shù),如下所示,我們定義了一個(gè)Person類型:

function Person(){
     this.name = 'xfrog';
     this.Say = function(){
          alert(this.name);
     };
}

     當(dāng)使用new關(guān)鍵字時(shí),可以創(chuàng)建一個(gè)新的Person對(duì)象實(shí)例:

var p1 = new Person();
p1.Say();

     如果不使用new關(guān)鍵字,將直接執(zhí)行Person函數(shù),由于執(zhí)行上下文為全局范圍,故name屬性和Say方法將被添加到window對(duì)象:

Person();
Say();
window.Say();

原型

     注意上述Person的定義方式,當(dāng)使用new來創(chuàng)建Person實(shí)例時(shí),將會(huì)執(zhí)行Person構(gòu)造函數(shù),也就是會(huì)聲明name屬性和Say方法,這樣可能產(chǎn)生效率問題,注意以下代碼:

var p1 = new Person();
     var p2 = new Person();
     var test = p1.Say == p2.Say;

     比較p1和p2兩個(gè)Say函數(shù)指針,返回false,表示每個(gè)Person實(shí)例中的Say方法都是獨(dú)立的,而事實(shí)上Say函數(shù)的功能是完全一樣的,我們完全沒有必要為每個(gè)對(duì)象重新分配Say函數(shù)”對(duì)象“,如果Person實(shí)例很多,將會(huì)造成大量的內(nèi)存耗用。

     如果將Say函數(shù)提取出來放入全局執(zhí)行范圍,似乎可解決次問題:

復(fù)制代碼
function Person(){
          this.name = 'xfrog';
          this.Say = say;     
     }

     function say(){
          alert(this.name);     
     }

     var p1 = new Person();
     var p2 = new Person();
     alert(p1.Say == p2.Say);
     p1.name = 'wang';
     p1.Say();
復(fù)制代碼

      由于this始終和執(zhí)行上下文相關(guān),p1和p2實(shí)例中的Say方法中會(huì)正確地返回對(duì)應(yīng)實(shí)例的name屬性。但是,使用此方式有違面向?qū)ο蟮乃枷?,也失去了類型密封的原則。還會(huì)造成大量的全局函數(shù)。

     為了解決這些缺點(diǎn),Javascript引出了原型的概念,簡(jiǎn)單理解,原型可以看成是類型的共享區(qū),原型本身是一個(gè)對(duì)象,而對(duì)象中的屬性對(duì)于類型來說是共享的。Javascript中每個(gè)類型通過prototype屬性來表示原型,通過這個(gè)屬性可指定共享方法:

 

復(fù)制代碼
function Person(){

     }
     Person.prototype.name = 'xfrog';
     Person.prototype.Say = function(){
          alert(this.name);
     };

     var p1 = new Person();
     var p2 = new Person();
     alert(p1.Say == p2.Say);     //返回true
復(fù)制代碼

     為什么這里可以通過p1.Say來訪問Say方法呢?這是因?yàn)镋CMAScript標(biāo)準(zhǔn)規(guī)定了類型屬性的查找順序:先在類型的實(shí)例上查找,如果沒有則繼續(xù)在類型原型上查找,這一查找路徑采用短路算法,即找到首個(gè)后即返回,考慮如下代碼:

復(fù)制代碼
function Person(){
          this.name = 'wang';
     }

     Person.prototype.name = 'xfrog';
     Person.prototype.Say = function(){
          alert(this.name);
     }

     var p1 = new Person();
     p1.Say();      //將返回wang
復(fù)制代碼

 

     上面提到prototype實(shí)際上是一個(gè)對(duì)象,那么我們是否可以直接訪問呢? 在一些瀏覽器實(shí)現(xiàn)(如Chrome、Fixfox等)的確可通過實(shí)例的__proto__屬性來訪問內(nèi)部的prototype對(duì)象,這種特征表明Javascript引擎在每個(gè)對(duì)象的內(nèi)部都是通過一個(gè)變量來保存對(duì)prototype的引用,這保證了prototype對(duì)應(yīng)整個(gè)類型的實(shí)例來說是共享的,例如,你可在Chrome瀏覽器內(nèi)使用如下方式來訪問Say方法:

p1.__proto__["Say"]();

     由于原型是一個(gè)對(duì)象,我們可以直接將一個(gè)對(duì)象賦值給prototype:

復(fù)制代碼
function Person(){

     }

     Person.prototype = {name:'xfrog', Say:function(){
          alert(this.name);
     }};
復(fù)制代碼

     注意這個(gè)方式下,實(shí)際上是完全替換了Person的prototype,這與上面Person.prototype.name方式還是有細(xì)微差異的,這是因?yàn)槿魏晤愋?,Javascript引擎都會(huì)添加默認(rèn)的prototype,在這個(gè)prototype中包含一個(gè)對(duì)構(gòu)造函數(shù)的引用,即原型對(duì)象屬性constructor,所以通常使用替代prototype方式時(shí),我們需要手動(dòng)加上constructor屬性:

復(fù)制代碼
Person.prototype = { 
          constructor: Person,
          name :'xfrog',
          Say:function(){
               alert(this.name);
          }
     }
復(fù)制代碼

     注意,由于prototype對(duì)于整個(gè)類型是共享的,那么在prototype中的引用類型可能會(huì)存在問題,前面的Say函數(shù)作為一個(gè)對(duì)象,也是引用類型,所以每個(gè)實(shí)例中的Say都指向原型對(duì)象中的同一個(gè)函數(shù),這本身沒有問題,也是我們使用原型的初衷,但對(duì)于其他引用對(duì)象,可能結(jié)果并不是我們想要的:

復(fù)制代碼
function Person(){
     }

     Person.prototype = {
          name: 'xfrog',
          obj : { age: 18 },
          Say : function(){
               alert(this.obj.age);
          }
     };

     var p1 = new Person();
     var p2 = new Person();
     p1.obj.age = 20;
     p1.Say();
     p2.Say();
復(fù)制代碼

      p2.Say返回的是20,這是因?yàn)閛bj屬性作為原型屬性是共享的,在內(nèi)存中只存在一個(gè)實(shí)例,所以通過p1修改后,p2只能得到修改后的狀態(tài)。如果要避免此情況,可將obj屬性放到實(shí)例中:

function Person(){
          this.obj = { age: 18 };
     }

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多

    四季精品人妻av一区二区三区| 四季av一区二区播放| 欧美一级特黄特色大色大片| 日韩欧美国产高清在线| 欧美亚洲综合另类色妞| 国产偷拍盗摄一区二区| 日本男人女人干逼视频| 青青草草免费在线视频| 婷婷伊人综合中文字幕| 欧美一区二区不卡专区| 国产成人精品99在线观看| 冬爱琴音一区二区中文字幕| a久久天堂国产毛片精品| 久热99中文字幕视频在线| 日韩中文字幕在线不卡一区| 国产欧美日韩精品一区二| 91蜜臀精品一区二区三区| 91偷拍裸体一区二区三区| 日韩中文字幕在线不卡一区| 日韩中文字幕视频在线高清版 | 亚洲欧美日韩网友自拍| 亚洲午夜精品视频在线| 久久精品色妇熟妇丰满人妻91| 九九九热视频最新在线| 日韩性生活片免费观看| 欧美乱码精品一区二区三| 久久精品久久久精品久久| 日本熟妇熟女久久综合| 欧美乱视频一区二区三区| 亚洲高清中文字幕一区二三区| 精品香蕉一区二区在线| 又大又长又粗又黄国产| 97人摸人人澡人人人超碰| 国产户外勾引精品露出一区| 厕所偷拍一区二区三区视频| 久久午夜福利精品日韩| 色婷婷在线视频免费播放| 欧美国产日产综合精品| 熟女乱一区二区三区四区| 成人欧美一区二区三区视频| 国产白丝粉嫩av在线免费观看|