摘要:我們通過這個構造函數(shù)為原型對象添加其他方法和屬性。這個屬性存在與實例與構造函數(shù)的原型對象上直接,而不存在于實例與構造函數(shù)之間。李小花班花張全蛋張全蛋李小花李小花我們在遍歷對象的的屬性的時候,經常需要判斷屬性是否來自于對象的原型還是屬性。
引言
上面說了創(chuàng)建對象有字面量方式和工廠模式還有構造函數(shù)模式,結果發(fā)現(xiàn)他們都各自有缺點,所以下面再給大家介紹幾種創(chuàng)建對象的方式,爭取能找到一種無痛的模式?。
原型模式下面會有一段非常晦澀難懂的內容,大家跟緊了別翻車。
我們創(chuàng)建的每個函數(shù)都有一個prototype(原型)屬性,這個屬性是一個指針(地址),指向一個對象,這個對象的用途是包含可以由特定類型的所有實例共享的屬性和方法。
function Person () { } Person.prototype.name = "李小花"; Person.prototype.age = "60"; Person.prototype.sayName = function () { console.log(this.name); }; var person1 = new Person(); person1.sayName(); //李小花 var person2 = new Person(); person2.sayName(); //李小花
Person?的prototype 屬性中,構造函數(shù),構造函數(shù)是空函數(shù)。新對象上的屬性和實例是共享的。現(xiàn)在我們需要做一件事,就是理解原型對象。
理解原型對象無論什么時候,只要創(chuàng)建了一個新的函數(shù),就會根據一組特定的規(guī)則為該函數(shù)創(chuàng)建一個prototype屬性,這個屬性指向函數(shù)的原型對象,所有的原型都會獲得一個constructor屬性,指向prototype屬性所在函數(shù)的指針。我們通過這個構造函數(shù)為原型對象添加其他方法和屬性。創(chuàng)建對象后,其原型對象默認只有constructor屬性。當構造函數(shù)創(chuàng)建一個新實例后,該實例的內部將包含一個指針,指向構造函數(shù)的原型。雖然在腳本中沒有標準的方式訪問[[Prototype]],但除IE外都支持一個叫_proto_。這個屬性存在與實例與構造函數(shù)的原型對象上直接,而不存在于實例與構造函數(shù)之間。
大家是不是看暈了?,我下面用一張圖展示一下各個之間的對應關心,看好了,我要展示我高超的畫圖神功了。
靈魂圖片已經展示,相信大家已經看懂了吧。需要注意的是,雖然這兩個實例都不包含屬性和方法 ,但我們可以在實例上調用原型上的方法,這是通過查找對象屬性的過程來實現(xiàn)的。
擴展一下,既然js無法實例的的[[Prototype]],但是可以通過isPrototype()方法來確定這層關系。
console.log(Person.prototype.isPrototypeOf(person1)); // true
在es5中新增了一個方法,叫Object.getPrototype(),這個方法返回[[Prototype]]的值,例如,
console.log(Object.getPrototypeof(person1) == Person.prototype) //true console.log(Object.getPrototypeof(person1).name) //李小花
但是同樣的,IE8以下的瀏覽器都不支持這個屬性。
每當代碼讀取某個對象的某個屬性時,都會執(zhí)行一次搜索,目標是給定名字的屬性,搜索首先從實例本身開始,如果在實例本身找到了這個屬性,則返回該屬性的值,如果沒有找到,則繼續(xù)指針指向的原型對象,如果找到,則返回這個屬性的值。
雖然可以通過對象實例訪問保存在原型中的值,但確不能通過對象重寫原型中的值。如果我們在實例中添加一個屬性,而該屬性與實例原型中的一個屬性同名,這個屬性會屏蔽原型中的那個屬性。
function Person () { } Person.prototype.name = "李小花"; Person.prototype.age = "29"; Person.prototype.job = "班花"; Person.prototype.sayName = function () { console.log(this.name); }; var person1 = new Person(); var person2 = new Person(); person1.name = "張全蛋"; console.log(person1.name); // 張全蛋 console.log(person2.name); // 李小花
當為對象添加一個屬性時,這個屬性會屏蔽原型對象的同名屬性,添加這個屬性只會阻止我們訪問原型的那個屬性,但不會修改那個屬性,使用delete屬性能夠讓我們訪問原型中的屬性。
function Person () { } Person.prototype.name = "李小花"; Person.prototype.name = "29"; Person.prototype.job = "班花"; Person.prototype.sayName = function () { console.log(this.name); }; var person1 = new Person(); var person2 = new Person(); person1.name = "張全蛋"; console.log(person1.name); // 張全蛋 console.log(person2.name); // 李小花 delete person1.name console.log(person1.name); // 李小花
我們在遍歷對象的的屬性的時候,經常需要判斷屬性是否來自于對象的原型還是屬性。
function Person () { } Person.prototype.name = "李小花"; Person.prototype.name = "29"; Person.prototype.job = "班花"; Person.prototype.sayName = function () { console.log(this.name); }; var person1 = new Person(); var person2 = new Person(); console.log(person1.hasOwnProperty("name")); // false person1.name = "張全蛋"; console.log(person1.hasOwnProperty("name")); // true console.log(person1.name); // 張全蛋 console.log(person2.name); // 李小花 delete person1.name console.log(person1.name); // 李小花
我們有一個神器,hasOwnProperty方法,只有當屬性是實例的屬性時,才會返回true。
原型操作符中的in方法我上面介紹了怎么通過hasOwnProperty方法判斷屬性是否來自對象屬性,那怎么判斷屬性來自原型鏈呢?
下面隆重介紹 in操作符,不過屬性來自屬性還是來自原型鏈的屬性,都會返回true,我們通過這個屬性結合hasOwnProperty方法判斷屬性是否來自于原型鏈。
function hasPrototypeproperty(obj, name) { return !object.hasOwnProperty(name) && (name in obj) }
function Person () { } Person.prototype.name = "李小花"; Person.prototype.name = "29"; Person.prototype.job = "班花"; Person.prototype.sayName = function () { console.log(this.name); }; var person1 = new Person(); console.log(hasPrototypeproperty(person, "name")); // true person1.name = "張全蛋"; console.log(hasPrototypeproperty(person, "name")); // false
在使用for-in循環(huán)時,返回的是能夠通過對象訪問的,可枚舉的屬性,包括實例中的屬性,也包含存在于原型中的屬性,屏蔽原型中不可枚舉的屬性也會在for-in中返回。可以通過es5 中的Object.keys方法,返回一個包含所有可枚舉屬性的字符串數(shù)組。
function Person () { } Person.prototype.name = "李小花"; Person.prototype.age = "29"; Person.prototype.job = "班花"; Person.prototype.sayName = function () { console.log(this.name); }; var keys = Object.keys(Person.prototype); console.log(keys); //name age job sayName var p1 = new Person(); p1.name = "全蛋"; p1.age = 20; var p1keys = Object.keys(p1); console.log(p1keys); // name,age
很多時候我們不想那么麻煩的寫,所以會像下面這樣簡便的申明原型模式。
function Person () { } Person.prototype = { name: "李小花", age: 30, job: "班花", sayName: function () { console.log(this.name) } } Object.defineProperty(Person.prototype, "constructor", { enumerable: false, value: Person })
function Person() { } var friend = new Person(); Person.prototype = { constructor: Person, name: "李小花", age: 30, job: "班花", sayName: function () { console.log(this.name) } }; friend.sayName(); //Uncaught TypeError: friend.sayName is not a function
這段代碼大家是不是看蒙了,前面的我都白學了?難道不應該輸出李小花嗎?記得我們之前說的嗎,創(chuàng)建構造函數(shù)會為實例添加一個指向最初原型的[[Prototype]]指針,這段代碼修改了切斷了構造函數(shù)與原型的聯(lián)系,所以請記住,實例中的指針僅指向原型,而不指向構造函數(shù)。
為了增強大家的理解,我必須從操舊業(yè),為大家畫一幅流暢圖。
重寫原型對象之前的
重寫原型對象之后
原生對象的問題那么原聲對象有缺點嗎,如你所愿,當然是有缺點的,那么原聲對象有缺點嗎,如你所愿,當然是有缺點的,原型中的很多實例是被很多實例共享的,這種對于函數(shù)很合適,基本值的屬性
也是可以的,可以通過在實例中添加一個屬性,隱藏原型中的對應屬性,對于包含引用類型的值的屬性來說,問題就比較突出了。
function Person () { } Person.prototype = { constructor: Person, name: "李小花", friends: ["全蛋", "大隊長"] } var person1 = new Person(); var person2 = new Person(); person1.friends.push("狗蛋"); console.log(person1.friends) // ["全蛋", "大隊長", "狗蛋"] console.log(person2.friends) // ["全蛋", "大隊長", "狗蛋"] person1.friends = [1, 2, 3] console.log(person1.friends) // [1, 2, 3],切斷了與原型的指針 console.log(person2.friends) // ["全蛋", "大隊長", "狗蛋"]
現(xiàn)在業(yè)內最廣泛最認同的模式是組合使用構造函數(shù)模式和原型模式
function Person () { name: "李小花", friends: ["全蛋", "大隊長"] } Person.prototype = { constructor: Person, sayName: function () { console.log(1) } }
剩余的動態(tài)原型模式、寄生構造函數(shù)模式、穩(wěn)妥構造函數(shù)模式因為很少用這里就不多介紹了。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/83503.html
摘要:一面向對象編程基礎實踐通過對象的編程方式,可將實現(xiàn)生活中的一切事物以對象的形式表現(xiàn)出來。此時程序也將會報致命錯誤。屬性不可訪問或未定義,值判斷對象中的屬性不存在時,自動執(zhí)行該函數(shù)。屬性值未定義釋放對象中的不存在的屬性值時,自動執(zhí)行該函數(shù)。 一、PHP面向對象編程基礎實踐 二、PHP面向對象高級編程實踐 知識點:類的繼承、方法重寫、訪問控制、static關鍵字、final關鍵字、數(shù)據訪...
摘要:還有一個問題,就是不能在創(chuàng)建子類性時,像父類型的構造函數(shù)傳遞參數(shù)。組合繼承將原型鏈和借用構造函數(shù)組合到一起,發(fā)揮兩者之長的一張繼承模式,下面來看個例子。組合繼承最大的問題是無論在什么情況下,都會調用兩次父類型構造函數(shù)。 繼承 繼承是面向對象語言中特別重要的概念,js的繼承主要是靠原型鏈實現(xiàn)的。 原型鏈!!! 看到我給標題打了三個嘆號嗎,這里真的很重要!這里真的很重要!這里真的很重要!j...
摘要:引言對于面向對象,相信大家一定不陌生。創(chuàng)建對象面向對象第一步是什么答創(chuàng)建對象。構造函數(shù)優(yōu)于工廠模式也是在于它可以通過辨識出一類的對象。 引言 對于面向對象,相信大家一定不陌生。最近看了一些關于es6面向對象的知識,正好通過這篇文章把關于面向對象的東西給串起來分享給大家。 什么是對象 很多人會鄙視我,說你這篇文章是騙騙剛入行的小朋友的吧,什么是對象我還能不知道?罵我的吃瓜群眾先冷靜一下,...
摘要:中的和是一門很靈活的語言,尤其是。即然是面向對象的編程語言,那也是不可或缺的。在中,永遠指向的是他的調用者。定義是存在于實例化后對象的一個屬性,并且指向原對象的屬性。我們在擴展的時候,同時父類也會有對應的方法,這很顯然是一個很嚴重的問題。 javascript中的this和new javascript是一門很靈活的語言,尤其是function。他即可以以面向過程的方式來用,比如: f...
閱讀 1457·2023-04-25 17:18
閱讀 1889·2021-10-27 14:18
閱讀 2130·2021-09-09 09:33
閱讀 1845·2019-08-30 15:55
閱讀 2021·2019-08-30 15:53
閱讀 3443·2019-08-29 16:17
閱讀 3432·2019-08-26 13:57
閱讀 1735·2019-08-26 13:46