国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

白話原型和原型鏈

lijy91 / 1732人閱讀

摘要:二原型和原型鏈其實,原型這個名字本身就很容易產生誤解,原型在百度詞條中的釋義是指原來的類型或模型。對象的原型是通過創建的對象,其原型是而的原型是,從而兩個原型對象和有了繼承關系三和這是容易混淆的兩個屬性。

關于原型和原型鏈的介紹,網上數不勝數,但能講清楚這兩個概念的很少,大多數都是介紹各種對象、屬性之間如何指來指去,最后的結果就是箭頭滿天飛,大腦一團糟。本文將從這兩個概念的命名入手,用通俗易懂的語言,幫助你理解這兩個東西到底是何方神圣。

一. 背景知識

JavaScript和Java、C++等傳統面向對象的編程語言不同,它是沒有類(class)的概念的(ES6 中的class也只不過是語法糖,并非真正意義上的類),而在JavaScript中,一切皆是對象(object)。在基于類的傳統面向對象的編程語言中,對象由類實例化而來,實例化的過程中,類的屬性和方法會拷貝到這個對象中;對象的繼承實際上是類的繼承,在定義子類繼承于父類時,子類會將父類的屬性和方法拷貝到自身當中。因此,這類語言中,對象創建和繼承行為都是通過拷貝完成的。但在JavaScript中,對象的創建、對象的繼承(更好的叫法是對象的代理,因為它并不是傳統意義上的繼承)是不存在拷貝行為的。現在讓我們忘掉類、忘掉繼承,這一切都不屬于JavaScript。

二. 原型和原型鏈

其實,原型這個名字本身就很容易產生誤解,原型在百度詞條中的釋義是:指原來的類型或模型。按照這個定義解釋的話,對象的原型是對象創建自身的模子,模子具備的特點對象都要具有,這儼然就是拷貝的概念。我們已經說過, JavaScript的對象創建不存在拷貝,對象的原型實際上也是一個對象,它和對象本身是完全獨立的兩個對象。既然如此,原型存在的意義又是什么呢?原型是為了共享多個對象之間的一些共有特性(屬性或方法),這個功能也是任何一門面向對象的編程語言必須具備的。A、B兩個對象的原型相同,那么它們必然有一些相同的特征。

JavaScript中的對象,都有一個內置屬性[[Prototype]],指向這個對象的原型對象。當查找一個屬性或方法時,如果在當前對象中找不到定義,會繼續在當前對象的原型對象中查找;如果原型對象中依然沒有找到,會繼續在原型對象的原型中查找(原型也是對象,也有它自己的原型);如此繼續,直到找到為止,或者查找到最頂層的原型對象中也沒有找到,就結束查找,返回undefined。可以看出,這個查找過程是一個鏈式的查找,每個對象都有一個到它自身原型對象的鏈接,這些鏈接組成的整個鏈條就是原型鏈。擁有相同原型的多個對象,他們的共同特征正是通過這種查找模式體現出來的。

在上面的查找過程,我們提到了最頂層的原型對象,這個對象就是Object.prototype,這個對象中保存了最常用的方法,如toStringvalueOfhasOwnProperty等,因此我們才能在任何對象中使用這些方法。

1.字面量方式

當通過字面量方式創建對象時,它的原型就是Object.prototype。雖然我們無法直接訪問內置屬性[[Prototype]],但我們可以通過Object.getPrototypeOf()或對象的__proto__獲取對象的原型。

var obj = {};
Object.getPrototypeOf(obj) === Object.prototype;   // true
obj.__proto__  === Object.prototype;            // true
2.函數的構造調用

通過函數的構造調用(注意,我們不把它叫做構造函數,因為JavaScript中同樣沒有構造函數的概念,所有的函數都是平等的,只不過用來創建對象時,函數的調用方式不同而已)也是一種常用的創建對象的方式。基于同一個函數創建出來的對象,理應可以共享一些相同的屬性或方法,但這些屬性或方法如果放在Object.prototype里,那么所有的對象都可以使用它們了,作用域太大,顯然不合適。于是,JavaScript在定義一個函數時,同時為這個函數定義了一個 默認的prototype屬性,所有共享的屬性或方法,都放到這個屬性所指向的對象中。由此看出,通過一個函數的構造調用創建的對象,它的原型就是這個函數的prototype指向的對象。

var f = function(name) { this.name = name };
f.prototype.getName = function() { return this.name; }   //在prototype下存放所有對象的共享方法
var obj = new f("JavaScript");
obj.getName();                  // JavaScript
obj.__proto__ === f.prototype;  // true
3.Object.create()

第三種常用的創建對象的方式是使用Object.create()。這個方法會以你傳入的對象作為創建出來的對象的原型。

var obj = {};
var obj2 = Object.create(obj);
obj2.__proto__ === obj;       // true

這種方式還可以模擬對象的“繼承”行為。

function Foo(name) {
    this.name = name;
}

Foo.prototype.myName = function() {
    return this.name;
};

function Bar(name,label) {
    Foo.call( this, name );   //
    this.label = label;
}

