今天研究了一下js的原型,把自己的理解寫到這里,如有不正確的地方,還望指出,在此先謝過啦~
什么是原型?原型是一個對象。所有對象都有原型。任何一個對象也都可以成為其他對象的原型。
每個原型都有一個 constructor 屬性指向其構造函數。
一個對象的原型被對象內部的 [[Prototype]] 屬性所持有。
一句話就是,所有對象都有原型,其原型是該對象的內部屬性。那么有哪些方法可以訪問到這個內部屬性呢?
ECMAScript 5 增加了方法 Object.getPrototypeOf() ,用于返回對象 [[Prototype]] 的值。IE 9+、Firefox 3.5+、Safari 5+、Opera 12+ 和 Chrome 都實現了該方法。
除了IE,其他瀏覽器都支持非標準的訪問器 __proto__
如果這兩者都不起作用,我們就需要通過對象的構造函數找它的原型屬性了。
var a = {}; Object.getPrototypeOf(a); a.__proto__; a.constructor.prototype;函數的 prototype 屬性
不知親剛剛有沒有注意到訪問 [[Prototype]] 的最后一個方法 a.constructor.prototype; ,直接使用了構造函數的 prototype屬性。
在這里要多說兩句,js中函數也是對象,所以函數也有原型,其原型也和其他對象一樣,可以通過 Object.getPrototypeOf() 和 __proto__ 訪問。但是創建對象時,我們往往要使用構造函數 (constructor) 的原型,為了用起來方便,就給構造函數添加了 prototype 屬性,用于直接訪問其原型。由于所有的函數都可以成為構造函數,所以就造就了函數有那么一點點特(you)殊(shi)—— 一個函數可以通過其 prototype 屬性直接訪問其原型,或者說 一個函數的 prototype 屬性指向其原型對象。
如果僅僅只是因為一個實例而使用原型是沒有多大意義的,這和直接添加屬性到這個實例是一樣的。原型真正魅力體現在多個實例共用一個原型,原型對象的屬性一旦定義,就可以被多個引用它的實例所繼承,這種操作在性能和維護方面其意義是不言自明的。
這也是構造函數存在的原因,構造函數提供了一種方便的跨瀏覽器機制,這種機制允許在創建實例時為實例提供一個通用的原型。
原型語法在使用原型前,先寫一下構造函數部分。
function Calculator (decimalDigits, tax) { this.decimalDigits = decimalDigits; this.tax = tax; };分步聲明
分開設置原型的每個屬性。
Calculator.prototype.add = function (x, y) { return x + y; }; Calculator.prototype.subtract = function (x, y) { return x - y; };
這樣,在new Calculator對象以后,就可以調用add方法來計算結果了。
此時, Calculator.prototype 的 constructor 屬性指向 Calculator。即:
Calculator.prototype.constructor = Calculator
通過給Calculator的prototype屬性賦值對象字面量來設定Calculator對象的原型。
Calculator.prototype = { add: function (x, y) { return x + y; }, subtract: function (x, y) { return x - y; } };
上面的代碼中,將 Calculator.prototype 賦值為一個以對象字面量形式創建的新對象。最終結果相同,但是,此時 constructor 屬性不再指向 Calculator ,即 Calculator.prototype.constructor != Calculator 。
每創建一個函數,就會同時創建它的 prototype 對象,這個對象會自動獲得 constructor 屬性。而我們這里使用的語法,本質上完全重寫了默認的 prototype 對象,因此 constructor 屬性也就變成了新對象的 constructor 屬性 —— 指向 Object 構造函數。
如果 constructor 的值很重要,可以向下面一樣設定:
Calculator.prototype = { constructor: Calculator, // 修復constructor 屬性 add: function (x, y) { return x + y; }, subtract: function (x, y) { return x - y; } };其他方式
使用function立即執行的表達式來為prototype賦值,格式如下:
Calculator.prototype = function () { var add = function (x, y) { return x + y; }, var subtract = function (x, y) { return x - y; } return { add: add, subtract: subtract } } ();原型的動態性
var friend = new Person(); Person.prototype.sayHi = function () { alert("hi"); }; friend.sayHi(); // "hi" (沒有問題)
在以上代碼中,即使 friend 是在添加新方法之前創建的,但它仍然可以訪問這個新方法。其原因可以歸結為實例與原型之間的松散連接關系。當我們調用 friend.sayHi() 時,會首先在實例中搜索名為 sayHi 的屬性,在沒有找到的情況下,會繼續搜索原型。因為實例實例與原型之間連接是一個指針,而非副本,因此可以在原型中找到新的 sayHi 屬性并返回保存在那里的函數。
可以隨時為原型添加屬性和方法,并且修改能立即在所有對象實例中反映出來,但如果重寫了原型對象,那結果就不一樣了……
function Person () { } var friend = new Person(); Person.prototype = { constructor: Person, name: "Nicholas", age: 29, job: "software Engineer", sayHi: function () { alert("hi"); } }; friend.sayHi(); // error
在這個例子中,先創建了 friend 實例,然后又重寫其原型對象。在調用 friend.sayHi() 時發生錯誤,因為friend 指向的原型中不包含以該名字命名的屬性。
重寫原型對象切斷了現有原型與任何之前已經存在的對象實例之間的聯系,這些實例仍然引用的是最初的原型。
一切都是對象這部分與原型沒什么大關系,只是看到了覺有幫助,就插到這里了,莫要見怪 :)
當然,也不是所有的都是對象,值類型就不是對象。
舉個不太容易理解的例子,函數作為對象時,其屬性還是函數的例子。
var fn = function () { alert(100); }; fn.a = 10; fn.b = function () { alert(123); }; fn.c = { name: "福布斯", year: 1968 };
上段代碼中,函數就作為對象被賦值了a、b、c三個屬性,第二個屬性值就是函數,這個有用嗎?
可以看看jQuery源碼。
在jQuery源碼中,“jQuery”或者“$”,這個變量其實是一個函數,不信可以用 typeof 驗證一下。
console.log(typeof $); // function console.log($.trim(" ABC "));
驗明正身!的確是個函數。而經常使用的 $.trim() 也是個函數。
很明顯,這就是在 $ 或者 jQuery 函數上加了一個 trim 屬性,屬性值是函數,作用是截取前后空格。要習慣的把js中的一切看作對象,只要是對象,就是屬性的集合,屬性是鍵值對的形式。
參考資料理解JavaScript原型
深入理解javascript原型和閉包(1)——一切都是對象
JavaScript探秘:強大的原型和原型鏈
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/85716.html
摘要:用構造器模擬類的兩種方法在構造器中修改,給添加屬性修改構造器的屬性指向的對象,它是從這個構造器構造出來的所有對象的原型。 筆記說明 重學前端是程劭非(winter)【前手機淘寶前端負責人】在極客時間開的一個專欄,每天10分鐘,重構你的前端知識體系,筆者主要整理學習過程的一些要點筆記以及感悟,完整的可以加入winter的專欄學習【原文有winter的語音】,如有侵權請聯系我,郵箱:kai...
摘要:用構造器模擬類的兩種方法在構造器中修改,給添加屬性修改構造器的屬性指向的對象,它是從這個構造器構造出來的所有對象的原型。 筆記說明 重學前端是程劭非(winter)【前手機淘寶前端負責人】在極客時間開的一個專欄,每天10分鐘,重構你的前端知識體系,筆者主要整理學習過程的一些要點筆記以及感悟,完整的可以加入winter的專欄學習【原文有winter的語音】,如有侵權請聯系我,郵箱:kai...
摘要:用構造器模擬類的兩種方法在構造器中修改,給添加屬性修改構造器的屬性指向的對象,它是從這個構造器構造出來的所有對象的原型。 筆記說明 重學前端是程劭非(winter)【前手機淘寶前端負責人】在極客時間開的一個專欄,每天10分鐘,重構你的前端知識體系,筆者主要整理學習過程的一些要點筆記以及感悟,完整的可以加入winter的專欄學習【原文有winter的語音】,如有侵權請聯系我,郵箱:kai...
摘要:例例通過原型鏈來檢測對象所調用的方法是否存在,存在在哪個原型對象上除了在對象對象中存在外,其他方法都是通過原型鏈的方法在上找到并調用。 前言 學習了解JavaScript對象的繼承機制 JavaScript Object 概念 Object是js的基本數據結構的一種,屬于引用類型。 對象的創建方法 對象字面量寫法 構造函數,通過構造函數來創建對象實例 Object()構造函數 cre...
摘要:繼承原型鏈如果構造函數或對象的原型指向構造函數或對象,的原型再指向構造函數或對象,以此類推,最終的構造函數或對象的原型指向的原型。 繼承 原型鏈 如果構造函數或對象A的原型指向構造函數或對象B,B的原型再指向構造函數或對象C,以此類推,最終的構造函數或對象的原型指向Object的原型。由此形成了一條鏈狀結構,被稱之為原型鏈。按照上述的描述,在B中定義的屬性或方法,可以在A中使用并不需要...
閱讀 871·2021-10-25 09:45
閱讀 3293·2021-09-22 14:58
閱讀 3854·2021-08-31 09:43
閱讀 918·2019-08-30 15:55
閱讀 921·2019-08-29 13:51
閱讀 1231·2019-08-29 13:02
閱讀 3488·2019-08-29 12:52
閱讀 1963·2019-08-26 13:27