国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > JavaScript > 正文

淺談Javascript中的函數、this以及原型

2019-11-20 08:47:55
字體:
來源:轉載
供稿:網友

關于函數

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

function test(message){     alert(message);   }   var f = test;   f('hello world');

你也可以直接將函數申明賦值給變量:

var f = function(message){     alert(message);      };f('hello world');

在這種情況下,函數申明中可以省略函數名稱,因為此時名稱已經沒有任何意義,我們可直接通過變量f來調用函數。

通過Function類型,我們可以更好地理解函數即對象:

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

關于this

this可以看成調用函數的實際作用域上下文。比較以下函數的執行結果:

function test(){     this.property = 'hello world';   }   test();   alert(window.property);  //由于在全局范圍內調用,test函數中的this實際指向全局對象(window)   var obj = {};   test.call(obj);   //通過call第一個參數指定執行上下文范圍,所以test函數中this指向obj實例。   alert(obj.property);      var obj2 = {};   obj2.test2 = test;   //將obj2實例方法test指向 全局test方法   obj2.test2();      //由于是在obj2上調用test方法,所以test函數中的this也指向了obj2實例   alert(obj2.property);

定義類型

在Javascript中可以定義構造函數,構造函數與一般函數沒有任何區別,在創建實例時,如果我們使用了new關鍵字,那么這個函數就具有構造函數的特性,否則就是一般函數,如下所示,我們定義了一個Person類型:

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

當使用new關鍵字時,可以創建一個新的Person對象實例:

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

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

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

原型

注意上述Person的定義方式,當使用new來創建Person實例時,將會執行Person構造函數,也就是會聲明name屬性和Say方法,這樣可能產生效率問題,注意以下代碼:

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

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

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

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();

由于this始終和執行上下文相關,p1和p2實例中的Say方法中會正確地返回對應實例的name屬性。但是,使用此方式有違面向對象的思想,也失去了類型密封的原則。還會造成大量的全局函數。

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

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

為什么這里可以通過p1.Say來訪問Say方法呢?這是因為ECMAScript標準規定了類型屬性的查找順序:先在類型的實例上查找,如果沒有則繼續在類型原型上查找,這一查找路徑采用短路算法,即找到首個后即返回,考慮如下代碼:

function Person(){     this.name = 'wang';   }   Person.prototype.name = 'xfrog';   Person.prototype.Say = function(){     alert(this.name);   }   var p1 = new Person();   p1.Say();   //將返回wang

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

p1.__proto__["Say"]();

由于原型是一個對象,我們可以直接將一個對象賦值給prototype:

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

注意這個方式下,實際上是完全替換了Person的prototype,這與上面Person.prototype.name方式還是有細微差異的,這是因為任何類型,Javascript引擎都會添加默認的prototype,在這個prototype中包含一個對構造函數的引用,即原型對象屬性constructor,所以通常使用替代prototype方式時,我們需要手動加上constructor屬性:

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

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

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();

p2.Say返回的是20,這是因為obj屬性作為原型屬性是共享的,在內存中只存在一個實例,所以通過p1修改后,p2只能得到修改后的狀態。如果要避免此情況,可將obj屬性放到實例中:

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

以上就是小編為大家帶來的淺談Javascript中的函數、this以及原型全部內容了,希望大家多多支持武林網~

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 府谷县| 称多县| 璧山县| 科技| 西城区| 上栗县| 江川县| 广安市| 陆丰市| 荆门市| 洛宁县| 壶关县| 珲春市| 安阳县| 田东县| 石阡县| 大方县| 东源县| 固阳县| 区。| 黄冈市| 莲花县| 新宾| 海丰县| 轮台县| 中卫市| 呼伦贝尔市| 页游| 金寨县| 揭东县| 永修县| 东源县| 古丈县| 石渠县| 思南县| 荆门市| 九寨沟县| 远安县| 屏山县| 宁南县| 卢龙县|