JS中的對象(Object)是一個基本數據類型,是一種複合值,它將不少值(原始值或者其餘對象)聚合在一塊兒,可經過名字訪問這些值(屬性)的無序集合。每一個對象都有一個原型,原型能夠爲空。git
Object每一個屬性既能夠是一個命名的數據屬性,也能夠是一個命名的訪問器屬性,或者是一個內部屬性:github
上面兩個列表中屬性的默認值爲(以下表3)函數
每個對象數據屬性都具備表1的特性,每個對象裏面的方法屬性都具備表3裏面的特性,這些特性能夠經過ECMAScript內置對象Object構造器方法Object.defineProperty來修改。如a.x屬性的Enumerable被修改成false時,對象在for-in循環裏將迭代不出該屬性。其餘的屬性這裏不詳細講解ui
全部的Object對象都必須具備下表的屬性(表4)this
[[prototype]]用於實現繼承,[[Class]]用於區分對象的種類,也就是對象的名字。如String對象的[[Class]]值爲"String"。建立對象時,對象的內部屬性的[[Classs]]是除了"Arguments","Date","Array"....等內部對象名以外的值。因此咱們在定義對象的時候不能重名和用內置對象的名字。es5
ECMAScript不一樣的對象的行爲不一樣,對應實現上表這些屬性的方式也是略有不一樣。可是必須都具有上述屬性。不一樣的內置對象具備不一樣的屬性,下表是隻有在某些對象裏面才具備屬性(表5)spa
相對於Object內置對象Number,Date對象多實現[[primitiveValue]],Function對象多實現[[Code]]等屬性,而經過Function.prototype.bind方法建立的Function對象還多實現[[TargetFunction]]方法,RegExp對象比Object多實現了[[Match]]屬性等。而若是是可用於構造的對象則必須實現[[construct]]屬性。prototype
一、對象字面量建立3d
var obj = {
name: 'lyq',
age: 18
}
console.log(obj.name) //lyq複製代碼
直接複製操做。不詳細講解,由於涉及到JS中的「=、{}」操做符的運行過程,詳細講解的話又是一個話題。code
var obj = new Object();
obj.name = 'lyq';
console.log(obj.name); //lyq複製代碼
function Obj (name) {
this.name = name;
this.age = 18;
}
var obj = new Obj('lyq');
console.log(obj.name); //lyq
console.log(obj.age); //18複製代碼
- 若是提供了value則
- 若是Type(value)是Object,則
- value是原聲ECMAScript對象(Array,Date這些),不建立新對象,簡單返回value
- 若是value是宿主對象,則採起動做和放回依賴實現的結果的方式可使依賴於宿主對象(不糾結字面意思,簡單的說就是返回宿主對象)
- 若是Type(value)是String類型,返回ToObject(value).
- 若是Type(value)是Boolean類型,返回ToObject(value).
- 若是Type(value)是Number類型,返回ToObject(value).
- 未提供參數value或者類型是Null或者Undefined
- 令obj爲一個新建立的原聲ECMAScript對象
- 設定obj的[[prototype]]內部屬性爲標準內置的Object的prototype。
- 設定obj的[[Class]]內部屬性爲"Object「
- 設定obj的[[Extensible]]內部屬性爲true
- 設定obj的表1指定的全部內部方法
- 返回obj。
根據表5建立Function對象,必須實現多些屬性,其中包括Function對象需擁有 FormalParameterList 爲可選參數列表,FunctionBody 爲函數體,詞法環境 Scope ,嚴格模式標記Strict。經過Function構造器建立Function對象的步驟以下:
- 令argCount爲傳給這個函數調用的參數總數
- 令P爲空字符串
- 若是argCount=0,令body爲空字符串
- 不然若是argCount=1,令body爲那個參數
- 不然argCount>1
- 令firstArg爲第一個參數
- 令P爲ToString(firstArg)
- 令k爲2
- 只要k<argCount就重複
- 令nextArg爲第k個參數
- 令P爲以前的P值。字符串「,」(逗號),ToString(nextArg)串聯結構
- k遞增
- 令body爲第k個參數
- 令body爲ToString(body)
- 若是P不可解析爲一個FormalParameterListopt,則拋出一個SyntaxError異常
- 若是body不可解析爲FunctionBody,則拋出一個SyntaxError異常
- 建立一個新的 ECMAScript 原生對象,令 F 爲此對象。
- 依照 表1 描述設定 F 的除 [[Get]] 之外的全部內部方法
- 設定 F 的 [[Class]] 內部屬性爲 "Function"。
- 設定 F 的 [[Prototype]] 內部屬性爲指定的標準內置 Function 對象的 prototype 屬性。
- 設定 F 的 [[Get]] 內部屬性。
- 設定 F 的 [[Call]] 內部屬性。
- 設定 F 的 [[Construct]] 內部屬性。
- 設定 F 的 [[HasInstance]] 內部屬性。
- 設定 F 的 [[Scope]] 全局環境。
- 設定 F 的 [[FormalParameters]] 內部屬性爲 P。
- 設定 F 的 [[Code]] 內部屬性爲 body 解析後的 FunctionBody。
- 設定 F 的 [[Extensible]] 內部屬性爲 true。
- 令 argCount爲 FormalParameterList 指定的形式參數的個數。
- 以參數 "length",屬性描述符 {[[Value]]: len, [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false},false 調用 F 的 [[DefineOwnProperty]] 內部方法。
- 令 proto 爲彷彿使用 new Object() 表達式建立新對象的結果,其中 Object 是標準內置構造器名。
- 以參數 "constructor", 屬性描述符 {[[Value]]: F, { [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true}, false 調用 proto 的 [[DefineOwnProperty]] 內部方法。
- 以參數 "prototype", 屬性描述符 {[[Value]]: proto, { [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: false}, false 調用 F 的 [[DefineOwnProperty]] 內部方法。
- 若是body是嚴格模式代碼。則令strict爲true,不然令strict爲false
- 若是strict是true,按照嚴格模式下的代碼解析判斷是否拋出異常
- 返回 F。
上述建立內部方法的步驟都沒有詳細標出,可是不礙理解對象的建立過程。對象建立中的內存分配是由構造函數的內部方法[[Construct]]負責的。該內部方法的行爲是ECMAScript定義好的,全部的構造函數都是使用該方法來爲新對象分配內存的。而若是被new的對象沒有實現[[contruct]]這個屬性將會拋出異常。接下來補充上面Function對象的建立過程當中省略的建立[[construct]]屬性的過程。
當以一個可能的空的參數列表調用函數對象 F 的 [[Construct]] 內部方法,採用如下步驟:
- 令 obj 爲新建立的 ECMAScript 原生對象。
- 依照 8.12 設定 obj 的全部內部方法。
- 設定 obj 的 [[Class]] 內部方法爲 "Object"。
- 設定 obj 的 [[Extensible]] 內部方法爲 true。
- 令 proto 爲以參數 "prototype" 調用 F 的 [[Get]] 內部屬性的值。
- 若是 Type(proto) 是 Object,設定 obj 的 [[Prototype]] 內部屬性爲 proto。
- 若是 Type(proto) 不是 Object,設定 obj 的 [[Prototype]] 內部屬性爲 標準的內置對象
- 以 obj 爲 this 值,調用 [[Construct]] 的參數列表爲 args,調用 F 的 [[Call]] 內部屬性,令 result 爲調用結果。
- 若是 Type(result) 是 Object,則返回 result。
- 返回 obj
回到前面實例2,Obj 是一個Function對象,實現了[[contruct]]屬性,能夠經過 new Obj()來建立一個新的對象。而此時new Obj() 的過程就能new Object()原理同樣。
var obj = {};
console.log(obj.name); //undefined
obj.name = 'lyq';
console.log(obj.name); // lyq複製代碼
var obj = {
name : 'lyl'
};
console.log(obj.name); //lyl
delete obj.name;
console.log(obj.name); //undefined複製代碼
var obj = {
name: 'lyq'
};
// 第一種方法
console.log(obj['name']); //lyq
// 第二種方法
console.log(obj.name); // lyq
console.log(obj.age); // undefined複製代碼
var obj = {
name: 'lyq'
};
console.log(obj.name); // lyq
obj.name = 'lee';
console.log(obj.name); // lee複製代碼
var person = function Person(){};
Person.prototype.x = 1;
var person = new Person();複製代碼
根據上述建立對象的過程,當我經過new建立一個實例對象的時候,會先判斷構造函數的prototype是否存在,同時是一個對象,若是是則將這個prototype對象賦值給新建立的對象的prototype。若是不存在和不是一個對象,則賦給新建立出來的對象一個標準內置的prototype。上述Person.prototype就是實例對象的原型。(經過上述函數對象的建立過程當中可以看出,每一個函數都會自動建立一個prototype對象,默認爲標準的內置對象,用於知足函數會被當作構造函數的可能性。)
構造函數建立出來的實例對象共有一個prototype對象,而不是每一個實例都複製一份prototype出來,每一個實例對象都有一個指向原型的對象爲proto
構造函數的prototype裏面有一個指向構造函數自己的屬性爲constructor,標識每一個實例是經過哪一個構造函數建立出來的,如:
Person === person.__proto__.constructor //true;複製代碼
prototype也是一個對象,也具備prototype屬性,上例中Person.prototype的prototype屬性是Object對象的內置prototype屬性。而Object對象的內置prototype的prototype爲null。對象的原型圖以下
當要獲取person對象的屬性時,就會照圖中藍色的鏈來查找屬性,這條藍色的鏈便可理解爲原型鏈(這逼其實就是js中的原型鏈)。
js在查找值的時候就是經過表1中的[[get]]方法來獲取的,設置值是經過[[put]]方法來設置。這裏不深刻講解這兩個方法,有興趣能夠繼續深刻了解。ECMAScript中[[get]]會照着原型鏈獲取屬性,而[[put]]是直接將屬性設置在person對象上,因此即便對象原型上存在的屬性,在設置的時候若是對象自己不存在該屬性,則直接建立新屬性,而不會影響原型,以下圖
因此當對對象進行增刪改操做時不會影響到對象的原型和構造函數,當對對象進行查操做時,若是在自身獲取不到,則會繼續在原型鏈上查找,直到獲取到該對象或到根原型爲null爲止
- Object.prototype —— 對象原型
- Object.getPrototypeOf(o) —— 返回o的內部屬性值
- Object.getOwnPropertyDescriptor ( O, P ) —— 返回對象O上面P屬性的描述符
- Object.create ( O [, Properties] ) —— 建立一個擁有指定原型和若干屬性的對象
- Object.defineProperty ( O, P, Attributes ) —— 在對象上添加或者修改一個屬性,並返回這個對象,其中obj爲要修改的對象,p爲要修改或者添加的屬性,Attributes將被定義或者修改的屬性的描述符
- Object.defineProperties ( O, Properties ) —— 添加或者修改多個屬性,操做多個屬性不能更改描述符
- Object.seal ( O ) —— 密封對象
- Object.freeze ( O ) —— 凍結對象中的某個屬性,使該屬性沒法進行增刪改查
- Object.preventExtensions ( O ) ——禁止對象不能擴展,這樣對象就永遠不能添加更改屬性
- Object.isSealed ( O ) —— 判斷一個對象是否被密封
- Object.isFrozen ( O ) —— 判斷一個對象是否被凍結
- Object.isExtensible ( O ) —— 判斷對象是否能夠擴展
- Object.prototype.constructor —— 標準內置的Object構造器
- Object.prototype.toString ( ) —— 返回對象的字符串表示
- Object.prototype.toLocaleString ( ) —— 返回對象的本地字符串表示
- Object.prototype.valueOf ( ) —— 返回指定對象的原始值
- Object.prototype.hasOwnProperty (V) —— 返回一個布爾值,表示對象是否包含有V這個屬性,該屬性爲對象自己屬性,不包括原型鏈上的屬性
- Object.prototype.isPrototypeOf (V) —— 返回一個布爾值,表示對象是否包含V這個屬性,包含自身和原型鏈上的
- Object.prototype.propertyIsEnumerable (V) —— 返回一個布爾值,表示V屬性是否能夠枚舉