摘要:深入理解原型與繼承看過不少書籍,不少文章,對(duì)于原型與繼承的說明基本上讓人不明覺厲,特別是對(duì)于習(xí)慣了面向?qū)ο缶幊痰娜藖碚f更難理解,這里我就給大家說說我的理解。
深入理解:JavaScript原型與繼承
看過不少書籍,不少文章,對(duì)于原型與繼承的說明基本上讓人不明覺厲,特別是對(duì)于習(xí)慣了面向?qū)ο缶幊痰娜藖碚f更難理解,這里我就給大家說說我的理解。
首先JavaScript是一門基于原型編程的語言,它遵守原型編程的基本原則:
所有的數(shù)據(jù)都是對(duì)象(javascript中除了字符串字面量、數(shù)字字面量、true、false、null、undefined之外,其他值都是對(duì)象!)
要得到一個(gè)對(duì)象,不是通過實(shí)例化類,而是找到一個(gè)對(duì)象作為原型并克隆它(new操作符)
對(duì)象會(huì)記住它的原型(JavaScript中通過隱藏的__proto__屬性)
如果對(duì)象無法響應(yīng)某個(gè)請(qǐng)求,它會(huì)把該請(qǐng)求委托給它自己的原型
這么說來,JavaScript一定有一個(gè)根對(duì)象,所有的對(duì)象的最終原型都將是它,它就是Object.prototype(有的人說跟對(duì)象是null,因?yàn)?b>Object.prototype.__proto__為null),Object.prototype也是一個(gè)對(duì)象,它是一個(gè)空的對(duì)象。(記住一點(diǎn):所有的原型都是對(duì)象,但不是函數(shù),雖然函數(shù)也是對(duì)象,Object其實(shí)就是一個(gè)函數(shù),而Object.prototype是一個(gè)對(duì)象)
以下代碼創(chuàng)建空對(duì)象:
var obj1 = new Object(); var obj2 = {}; Object.getPrototypeOf(obj1) === Object.prototype; //true Object.getPrototypeOf(obj2) === Object.prototype; //true
我們?cè)賮砜聪乱韵麓a:
function Book(name){ this.name = name; } Book.prototype.getName = function(){ return this.name; } Book.num = 5; var book1 = new Book("javascript"); book1.getName(); //javascript Object.getPrototypeOf(book1) === Book.prototype; //true
我們通常說,使用了new Book()來創(chuàng)建了Book的實(shí)例book1,但是JavaScript并沒有類的概念,這里的Book本質(zhì)上只是一個(gè)函數(shù)而已,如果用new則把它當(dāng)著構(gòu)造函數(shù)對(duì)待,那么var book1 = new Book("javascript)是怎么個(gè)執(zhí)行過程呢?在這之前,我們來先看下Function與Object的關(guān)系
這里有張圖:來源于javascriptcn
console.log(Function); //Function 函數(shù) console.log(Function.constructor); //Function 函數(shù) console.log(Function.__proto__); //function(){} 空函數(shù) console.log(Function.__proto__.__proto__);//{} 空對(duì)象,即Object.prototype console.log(Function.prototype); //function(){} 空函數(shù) console.log(Function.constructor.prototype); //function(){} 空函數(shù) console.log(Object); //function Object(){[native code]} Object是個(gè)函數(shù) console.log(Object.__proto__); //function(){} 空函數(shù) console.log(Object.prototype); //{} 空對(duì)象 console.log(Object.constructor); //Function 函數(shù) console.log(Object.constructor.prototype); //function(){} 空函數(shù)
以上測(cè)試說明什么?
說明了內(nèi)置函數(shù)Function以它自身為構(gòu)造函數(shù),且以它自身為原型,這個(gè)原型是個(gè)空函數(shù);
Object是個(gè)函數(shù),Object是以內(nèi)置函數(shù)Function為構(gòu)造函數(shù)的,它自己的原型Object.prototype是個(gè)空對(duì)象
我總結(jié)了這么個(gè)東西:在JavaScript中,最原始的東西有兩個(gè),就是function(){}空函數(shù) 和 {}空對(duì)象,但它們都有內(nèi)置的屬性、方法,所有的JS對(duì)象都是基于它們創(chuàng)建出來的;
Function和Object就像是女媧和伏羲,Object提供種子(Object.prototype),F(xiàn)unction負(fù)責(zé)繁衍(Function.prototype)。Object的實(shí)例是由Object.prototype提供的種子經(jīng)過Function.prototype(function(){} 空函數(shù))打造出來的。Object.prototype這個(gè)基因會(huì)被一直繼承下去,并一代一代增強(qiáng)。
每一個(gè)函數(shù)都有一個(gè)原型對(duì)象(prototype)和隱藏的__proto__屬性,函數(shù)的__proto__屬性指向Function.prototype,而原型對(duì)象(prototype)是一個(gè)對(duì)象,符合以下第2點(diǎn)(也有構(gòu)造函數(shù)constructor和隱藏的__proto__屬性);
每一個(gè)對(duì)象都有一個(gè)構(gòu)造函數(shù)(constructor)和隱藏的__proto__屬性,constructor自然指的是它的構(gòu)造函數(shù),而__proto__指向的是它的構(gòu)造函數(shù)的原型對(duì)象prototype,而對(duì)象的原型prototype對(duì)象同時(shí)又包含了該對(duì)象構(gòu)造函數(shù)、還具有自己的__proto__屬性;
通過__proto__屬性,每個(gè)對(duì)象和函數(shù)都會(huì)記住它的原型,這樣就形成了原型鏈;
console.log(Book); //Book函數(shù)自身 console.log(Book.__proto__); //function(){} 空函數(shù) console.log(Book.prototype); //Book的原型對(duì)象,包含了構(gòu)造函數(shù)constructor、__proto__ console.log(Book.prototype.__proto__); //{} 等于Object.prototype console.log(Book.prototype.constructor); //Book函數(shù)自身 console.log(Book.constructor); //Function函數(shù) console.log(Book.constructor.prototype); //function(){} 空函數(shù)(Function函數(shù)的原型) console.log(Book.__proto__.__proto__); //{} 等于Object.prototype
每一個(gè)函數(shù)都是通過Function構(gòu)造出來的,函數(shù)的原型屬性__proto__指向Function.prototype,而函數(shù)的原型對(duì)象prototype是代表著自身的對(duì)象,它的__proto__屬性指向Object.prototype,它的constructor屬性默認(rèn)指向它自己構(gòu)造函數(shù)(也可改為別的函數(shù),如:Book.prototype.constructor = Person;)。
console.log(book1); //Book { name: "javascript" } console.log(book1.__proto__); //指向Book.prototype對(duì)象 console.log(book1.prototype); //undefined console.log(book1.constructor); //指向Book函數(shù) console.log(book1.constructor.prototype); //Book.prototype對(duì)象
所以,我們通常說‘一個(gè)對(duì)象的原型’其實(shí)是不準(zhǔn)確的,應(yīng)該是‘一個(gè)對(duì)象的構(gòu)造器的原型’,且對(duì)象是把它無法響應(yīng)的請(qǐng)求委托給它的構(gòu)造器的原型順著原型鏈往上傳遞的。
現(xiàn)在來講解一下var book1 = new Book("javascript)的執(zhí)行過程,是這樣:new先通過Function.prototype從Object.prototype克隆一個(gè)空對(duì)象,然后將空對(duì)象的構(gòu)造函數(shù)constructor指定為Book,并將該空對(duì)象的__proto__屬性指向它的構(gòu)造函數(shù)的原型Book.prototype,之后通過Book構(gòu)造函數(shù)對(duì)這個(gè)空對(duì)象進(jìn)行賦值操作,最后將這個(gè)對(duì)象返回給變量book1。
我們?cè)倏慈缦麓a:
var obj = {name: "Sufu"}; var Person = function(){}; Person.prototype = obj; var a = new Person(); console.log(a.name); //Sufu
這段是這樣執(zhí)行的:
首先嘗試查找對(duì)象a的name屬性,找不到,執(zhí)行第2步
將查找name屬性的這個(gè)請(qǐng)求委托給a的構(gòu)造器的原型,a.__proto__記錄的是Person.prototype,Person.prototype.__proto__記錄的是obj
在對(duì)象obj中查找name,找到并返回它的值給a,假如還找不到,它就通過obj.__proto__找到Object.prototype,而Object.prototype.__proto__為null,所以找不到就返回undefined。
總之,對(duì)象、函數(shù)都有一個(gè)隱藏的__proto__屬性,這個(gè)屬性就是原型鏈上的環(huán),一環(huán)扣一環(huán),從而形成了原型鏈!
好了,就介紹到這里了,以上是個(gè)人的理解,有不對(duì)的地方歡迎指出!
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/80463.html
摘要:深入之繼承的多種方式和優(yōu)缺點(diǎn)深入系列第十五篇,講解各種繼承方式和優(yōu)缺點(diǎn)。對(duì)于解釋型語言例如來說,通過詞法分析語法分析語法樹,就可以開始解釋執(zhí)行了。 JavaScript深入之繼承的多種方式和優(yōu)缺點(diǎn) JavaScript深入系列第十五篇,講解JavaScript各種繼承方式和優(yōu)缺點(diǎn)。 寫在前面 本文講解JavaScript各種繼承方式和優(yōu)缺點(diǎn)。 但是注意: 這篇文章更像是筆記,哎,再讓我...
摘要:原型鏈與繼承當(dāng)談到繼承時(shí),只有一種結(jié)構(gòu)對(duì)象。如果對(duì)該圖不怎么理解,不要著急,繼續(xù)往下看基于原型鏈的繼承對(duì)象是動(dòng)態(tài)的屬性包指其自己的屬性。當(dāng)使用操作符來作用這個(gè)函數(shù)時(shí),它就可以被稱為構(gòu)造方法構(gòu)造函數(shù)。 原型鏈與繼承 當(dāng)談到繼承時(shí),JavaScript 只有一種結(jié)構(gòu):對(duì)象。每個(gè)實(shí)例對(duì)象(object )都有一個(gè)私有屬性(稱之為proto)指向它的原型對(duì)象(prototype)。該原型對(duì)象也...
摘要:首先,需要來理清一些基礎(chǔ)的計(jì)算機(jī)編程概念編程哲學(xué)與設(shè)計(jì)模式計(jì)算機(jī)編程理念源自于對(duì)現(xiàn)實(shí)抽象的哲學(xué)思考,面向?qū)ο缶幊淌瞧湟环N思維方式,與它并駕齊驅(qū)的是另外兩種思路過程式和函數(shù)式編程。 JavaScript 中的原型機(jī)制一直以來都被眾多開發(fā)者(包括本人)低估甚至忽視了,這是因?yàn)榻^大多數(shù)人沒有想要深刻理解這個(gè)機(jī)制的內(nèi)涵,以及越來越多的開發(fā)者缺乏計(jì)算機(jī)編程相關(guān)的基礎(chǔ)知識(shí)。對(duì)于這樣的開發(fā)者來說 J...
摘要:原文發(fā)自我的博客易企秀招聘啦首先我們先來回顧以下中出現(xiàn)的原型繼承原型繼承自如果我們要在上查詢一個(gè)定義在的屬性會(huì)先在上查找如果沒有查到那么會(huì)順著原型鏈去查找所以以下判別式均為如果我們做如下操作原型鏈并沒有被訪問一個(gè)新的會(huì)被加入到的屬性中去新的 原文發(fā)自我的博客 xiaoyu2er.github.io 易企秀招聘啦! JavaScript Prototypal Inheritance 首先...
摘要:深入系列的第一篇,從原型與原型鏈開始講起,如果你想知道構(gòu)造函數(shù)的實(shí)例的原型,原型的原型,原型的原型的原型是什么,就來看看這篇文章吧。讓我們用一張圖表示構(gòu)造函數(shù)和實(shí)例原型之間的關(guān)系在這張圖中我們用表示實(shí)例原型。 JavaScript深入系列的第一篇,從原型與原型鏈開始講起,如果你想知道構(gòu)造函數(shù)的實(shí)例的原型,原型的原型,原型的原型的原型是什么,就來看看這篇文章吧。 構(gòu)造函數(shù)創(chuàng)建對(duì)象 我們先...
閱讀 1029·2021-11-23 10:11
閱讀 3866·2021-11-16 11:50
閱讀 935·2021-10-14 09:43
閱讀 2720·2021-10-14 09:42
閱讀 2719·2021-09-22 16:02
閱讀 1064·2019-08-29 10:57
閱讀 3385·2019-08-29 10:57
閱讀 2275·2019-08-26 13:52