摘要:每個原型對象都有一個屬性指向關聯的構造函數為了驗證這一說話,舉個例子。
本文共 1475 字,讀完只需 6 分鐘一、概述
在 JavaScript 中,是一種面向對象的程序設計語言,但是 JS 本身是沒有 “類” 的概念,JS 是靠原型和原型鏈實現對象屬性的繼承。
在理解原型前,需要先知道對象的構造函數是什么,構造函數都有什么特點?
1. 構造函數
// 構造函數 Person() function Person(name, gender) { this.name = name; this.gender = gender; } var person = new Person("周杰倫", "男"); // 最后創建出來的對象實例 person person { name: "周杰倫", gender: "男" }
以上代碼,普通函數 Person(),加上 new 關鍵字后,就構造了一個對象 person
所以構造函數的定義就是普通函數加上 new 關鍵字,并總會返回一個對象。
2. 函數對象
同時,JS 中的對象分為一般對象和函數對象。那什么是一般對象,什么又是函數對象呢?
JavaScript 的類型分為基本數據類型和引用數據類型,基本數據類型目前有 6 種(null, undefined, string, number, boolean, Symbol)。 其余的數據類型都統稱為 object 數據類型,其中,包括 Array, Date, Function等,所以函數可以稱為函數對象。
let foo = function(){ } foo.name = "bar"; foo.age = 24; console.log(foo instanceof Function) //true console.log(foo.age) // 24
以上代碼就說明了函數其實是一個對象,也可以具有屬性。
二、原型鏈JavaScript 中的對象,有一個特殊的 [[prototype]] 屬性, 其實就是對于其他對象的引用(委托)。當我們在獲取一個對象的屬性時,如果這個對象上沒有這個屬性,那么 JS 會沿著對象的 [[prototype]]鏈 一層一層地去找,最后如果沒找到就返回 undefined;
這條一層一層的查找屬性的方式,就叫做原型鏈。
var o1 = { age: 6 }
那么,為什么一個對象要引用,或者說要委托另外一個對象來尋找屬性呢?
本文開篇的第一句話,就指出來的,JavaScript 中,和一般的 OOP 語言不同,它沒有 "類"的概念,也就沒有 "模板" 來創建對象,而是通過字面量或者構造函數的方式直接創建對象。那么也就不存在所謂的類的復制繼承。
三、原型那什么又是原型呢?
既然我們沒有類,就用其他的方式實現類的行為吧,看下面這句話↓↓。
1. 每個函數都有一個原型屬性 prototype 對象
function Person() { } Person.prototype.name = "JayChou"; // person1 和 person2 都是空對象 var person1 = new Person(); var person2 = new Person(); console.log(person1.name) // JayChou console.log(person2.name) // JayChou
通過構造函數創造的對象,對象在尋找 name 屬性時,找到了 構造函數的 prototype 對象上。
這個構造函數的 prototype 對象,就是 原型
用示意圖來表示:
查找對象實例屬性時,會沿著原型鏈向上找,在現代瀏覽器中,標準讓每個對象都有一個 __proto__ 屬性,指向原型對象。那么,我們可以知道對象實例和函數原型對象之間的關系。
2. 每個原型對象都有一個 constructor 屬性指向關聯的構造函數
為了驗證這一說話,舉個例子。
function Person() {} Person === Person.prototype.constructor; // true
那么對象實例是構造函數構造而來,那么對象實例是不是也應該有一個 constructor 呢?
function Person() {} const person = new Person(); person.constructor === Person // true
但事實上,對象實例本身并沒有 constructor 屬性,對象實例的 constructor 屬性來自于引用了原型對象的 constructor 屬性
person.constructor === Person.prototype.constructor // true
3. 原型鏈頂層:Object.prototype.__proto__ == null
既然 JS 通過原型鏈查找屬性,那么鏈的頂層是什么呢,答案就是 Object 對象,Object 對象其實也有 __proto__屬性,比較特殊的是 Object.prototype.__proto__ 指向 null, 也就是空。
Object.prototype.__proto__ === null
我們回過頭來看函數對象:
所有函數對象的proto都指向Function.prototype,它是一個空函數(Empty function)
Number.__proto__ === Function.prototype // true Number.constructor == Function //true Boolean.__proto__ === Function.prototype // true Boolean.constructor == Function //true String.__proto__ === Function.prototype // true String.constructor == Function //true // 所有的構造器都來自于Function.prototype,甚至包括根構造器Object及Function自身 Object.__proto__ === Function.prototype // true Object.constructor == Function // true // 所有的構造器都來自于Function.prototype,甚至包括根構造器Object及Function自身 Function.__proto__ === Function.prototype // true Function.constructor == Function //true Array.__proto__ === Function.prototype // true Array.constructor == Function //true RegExp.__proto__ === Function.prototype // true RegExp.constructor == Function //true Error.__proto__ === Function.prototype // true Error.constructor == Function //true Date.__proto__ === Function.prototype // true Date.constructor == Function //true
所有的構造器都來自于 Function.prototype,甚至包括根構造器Object及Function自身。所有構造器都繼承了·Function.prototype·的屬性及方法。如length、call、apply、bind
以圖會友,這就是網上經常看到的 JS 原型和原型鏈關系圖:
對于以上看似很復雜的關系圖,只需要理解 5 點:
每個函數都有一個原型屬性 prototype 對象
普通對象的構造函數是 Object(),所以 Person.prototype.__proto__ === Object.prototype
函數對象都來自于 Function.prototype
函數對象也是對象,所有 Function.prototype.__proto__ === Object.prototype
記住,所有函數的默認原型都是 Object() 的實例,所以,Function.prototype.__proto__ === Object.prototype
Object.prototype.__proto__ 是 null
總結以上就是 JavaScript 中原型和原型鏈的知識。由于 JS 沒有"類", 所以采用了原型的方式實現繼承,正確的說法是引用或者委托,因為對象之間的關系不是復制,而是委托。在查找屬性的時候,引用(委托)原型對象的屬性,也就是我們常說的原型繼承。
歡迎關注個人微信訂閱號,專注分享原創文章
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/98441.html
摘要:不理解沒關系,下面會結合圖例分析上一篇高級程序設計筆記創建對象下一篇高級程序設計筆記繼承參考之原型鏈的解讀三張圖搞懂的原型對象與原型鏈繼承與原型鏈 文章直接從原型圖解開始的,如果對一些概念不太清除,可以結合后面幾節查看 1. 圖解原型鏈 1.1 鐵三角關系(重點) function Person() {}; var p = new Person(); showImg(https://s...
摘要:前言作為前端高頻面試題之一,相信很多小伙伴都有遇到過這個問題。 前言 作為前端高頻面試題之一,相信很多小伙伴都有遇到過這個問題。那么你是否清楚完整的了解它呢? 國際慣例,讓我們先拋出問題: 什么是原型、原型鏈 它們有什么特點 它們能做什么 怎么確定它們的關系 或許你已經有答案,或許你開始有點疑惑,無論是 get 新技能或是簡單的溫習一次,讓我們一起去探究一番吧 如果文章中有出現紕...
摘要:每一個由構造函數創建的對象都會默認的連接到該神秘對象上。在構造方法中也具有類似的功能,因此也稱其為類實例與對象實例一般是指某一個構造函數創建出來的對象,我們稱為構造函數的實例實例就是對象。表示該原型是與什么構造函數聯系起來的。 本文您將看到以下內容: 傳統構造函數的問題 一些相關概念 認識原型 構造、原型、實例三角結構圖 對象的原型鏈 函數的構造函數Function 一句話說明什么...
摘要:綜上所述有原型鏈繼承,構造函數繼承經典繼承,組合繼承,寄生繼承,寄生組合繼承五種方法,寄生組合式繼承,集寄生式繼承和組合繼承的優點于一身是實現基于類型繼承的最有效方法。 一、前言 繼承是面向對象(OOP)語言中的一個最為人津津樂道的概念。許多面對對象(OOP)語言都支持兩種繼承方式::接口繼承 和 實現繼承 。 接口繼承只繼承方法簽名,而實現繼承則繼承實際的方法。由于js中方法沒有簽名...
摘要:探索是如何判斷的表達式如果函數的顯式原型對象在對象的隱式原型鏈上,返回,否則返回是通過自己產生的實例案例案例重要注意的顯示原型和隱式原型是一樣的。面試題測試題測試題報錯對照下圖理解 原型與原型鏈深入理解(圖解) 原型(prototype) 函數的 prototype 屬性(圖) 每個函數都有一個prototype屬性,它默認指向一個Object空對象(即稱為:原型對象) 原型對象中有...
閱讀 3407·2021-11-25 09:43
閱讀 2294·2021-09-06 15:02
閱讀 3538·2021-08-18 10:21
閱讀 3340·2019-08-30 15:55
閱讀 2343·2019-08-29 17:06
閱讀 3534·2019-08-29 16:59
閱讀 962·2019-08-29 13:47
閱讀 2756·2019-08-26 13:24