// temp對象的原型是Foo.prototype
var temp = Object.create( Foo.prototype );  

// 通過new Bar() 創建的對象,其原型是temp, 而temp的原型是Foo.prototype,
// 從而兩個原型對象Bar.prototype和Foo.prototype 有了"繼承"關系
Bar.prototype = temp;

Bar.prototype.myLabel = function() {
    return this.label;
};

var a = new Bar( "a", "obj a" );

a.myName(); // "a"
a.myLabel(); // "obj a"
a.__proto__.__proto__ === Foo.prototype;  //true
三. __proto__和prototype

這是容易混淆的兩個屬性。__proto__指向當前對象的原型,prototype是函數才具有的屬性,默認情況下,new 一個函數創建出的對象,其原型都指向這個函數的prototype屬性。

四. 三種特殊情況

1.對于JavaScript中的內置對象,如String、Number、Array、Object、Function等,因為他們是native代碼實現的,他們的原型打印出來都是? () { [native code] }

2.內置對象本質上也是函數,所以可以通過他們創建對象,創建出的對象的原型指向對應內置對象的prototype屬性,最頂層的原型對象依然指向Object.prototype。

"abc".__proto__ === String.prototype;   // true 
new String("abc").__proto__ === String.prototype;  //true

new Number(1).__proto__  ==== Number.prototype;   // true

[1,2,3].__proto__ === Array.prototype;            // true
new Array(1,2,3).__proto__ === Array.prototype;   // true

({}).__proto__ === Object.prototype;               //true
new Object({}).__proto__ === Object.prototype;     // true

var f = function() {};
f.__proto__ === Function.prototype;            // true
var f = new Function("{}");
f.__proto__ === Function.prototype;            // true

3.Object.create(null) 創建出的對象,不存在原型。

var a = Object.create(null); 
a.__proto__;               // undefined

此外,函數的prototype中還有一個constructor方法,建議大家就當它不存在,它的存在讓JavaScript原型的概念變得更加混亂,而且這個方法也幾乎沒有作用。

歡迎關注我的公眾號:老干部的大前端,領取21本大前端精選書籍!

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/84831.html

相關文章

  • 白話解釋 Javascript 原型繼承(prototype inheritance)

    摘要:我們有了構造函數之后,第二步開始使用它構造一個函數。來個例子這種方式很簡單也很直接,你在構造函數的原型上定義方法,那么用該構造函數實例化出來的對象都可以通過原型繼承鏈訪問到定義在構造函數原型上的方法。 來源: 個人博客 白話解釋 Javascript 原型繼承(prototype inheritance) 什么是繼承? 學過面向對象的同學們是否還記得,老師整天掛在嘴邊的面向對象三大特...

    kid143 評論0 收藏0
  • 深入理解JavaScript

    摘要:深入之繼承的多種方式和優缺點深入系列第十五篇,講解各種繼承方式和優缺點。對于解釋型語言例如來說,通過詞法分析語法分析語法樹,就可以開始解釋執行了。 JavaScript深入之繼承的多種方式和優缺點 JavaScript深入系列第十五篇,講解JavaScript各種繼承方式和優缺點。 寫在前面 本文講解JavaScript各種繼承方式和優缺點。 但是注意: 這篇文章更像是筆記,哎,再讓我...

    myeveryheart 評論0 收藏0
  • 一篇文章帶你理解原型原型

    摘要:上面的代碼,運行以后,我們可以看到因為的原型是指向的實例上的,所以可以訪問他的屬性值,那如果我不想讓訪問的構造函數里聲明的屬性值,那怎么辦呢只需要將指向的原型而不是實例就行了。 走在前端的大道上 本篇將自己讀過的相關 javascript原型和原型鏈 文章中,對自己有啟發的章節片段總結在這(會對原文進行刪改),會不斷豐富提煉總結更新。 文章——深入理解javascript之原型 一般的...

    yintaolaowanzi 評論0 收藏0
  • JS筆記

    摘要:從最開始的到封裝后的都在試圖解決異步編程過程中的問題。為了讓編程更美好,我們就需要引入來降低異步編程的復雜性。異步編程入門的全稱是前端經典面試題從輸入到頁面加載發生了什么這是一篇開發的科普類文章,涉及到優化等多個方面。 TypeScript 入門教程 從 JavaScript 程序員的角度總結思考,循序漸進的理解 TypeScript。 網絡基礎知識之 HTTP 協議 詳細介紹 HTT...

    rottengeek 評論0 收藏0
  • 我來重新學習 javascript 的面向對象(part 2)

    摘要:先來說其實構造函數也有,原型對象有,實例有也有,或者更加籠統的說,所有對象都是有的。構造函數的原型對象上的會指向構造函數。由于屬性是可以變更的,所以未必真的指向對象的構造函數,只是一個提示。 續上一集內容,通過構造函數的方式,成功地更新了生產技術,老板笑呵呵,工人少奔波,只是問題總比辦法多,又遇到一個新問題,就是會造成一些資源的重復和浪費,那么經過工程師們的智慧交流,他們產生了一個新技...

    silvertheo 評論0 收藏0

發表評論

0條評論

lijy91

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<