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