JS筆記—— 物件 (原型物件)
JavaScript物件是一個很有意思的資料型別,由於js沒有類的概念,js物件就承擔起JavaScript物件導向的重任。
JavaScript 並沒有類的概念,但是它有物件。
ECMSscript將物件定義為無序屬性的集合,其屬性可以包含基本值、物件或者函式。
JavaScript的物件的屬性沒有嚴格的順序,每個屬性和方法都需有一個名字和對應的值,看起來和JSON基本沒有區別(實際上js物件和JSON可相互轉換)。
物件基本概念
物件的建立非常的簡單>>>
顯示申明var obj = new Object() obj.name = "tom"obj.age = 21obj.sayName = function(){return this.name} **物件字面量**var obj = {name:"tom", age:21, sayName:function(){return this.name} }
ECMA-262第五版定義了內部採用的特性時(attribute), 描述了屬性(property)
注:property是用來描述物件的,attribute是用來描述property的後設資料,此處的attribute區別於HTML的attribute,HTML標籤的attribute是標籤本身所具有的描述資料,和property描述的物件(DOM)不同,也就是這兩個的描述參照並不是同一基準
屬性
為了支援JavaScript引擎工作,ECMAScript5規定了屬性的型別:資料屬性和訪問器屬性。
資料屬性
資料屬性:資料屬性包含一個資料值的位置,在這個位置可以讀取和寫入值。資料屬性有四個描述其行為的特性。
[[Configurable]]:是否能夠對屬性進行其他更改,包括刪除,修改等[[Enumerable]]:是否能透過for-in迴圈返回屬性[[Writable]]:如字面意思,能否寫入值(修改值)[[Value]]:包含屬性的資料值,代表屬性值得儲存位置
四個特性預設值為,true,true,true,undefined
修改屬性預設特性:Object.defineProperty(obj,propertyName,attrConfig)
該方法接收三個引數:修改的物件,修改的屬性值名稱,該屬性的特性描述符物件
例如:var Car = {}Object.defineProperty(Car,"price",{ writeable:false, value:120000})
注意:運用Object.defineProperty()產生的屬性的特性預設為false,false,false,undefined
所以上面的例子中Car的price屬性中,configurable預設為false,enumerable預設為false
直接透過物件建立的屬性並無此限制
訪問器屬性
訪問器屬性就是我們在其他語言中常看到的getter和setter函式,訪問器屬性並不包含值,它也有四個特性
[[Configurable]]:是否能夠對屬性進行其他更改,包括刪除,修改等 [[Enumerable]]:是否能透過for-in迴圈返回屬性 [[Get]]:讀取資料時呼叫的函式,預設為undefined[[Set]]:寫入資料時呼叫的函式,預設為undefined
例如:
var people = { name:"tom", _age:17, adult:false}Object.defineProperty(people,"age",{ get:function(){ return this._age }, set:function(val){ this._age = val if(val > 18){ this.adult = true } } })
定義多個屬性
要想定義一個屬性就呼叫一次definProperty方法會非常繁瑣,ES5就存在方法defineProperties支援多屬性定義,只是傳入的引數有些許區別
例如:
Object.defineProperties("people",{ name:{ writable:false, value:"Amy" }, _age:{ get:function(){} set:function(){} } })
讀取屬性的特性
使用ECMAScript5的Object.getOwnPropertyDescriptor(),可以取得給定屬性的描述符
引數:包含待查屬性的物件,待查屬性的名稱
例如:
var perple = {}Object.defineProperty(perple,"name",{ writable:false, value:"Jack"})var result = Object.getOwnPropertyDescriptor(people,"name")console.log(result.value)console.log(result.writable)
原型物件
物件的建立往往是重複的,就好像建立一個學生物件並不能完成所有工作,如果牽扯到班級的概念,可能就要建立班級中所有學生的物件了,物件也有很多的重複性,比如一個班的人所在班級學校都是一樣的,是共有的,為了簡化程式碼,也就有了原型物件的概念。
注:物件建立中,每一個學生代表一個例項,這和其他OO(物件導向)語言的類具有相似的理念。
我們建立的每一個函式都有一個prototype(原型)屬性,這個屬性是一個指標,指向一個物件,而這個物件的用途。就是可以包含那些由特定型別的例項共享的屬性和方法。透過字面意思,prototype就是透過呼叫建構函式而建立的那個物件的原型物件。而原型物件也有一個指標constructor指向他所代表的建構函式。例如:Person.prototype.constructor == Person
原型物件就像是一個班級的標籤,例項就是班級的學生,不管這個班級來了多少個新學生,只要這個班級叫一年級,那麼這個班級的學生就都是一年級學生。原型物件包含所有例項公共的屬性為所有例項共享。
建立了自定義的建構函式之後,其原型物件預設只會取得 constructor 屬性;至於其他方法,則都是從 Object 繼承而來的。當呼叫建構函式建立一個新例項後,該例項的內部將包含一個指標(內部屬性),指向建構函式的原型物件。ECMA-262 第 5 版中管這個指標叫 [[Prototype]] 。雖然在指令碼中沒有標準的方式訪問 [[Prototype]] ,但 Firefox、Safari 和 Chrome 在每個物件上都支援一個屬性__proto__
;而在其他實現中,這個屬性對指令碼則是完全不可見的。不過,要明確的真正重要的一點就是,這個連線存在於例項與建構函式的原型物件之間,而不是存在於例項與建構函式之間。
function Person(){} Person.prototype.name="Nicholis" Person.prototype.age=29 Person.prototype.job="Software Engineer" Person.prototype.sayName=function(){ console.log(this.name) }var person1 = new Person() person1 .sayName() // Nicholisvar person2 = new Person() person2 .sayName() // Nicholisconsole.log(person1 .sayName == person2 .sayName) // true
物件例項關係圖
需要注意的幾點:
建構函式的prototype指標指向該特定型別物件(Person)的原型物件,同時該物件的constructor指正指向該建構函式。
例項的[[prototype]]並非建構函式的prototype指標,在主流瀏覽器中的實際實現是
_proto_
指標,指向建構函式的原型物件。例項與建構函式並無直接關係
原型物件屬性和例項屬性
原型物件屬性說不定也有和例項屬性衝突的時候,比如運動會的時候大多數人在開幕式的任務就是走佇列喊口號,但是領頭的人喊的口號和班裡其他人很有可能不同。
領頭:一年三班
同學:團結一心
領頭一年三班
同學:共創佳績
在JS中,發生了衝突該如何選擇,和現實中也是相差無幾的。
function Class13(){} Class13.prototype.sentence= "永爭第一"; Class13.prototype.say = function(){ alert(this.sentence); };var student = new Class13(); // 大多數同學var leader= new Class13(); // 領頭人leader.sentence= "一年三班"; alert(leader.say ()); //"一年三班" —— 來自例項alert(student .say ()); //"永爭第一" ——原型
以上程式碼不難看出,student例項沒建立例項屬性,便輸出了原型物件屬性,而設定了例項屬性的leader輸出的是例項屬性,領頭人在作為同學的基礎上口號是“永爭第一”,但是新的任務讓他產生了新的屬性,遮蔽了之前的設定。
當為物件例項新增一個屬性時,這個屬性就會遮蔽原型物件中儲存的同名屬性;換句話說,新增這個屬性只會阻止我們訪問原型中的那個屬性,但不會修改那個屬性。即使將這個屬性設定為 null ,也只會在例項中設定這個屬性,而不會恢復其指向原型的連線。
更簡單的原型語法
每一次都要書寫xxx.prototype著實讓人心煩,還好我們有更簡便的方法——字面量
function Person(){} Person.prototype = { name : "Nicholas", age : 29, job: "Software Engineer", sayName : function () { alert(this.name); } };
但是用字面量的方法hi重寫整個原型物件,導致的直接後果就是constructor指標不再是預設指向建構函式,而是Object
解決辦法一:在字面量中定義constructor
function Person(){} Person.prototype = { constructor : Person, name : "Nicholas", age : 29, job: "Software Engineer", sayName : function () { alert(this.name); } };
問題:constructor預設資料屬性enumerable會設定為true
解決辦法二:透過Object.defineProperty()重新定義constructor
Object.defineProperty(Person.prototype, "constructor", { enumerable: false, value: Person });
原型物件的問題
省略了為建構函式傳遞初始化引數這一環節,結果所有例項在預設情況下都將取得相同的屬性值。
原型物件包含引用型別值的屬性,會使得例項對該屬性的操作產生連鎖反應。
function Person(){ } Person.prototype = { constructor: Person, name : "Nicholas", age : 29, job : "Software Engineer", friends : ["Shelby", "Court"], sayName : function () { alert(this.name); } };var person1 = new Person();var person2 = new Person(); person1.friends.push("Van"); alert(person1.friends); //"Shelby,Court,Van"alert(person2.friends); //"Shelby,Court,Van"alert(person1.friends === person2.friends); //true
以上程式碼反映了引用型別在原型物件中的問題:當例項直接對引用型別進行方法操作時,將不會為例項建立同名例項屬性,而是定址,找到friends陣列的地址,再進行push操作,這就導致了例項改變了原型物件的值,使得其他例項也會取得改變後的friends。
單純的將引用型別進行賦值操作,那就不會有以上問題,因為這個過程中並沒有定址這個環節,而直接進行了例項屬性申明和賦值。如下:
var person1 = new Person();var person2 = new Person(); person1.friends=["hello"];console.log(person1.friends); //"hello"console.log(person2.friends); //"Shelby,Court,Van"console.log(person1.friends === person2.friends); //false
未命名檔案.png
相關方法
isPrototypeOf()
用途:判斷例項與目標是否含有原型物件關係,即判斷物件是否是某例項的原型物件
alert(Person.prototype.isPrototypeOf(person1)); //truealert(Person.prototype.isPrototypeOf(person2)); //true
Object.getPrototypeOf()
用途:獲取例項的原型物件
alert(Object.getPrototypeOf(person1) == Person.prototype); //truealert(Object.getPrototypeOf(person1).name); //"Nicholas"
hasOwnProperty()
用途: 檢測一個屬性是存在於例項中。
function Person(){} Person.prototype.name = "Tom";var person1 = new Person();var person2 = new Person(); person2.name = "Amy"alert(person1.hasOwnProperty("name")); //falsealert(person2.hasOwnProperty("name")); //truealert(person2.hasOwnProperty("nam")); //false
注:該方法結合運算子 in 可判斷屬性來自例項還是原型
in運算子會判斷給定屬性是否能透過物件訪問,如果能,返回true,不能,返回false
結合hasOwnProperty()就很好判斷屬性來源了
function hasPrototypeProperty(object, name){ return !object.hasOwnProperty(name) && (name in object); } alert(hasPrototypeProperty(person1, "name")); //truealert(hasPrototypeProperty(person2, "name")); //false
Object.keys()
用途:要取得物件上所有可列舉的例項屬性。接收一個物件作為引數,返回一個包含所有可列舉屬性的字串陣列。
function Person(){ } Person.prototype.name = "Nicholas"; Person.prototype.age = 29; Person.prototype.job = "Software Engineer"; Person.prototype.sayName = function(){ alert(this.name); };var keys = Object.keys(Person.prototype); alert(keys); //"name,age,job,sayName"var p1 = new Person(); p1.name = "Rob"; p1.age = 31;var p1keys = Object.keys(p1); alert(p1keys); //"name,age"
Object.getOwnPropertyNames()
用途:得到所有例項屬性,無論它是否可列舉。
ar keys = Object.getOwnPropertyNames(Person.prototype); alert(keys); //"constructor,name,age,job,sayName"// constructor 不可列舉
作者:FocusOn_
連結:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/2471/viewspace-2817315/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- js基礎--原型物件與原型物件鏈JS原型物件
- JS的物件原型JS物件原型
- js高程物件筆記JS物件筆記
- javascript 筆記03(建立物件/原型模式/js 繼承/BOM)JavaScript筆記物件原型模式JS繼承
- JS中的原型物件JS原型物件
- 原型與原型鏈 - 物件與函式關係筆記原型物件函式筆記
- 理解js中的原型,原型物件,原型鏈JS原型物件
- JS的物件導向(理解物件,原型,原型鏈,繼承,類)JS物件原型繼承
- 理解js的 prototype原型物件JS原型物件
- JSP筆記-隱式物件JS筆記物件
- 函式物件、物件、原型函式物件原型
- 物件獲取原型物件物件原型
- js裡的物件基本理解(原型)JS物件原型
- 說說JS中的原型物件和原型鏈JS原型物件
- 工廠方法、建構函式、原型物件——JS基礎學習筆記(四)函式原型物件JS筆記
- JS建構函式,原型鏈,原型物件總結JS函式原型物件
- 淺談JS物件的建立、原型、原型鏈繼承JS物件原型繼承
- JS核心系列:淺談 原型物件和原型鏈JS原型物件
- JS進階(一)(物件導向、原型)JS物件原型
- 原型物件與原型鏈原型物件
- JavaScript 物件 & 原型JavaScript物件原型
- 【JS基礎】原型物件的那些事(二)JS原型物件
- 【JS基礎】原型物件的那些事(一)JS原型物件
- JS物件導向程式設計(三):原型JS物件程式設計原型
- js高階 物件導向 學習筆記JS物件筆記
- JS基礎-函式、物件和原型、原型鏈的關係JS函式物件原型
- 前端筆記——JS基礎(原型&&原型鏈)前端筆記JS原型
- 由物件到原型物件原型
- 物件-原型-繼承物件原型繼承
- 物件導向筆記物件筆記
- JS進階(2):人人都能懂的原型物件JS原型物件
- JS語言精粹學習筆記--物件字面量JS筆記物件
- ES 筆記四十二:物件及 Nested 物件筆記物件
- JavaScript之物件和原型JavaScript物件原型
- 深入理解原型物件和原型鏈原型物件
- JS function 是函式也是物件, 淺談原型鏈JSFunction函式物件原型
- Redis的字串物件筆記Redis字串物件筆記
- Promise 物件學習筆記Promise物件筆記