摘要:而原型對(duì)象都會(huì)獲得一個(gè)構(gòu)造函數(shù)屬性,這是一個(gè)指向?qū)傩运诤瘮?shù)的指針。所以組合使用構(gòu)造函數(shù)模式和原型模式簡單來說就是構(gòu)造函數(shù)里面定義實(shí)例屬性,原型模式定義共享屬性。
一、創(chuàng)建對(duì)象
創(chuàng)建對(duì)象的發(fā)展史:
最早
var person = new Object() person.name = "Green"
對(duì)象字面量
var person = { name = "Green", age = "25", sayName: function(){ alert("this.name") } }
以上兩種都會(huì)有大量重復(fù)性的代碼,于是乎:
工廠模式
function createPerson(name, age, job){ var o = new Object(); // 這個(gè)叫做顯式的創(chuàng)造對(duì)象 o.name = name; o.age = age; o.job = job; o.sayName = function(){ alert("this.name") }; return o; } var example = createPerson("Green",25,"無業(yè)!");
雖然解決了重復(fù)代碼問題,但沒有解決對(duì)象識(shí)別(工廠模式無從識(shí)別對(duì)象的類型,因?yàn)槿慷际荗bject,不像Date、Array等,本例中,得到的都是o對(duì)象,對(duì)象的類型都是Object,因此出現(xiàn)了構(gòu)造函數(shù)模式)
構(gòu)造函數(shù)模式
function Person(name,age,family) { this.name = name; this.age = age; this.family = family; this.say = function(){ alert(this.name); } } var person1 = new Person("lisi",21,["lida","lier","wangwu"]); var person2 = new Person("lisi",21,["lida","lier","lisi"]); /* 這是在創(chuàng)建Person的實(shí)例,必須用到new - 創(chuàng)建一個(gè)新對(duì)象 - 將構(gòu)造函數(shù)的作用域賦過去(this指向新對(duì)象) - 執(zhí)行構(gòu)造函數(shù)的代碼 - 返回新對(duì)象 */ console.log(person1 instanceof Object); //true console.log(person1 instanceof Person); //true
算是構(gòu)造函數(shù)的特點(diǎn)?
。沒有顯式的創(chuàng)建對(duì)象(拗口)
。將屬性方法賦給了this對(duì)象
。沒有return
instanceof: 識(shí)別對(duì)象類型
在全局作用域中調(diào)用一個(gè)函數(shù)時(shí),this永遠(yuǎn)指向window (踩坑了~)
構(gòu)造函數(shù)模式內(nèi)的方法每次都會(huì)在實(shí)例上重建一遍,里面的方法在做同一件事,但是實(shí)例化后卻產(chǎn)生了不同的對(duì)象,方法是函數(shù) ,函數(shù)也是對(duì)象。但如果相同的方法都寫在全局作用域里,會(huì)產(chǎn)生很多全局函數(shù),失去了這個(gè)引用類型的封裝性。所以就產(chǎn)生了:
原型模式
function Person() { } Person.prototype.name = "lisi"; Person.prototype.age = 21; Person.prototype.family = ["lida","lier","wangwu"]; Person.prototype.say = function(){ alert(this.name); }; console.log(Person.prototype); //Object{name: "lisi", age: 21, family: Array[3]} var person1 = new Person(); //創(chuàng)建一個(gè)實(shí)例person1 console.log(person1.name); //lisi var person2 = new Person(); //創(chuàng)建實(shí)例person2 person2.name = "wangwu"; person2.family = ["lida","lier","lisi"]; console.log(person2); //Person {name: "wangwu", family: Array[3]} // console.log(person2.prototype.name); //報(bào)錯(cuò) console.log(person2.age); //21
~ 每個(gè)函數(shù)有一個(gè)prototype屬性,指向一個(gè)對(duì)象(該函數(shù)的原型對(duì)象),用途是包含了一些屬性和方法等信息,可以被一些由調(diào)用該函數(shù)創(chuàng)建的實(shí)例所共享。這些信息不必定義在構(gòu)造函數(shù)內(nèi),只要添加到原型對(duì)象上即可。
~ 而原型對(duì)象都會(huì)獲得一個(gè)constructor(構(gòu)造函數(shù))屬性,這是一個(gè)指向prototype屬性所在函數(shù)的指針。(prototype和constructor屬性在函數(shù)與原型之間互相指)
~ 而創(chuàng)建出的實(shí)例內(nèi)部,又有一個(gè)指針,指向原型對(duì)象(和構(gòu)造函數(shù)里的prototype指的一樣,其實(shí)實(shí)例與構(gòu)造函數(shù)無關(guān),與他的原型有關(guān)),是你嗎__proto__?
檢測屬性
使用 hasOwnProperty() 方法可以檢測一個(gè)屬性是存在于實(shí)例還是他的原型中。給定屬性存在于實(shí)例中會(huì)返回true。
in操作符:多帶帶使用時(shí),無論屬性存在于哪里,只要有就是true
for-in循環(huán)使用時(shí),返回所有能夠通過對(duì)象訪問的可枚舉屬性,實(shí)例和原型的都包括。入所需要取得對(duì)象上所有可枚舉的實(shí)例屬性,推薦Object.key()方法?!旧羁截愑眠^】
原型模式的優(yōu)點(diǎn)是共享,缺點(diǎn)也是共享(過度)。比如兩個(gè)實(shí)例由調(diào)用同一個(gè)構(gòu)造函數(shù)得來,其中一個(gè)實(shí)例修改了原型對(duì)象上屬性值 ,另一個(gè)實(shí)例也會(huì)共享這個(gè)修改。所以:
組合使用構(gòu)造函數(shù)模式和原型模式
簡單來說就是構(gòu)造函數(shù)里面定義實(shí)例屬性,原型模式定義共享屬性。
原型鏈簡單描述,就是將一個(gè)構(gòu)造函數(shù)的實(shí)例賦值給另一個(gè)構(gòu)造函數(shù)的原型對(duì)象。層層套在一起成為一個(gè)鏈條。是實(shí)現(xiàn)繼承的方法。
原型鏈的繼承仍然存在共享過度的問題,除此之外子類型實(shí)例不能給超類型傳遞參數(shù)。于是我們就要用到:
借用構(gòu)造函數(shù)
基本思想: 在子類型構(gòu)造函數(shù)內(nèi)部調(diào)用超類型構(gòu)造函數(shù)(通過call apply方法)
但是這樣方法又必須全定義在構(gòu)造函數(shù)里,又不能復(fù)用了。于是就又有了:
組合繼承
基本思想:使用原型鏈實(shí)現(xiàn)對(duì)原型屬性和方法的繼承,通過借用構(gòu)造函數(shù)來實(shí)現(xiàn)對(duì)實(shí)例屬性的繼承。這樣既通過在原型上定義方法實(shí)現(xiàn)了函數(shù)的復(fù)用,又能夠保證每個(gè)函數(shù)都有自己的屬性。
function SuperType(name) { this.name = name this.color = ["red", "blue"] } SuperType.prototype.getName = function() { console.log(this.name) } function SubType(name, age) { SuperType.call(this, name) // 繼承屬性 this.age = age } SubType.prototype.getAge = function() { console.log(this.age) } SubType.prototype = new SuperType() // 繼承方法 SubType.prototype.constructor = SubType var instance1 = new SubType("zhangsan", 18) instance1.colors.push("black") console.log(instance1.colors) // "red", "blue", "black" console.log(instance1.getName) // "zhangsan" console.log(instance1.getAge) // 18 var instance2 = new SubType("lisi", 20) console.log(instance2.colors) // "red", "blue" console.log(instance2.getName) // "lisi" console.log(instance2.getAge) // 20屬性類型 1、數(shù)據(jù)屬性
有四個(gè)描述特性:
configurable 能否刪除屬性 (*置為false后就無法再改變)
enumerable 能否通過for-in循環(huán)返回屬性
writable 能否修改屬性值
value 從這里讀取或者寫入屬性值
前三項(xiàng)默認(rèn)值都為true,如果需要修改,需要調(diào)用大名鼎鼎的Object.defineProperty()方法
var person = {} Object.defineProperty(person,"name",{ // 三個(gè)參數(shù) writable: false, // 這里如果不指定都默認(rèn)為false value: "Green" }) alert(person.name); // Green person.name = "Blue" alert(person.name); // Green2、訪問器屬性
包含一對(duì)getter(讀取訪問器屬性時(shí)調(diào)用)和setter(寫入訪問器屬性時(shí)調(diào)用)函數(shù)
有四個(gè)描述特性:
configurable 一樣
enumerable 一樣
get 讀取屬性時(shí)調(diào)用的函數(shù)
set 寫入屬性時(shí)調(diào)用的函數(shù)
仍需調(diào)用Object.defineProperty()方法來定義
var book = { _year :2004, edition: 1 } Object.defineProperty(book,"year",{ get: function(){ return this._year; } set: function(newValue){ if(newValue > 2004){ this._year = newValue; this.edition += newValue - 2004; } } }) book.year = 2005 alert(book.edition); // 2
這是使用訪問器屬性的常見方式,即設(shè)置一個(gè)屬性的值會(huì)導(dǎo)致其他屬性發(fā)生變化。
*_year的下劃線表示只能通過對(duì)象方法訪問(不懂,等我再查查)
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/103763.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)。 但是注意: 這篇文章更像是筆記,哎,再讓我...
摘要:是完全的面向?qū)ο笳Z言,它們通過類的形式組織函數(shù)和變量,使之不能脫離對(duì)象存在。而在基于原型的面向?qū)ο蠓绞街?,?duì)象則是依靠構(gòu)造器利用原型構(gòu)造出來的。 JavaScript 函數(shù)式腳本語言特性以及其看似隨意的編寫風(fēng)格,導(dǎo)致長期以來人們對(duì)這一門語言的誤解,即認(rèn)為 JavaScript 不是一門面向?qū)ο蟮恼Z言,或者只是部分具備一些面向?qū)ο蟮奶卣?。本文將回歸面向?qū)ο蟊疽?,從?duì)語言感悟的角度闡述為什...
摘要:通常有這兩種繼承方式接口繼承和實(shí)現(xiàn)繼承。理解繼承的工作是通過調(diào)用函數(shù)實(shí)現(xiàn)的,所以是寄生,將繼承工作寄托給別人做,自己只是做增強(qiáng)工作。適用基于某個(gè)對(duì)象或某些信息來創(chuàng)建對(duì)象,而不考慮自定義類型和構(gòu)造函數(shù)。 一、繼承的概念 繼承,是面向?qū)ο笳Z言的一個(gè)重要概念。通常有這兩種繼承方式:接口繼承和實(shí)現(xiàn)繼承。接口繼承只繼承方法簽名,而實(shí)現(xiàn)繼承則繼承實(shí)際的方法。 《JS高程》里提到:由于函數(shù)沒有簽名,...
摘要:一基礎(chǔ)接口的意義百度規(guī)范擴(kuò)展回調(diào)抽象類的意義我的前端面試經(jīng)歷百度前端掘金博主就讀于電子科技大學(xué),大三狗一枚面試是個(gè)漫長的過程,從海投到收獲電話面試,一面二面三面,一個(gè)步驟出錯(cuò)那么后面就宣告終結(jié)。 一道常被人輕視的前端 JS 面試題 - 前端 - 掘金 目錄前言第一問第二問變量聲明提升函數(shù)表達(dá)式第三問第四問第五問第六問構(gòu)造函數(shù)的返回值第七問最后前言 年前剛剛離職了,分享下我曾經(jīng)出過的一道...
摘要:創(chuàng)建構(gòu)造函數(shù)后,其原型對(duì)象默認(rèn)只會(huì)取得屬性至于其他的方法都是從繼承來的。上圖展示了構(gòu)造函數(shù)的原型對(duì)象和現(xiàn)有的兩個(gè)實(shí)例之間的關(guān)系。所有原生的引用類型都在其構(gòu)造函數(shù)的原型上定義了方法。 第6章我一共寫了3篇總結(jié),下面是相關(guān)鏈接:讀《javaScript高級(jí)程序設(shè)計(jì)-第6章》之理解對(duì)象讀《javaScript高級(jí)程序設(shè)計(jì)-第6章》之繼承 工廠模式 所謂的工廠模式就是,把創(chuàng)建具體對(duì)象的過程抽象...
閱讀 4355·2021-09-26 10:11
閱讀 2729·2021-07-28 00:37
閱讀 3277·2019-08-29 15:29
閱讀 1255·2019-08-29 15:23
閱讀 3190·2019-08-26 18:37
閱讀 2542·2019-08-26 10:37
閱讀 649·2019-08-23 17:04
閱讀 2402·2019-08-23 13:44