淺談Javascript中的函數(shù)、this以及原型
關(guān)于函數(shù)
在Javascript中函數(shù)實際上就是一個對象,具有引用類型的特征,所以你可以將函數(shù)直接傳遞給變量,這個變量將表示指向函數(shù)“對象"的指針,例如:
function test(message){ alert(message); } var f = test; f('hello world');
你也可以直接將函數(shù)申明賦值給變量:
var f = function(message){ alert(message); }; f('hello world');
在這種情況下,函數(shù)申明中可以省略函數(shù)名稱,因為此時名稱已經(jīng)沒有任何意義,我們可直接通過變量f來調(diào)用函數(shù)。
通過Function類型,我們可以更好地理解函數(shù)即對象:
var f = new Function("message","alert(message);"); f('hello world');
關(guān)于this
this可以看成調(diào)用函數(shù)的實際作用域上下文。比較以下函數(shù)的執(zhí)行結(jié)果:
function test(){ this.property = 'hello world'; } test(); alert(window.property); //由于在全局范圍內(nèi)調(diào)用,test函數(shù)中的this實際指向全局對象(window) var obj = {}; test.call(obj); //通過call第一個參數(shù)指定執(zhí)行上下文范圍,所以test函數(shù)中this指向obj實例。 alert(obj.property); var obj2 = {}; obj2.test2 = test; //將obj2實例方法test指向 全局test方法 obj2.test2(); //由于是在obj2上調(diào)用test方法,所以test函數(shù)中的this也指向了obj2實例 alert(obj2.property);
定義類型
在Javascript中可以定義構(gòu)造函數(shù),構(gòu)造函數(shù)與一般函數(shù)沒有任何區(qū)別,在創(chuàng)建實例時,如果我們使用了new關(guān)鍵字,那么這個函數(shù)就具有構(gòu)造函數(shù)的特性,否則就是一般函數(shù),如下所示,我們定義了一個Person類型:
function Person(){ this.name = 'xfrog'; this.Say = function(){ alert(this.name); }; }
當使用new關(guān)鍵字時,可以創(chuàng)建一個新的Person對象實例:
var p1 = new Person(); p1.Say();
如果不使用new關(guān)鍵字,將直接執(zhí)行Person函數(shù),由于執(zhí)行上下文為全局范圍,故name屬性和Say方法將被添加到window對象:
Person(); Say(); window.Say();
原型
注意上述Person的定義方式,當使用new來創(chuàng)建Person實例時,將會執(zhí)行Person構(gòu)造函數(shù),也就是會聲明name屬性和Say方法,這樣可能產(chǎn)生效率問題,注意以下代碼:
var p1 = new Person(); var p2 = new Person(); var test = p1.Say == p2.Say;
比較p1和p2兩個Say函數(shù)指針,返回false,表示每個Person實例中的Say方法都是獨立的,而事實上Say函數(shù)的功能是完全一樣的,我們完全沒有必要為每個對象重新分配Say函數(shù)”對象“,如果Person實例很多,將會造成大量的內(nèi)存耗用。
如果將Say函數(shù)提取出來放入全局執(zhí)行范圍,似乎可解決次問題:
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始終和執(zhí)行上下文相關(guān),p1和p2實例中的Say方法中會正確地返回對應實例的name屬性。但是,使用此方式有違面向?qū)ο蟮乃枷?,也失去了類型密封的原則。還會造成大量的全局函數(shù)。
為了解決這些缺點,Javascript引出了原型的概念,簡單理解,原型可以看成是類型的共享區(qū),原型本身是一個對象,而對象中的屬性對于類型來說是共享的。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標準規(guī)定了類型屬性的查找順序:先在類型的實例上查找,如果沒有則繼續(xù)在類型原型上查找,這一查找路徑采用短路算法,即找到首個后即返回,考慮如下代碼:
function Person(){ this.name = 'wang'; } Person.prototype.name = 'xfrog'; Person.prototype.Say = function(){ alert(this.name); } var p1 = new Person(); p1.Say(); //將返回wang
上面提到prototype實際上是一個對象,那么我們是否可以直接訪問呢? 在一些瀏覽器實現(xiàn)(如Chrome、Fixfox等)的確可通過實例的__proto__屬性來訪問內(nèi)部的prototype對象,這種特征表明Javascript引擎在每個對象的內(nèi)部都是通過一個變量來保存對prototype的引用,這保證了prototype對應整個類型的實例來說是共享的,例如,你可在Chrome瀏覽器內(nèi)使用如下方式來訪問Say方法:
p1.__proto__["Say"]();
由于原型是一個對象,我們可以直接將一個對象賦值給prototype:
function Person(){ } Person.prototype = {name:'xfrog', Say:function(){ alert(this.name); }};
注意這個方式下,實際上是完全替換了Person的prototype,這與上面Person.prototype.name方式還是有細微差異的,這是因為任何類型,Javascript引擎都會添加默認的prototype,在這個prototype中包含一個對構(gòu)造函數(shù)的引用,即原型對象屬性constructor,所以通常使用替代prototype方式時,我們需要手動加上constructor屬性:
Person.prototype = { constructor: Person, name :'xfrog', Say:function(){ alert(this.name); } }
注意,由于prototype對于整個類型是共享的,那么在prototype中的引用類型可能會存在問題,前面的Say函數(shù)作為一個對象,也是引用類型,所以每個實例中的Say都指向原型對象中的同一個函數(shù),這本身沒有問題,也是我們使用原型的初衷,但對于其他引用對象,可能結(jié)果并不是我們想要的:
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屬性作為原型屬性是共享的,在內(nèi)存中只存在一個實例,所以通過p1修改后,p2只能得到修改后的狀態(tài)。如果要避免此情況,可將obj屬性放到實例中:
function Person(){ this.obj = { age: 18 }; }
以上就是小編為大家?guī)淼臏\談Javascript中的函數(shù)、this以及原型全部內(nèi)容了,希望大家多多支持腳本之家~
- 改變javascript函數(shù)內(nèi)部this指針指向的三種方法
- JS函數(shù)this的用法實例分析
- 詳解JS構(gòu)造函數(shù)中this和return
- JavaScript函數(shù)中的this四種綁定形式
- JavaScript 嵌套函數(shù)指向this對象錯誤的解決方法
- 深入理解Javascript箭頭函數(shù)中的this
- js對象內(nèi)部訪問this修飾的成員函數(shù)示例
- 深入理解js函數(shù)的作用域與this指向
- JS匿名函數(shù)內(nèi)部this指向問題詳析
- JavaScript箭頭函數(shù)中的this詳解
- js函數(shù)和this用法實例分析
相關(guān)文章
JS判斷鼠標進入容器的方向與window.open新窗口被攔截的問題
這篇文章主要給大家介紹了利用Javascript判斷鼠標進入容器方向的方法,以及window.open新窗口被攔截的問題分析,文中給出了詳細圖文介紹和示例代碼,相信對大家的理解和學習具有一定的參考借鑒價值,下面來一起看看吧。2016-12-12Javascript 構(gòu)造函數(shù) 實例分析
一般構(gòu)造函數(shù)沒有返回值,他們通過關(guān)鍵字this初始化對象,沒有返回值。當然一個構(gòu)造器允許返回一個對 象,如果這樣的話 返回的對象將變成new 表達式的值,在這種情況下值為this的對象將拋棄2008-11-11bootstrap fileinput組件整合Springmvc上傳圖片到本地磁盤
這篇文章主要介紹了bootstrap fileinput組件整合Springmvc上傳圖片到本地磁盤的方法,需要的朋友可以參考下2017-05-05javascript中獲取元素標簽中間的內(nèi)容的實現(xiàn)方法
下面小編就為大家?guī)硪黄猨avascript中獲取元素標簽中間的內(nèi)容的實現(xiàn)方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-10-10