Object 對象數組
JavaScript 原生提供 Object
對象數據結構
JavaScript 的全部其餘對象都繼承自 Object
對象,即那些對象都是Object
的實例函數
Object
對象的原生方法分紅兩類:Object
對象自己的方法
Object
對象的方法Object
的實例方法
Objec
原型對象 Object.prototype
上的方法,能夠被 Object 實例直接使用Object()
自己是一個函數
var obj = Object(); // 等同於 var obj = Object(undefined); var obj = Object(null); obj instanceof Object // true
instanceof
運算符用來驗證,一個對象是否爲指定的構造函數的實例obj instanceof Object
返回 true
,就表示 obj
對象是 Object
的實例Object
方法將其轉爲對應的包裝對象的實例// 判斷變量是否爲對象的函數 function isObject(value) { return value === Object(value); } isObject([]) // true isObject(true) // false
new Object()
構造函數 的首要用途是 : 直接經過它來生成新對象。
// 經過var obj = new Object()的寫法生成新對象, // 與字面量的寫法var obj = {}是等價的。 // 或者說,後者只是前者的一種簡便寫法
// 與二者的語義是不一樣的
表示將轉成一個對象
則表示新生成一個對象,它的值是Object(value)new Object(value)// Object(value)value// new Object(value)value
Object.keys() 接受一個對象做爲參數,返回一個數組,該數組的成員都是該對象自身的(而不是繼承的)全部屬性名
Object.keys()
方法 只返回可枚舉的屬性(詳見《對象屬性的描述對象》一章)Object.getOwnPropertyNames()
方法 還返回不可枚舉的屬性名var a = ['Hello', 'World']; Object.keys(a) // ["0", "1"] Object.getOwnPropertyNames(a) // ["0", "1", "length"] // 數組的length屬性是不可枚舉的屬性,因此只出如今Object.getOwnPropertyNames() 方法的返回結果
var obj = { p1: 123, p2: 456 }; Object.keys(obj).length; // 2 Object.getOwnPropertyNames(obj).length; // 2
var obj = new Object(); obj.valueOf() === obj; // true
valueOf
方法,就能夠獲得想要的結果
var obj = new Object(); obj.valueOf = function () { return 2; }; 1 + obj // 3
// 用自定義的,覆蓋obj.valueOfObject.prototype.valueOf
var o1 = new Object(); o1.toString() // "[object Object]" var o2 = {a:1}; o2.toString() // "[object Object]" 該字符串說明對象的類型。
toString
方法,可讓對象在自動類型轉換時,獲得想要的字符串形式。
var obj = new Object(); obj.toString = function () { return 'hello'; }; obj + ' ' + 'world' // "hello world"
toString
方法,並不會返回[object Object]
,由於它們都自定義了toString
方法,覆蓋原始方法
[1, 2, 3].toString() // "1,2,3" '123'.toString() // "123" (function () { return 123; }).toString(); // "function () { // return 123; // }" (new Date()).toString(); // "Tue May 10 2016 09:11:31 GMT+0800 (C
Object.prototype.toString
方法。經過函數的call
方法,能夠在任意值上調用這個方法,幫助咱們判斷這個值的類型
Object.prototype.toString.call(value);
typeof
運算符更準確的類型判斷函數
var type = function (o){ var s = Object.prototype.toString.call(o); return s.match(/\[object (.*?)\]/)[1].toLowerCase(); }; type({}); // "object" type([]); // "array" type(5); // "number" type(null); // "null" type(); // "undefined" type(/abcd/); // "regex" type(new Date()); // "date" // 在上面這個type函數的基礎上,還能夠加上專門判斷某種類型數據的方法 ['Null', 'Undefined', 'Object', 'Array', 'String', 'Number', 'Boolean', 'Function', 'RegExp' ].forEach(function (t) { type['is' + t] = function (o) { return type(o) === t.toLowerCase(); }; }); type.isObject({}) // true type.isNumber(NaN) // true type.isRegExp(/abc/) // true
toString
的返回結果相同,也是返回一個值的字符串形式toLocaleString
,用來返回針對某些地域的特定的值toLocaleString
方法
toString
和toLocaleString
返回值就不同,並且toLocaleString
的返回值跟用戶設定的所在地域相關
屬性描述對象 attributes objectui
JavaScript 提供了一個內部數據結構,用來描述對象的屬性,控制它的行爲,好比該屬性是否可寫、可遍歷等等this
{
value: undefined, // 該屬性的屬性值,默認爲undefined
writable: true, // 表示屬性值(value)是否可改變(便是否可寫),默認爲true
enumerable: true, // 表示該屬性是否可遍歷,默認爲true。若是設爲false,會使得某些操做(好比for...in遍歷對象和對象原型中能夠遍歷的屬性、Object.keys())跳過該屬性
configurable: true, // 表示可配置性,默認爲true。若是設爲false,將阻止某些操做改寫該屬性,
// 好比沒法刪除該屬性,也不得改變該屬性的屬性描述對象(value屬性除外)。也就是說,configurable屬性控制了屬性描述對象的可寫性。
get: undefined, // 表示該屬性的取值函數(getter),默認爲undefined 每次讀取該屬性,都會調用這個取值函數
// 一旦定義了取值函數(或存值函數),就不能將屬性設爲
set: undefined // 表示該屬性的存值函數(setter),默認爲undefined
}
// 方式1
getsetwritabletruevar obj = Object.defineProperties({}, {
p1: { value: 1, enumerable: true },
p2: { value: 2, enumerable: false }
});
// 方式2
var obj = {name:"Tom", age:"22"};
Object.defineProperty(obj, "name", {
writable: false, // 屬性不可寫
enumerable: false, // 屬性不可遍歷 如 for in 將跳過 name 屬性
configurable: false, // 屬性不可配置 如 delete name
});
Object.defineProperty(obj, 'fullName', {
get:function(){
return this.name + "Michal";
},
set:function(newName){
this.name = newName.split(" ")[0];
}
});
Object.getOwnPropertyDescriptor()
方法
var obj = { p: 'a' }; // 獲取obj.p的屬性描述對象 Object.getOwnPropertyDescriptor(obj, 'p'); // Object {
// value: "a", // writable: true, // enumerable: true, // configurable: true // }
Object.getOwnPropertyNames()
方法
Object.defineProperty(object, propertyName, attributesObject) 方法
var obj = Object.defineProperty({}, 'p', { value: 123, writable: false, // 不可寫 enumerable: true, configurable: false }); obj.p // 123 obj.p = 246; obj.p // 123
var obj = Object.defineProperties({}, { p1: { value: 123, enumerable: true }, p2: { value: 'abc', enumerable: true }, p3: { get: function () { return this.p1 + this.p2 }, // 每次讀取該屬性,都會調用這個取值函數 enumerable:true, configurable:true } }); obj.p1 // 123 obj.p2 // "abc" obj.p3 // "123abc"
false
var obj = {}; obj.p = 123; obj.propertyIsEnumerable('p'); // true obj.propertyIsEnumerable('toString'); // false
元屬性spa
指屬性描述對象的各個屬性,即控制屬性的屬性prototype
value
屬性是目標屬性的值
var obj = {}; obj.p = 123; Object.getOwnPropertyDescriptor(obj, 'p').value; // 123 Object.defineProperty(obj, 'p', { value: 246 }); obj.p // 246
writable
屬性,決定了目標屬性的值(value)是否能夠被改變
writable
爲false
的屬性賦值不會報錯,只會默默失敗'use strict'; // 採用嚴格模式 var obj = {}; Object.defineProperty(obj, 'a', { value: 37, writable: false }); obj.a = 37; // Uncaught TypeError: Cannot assign to read only property 'a' of object
__proto__
是原型對象,它的foo
屬性不可寫。obj
對象繼承proto
,也不能夠再自定義這個屬性了。若是是嚴格模式,這樣作還會拋出一個錯誤
var proto = Object.defineProperty({}, 'foo', { value: 'a', writable: false }); var obj = Object.create(proto); obj.foo = 'b'; obj.foo // 'a' 若是是嚴格模式,此處將拋出一個錯誤
var obj = Object.create(proto); Object.defineProperty(obj, 'foo', { value: 'b' }); obj.foo // "b"
enumerable
(可遍歷性)返回一個布爾值,表示目標屬性是否可遍歷
enumerable
爲false
,下面三個操做不會取到該屬性for..in
循環Object.keys()
方法JSON.stringify()
方法enumerable
能夠用來設置「祕密」屬性obj.x
屬性的enumerable
爲false
,因此通常的遍歷操做都沒法獲取該屬性,使得它有點像「祕密」屬性,
configurable
(可配置性)返回一個布爾值,決定了是否能夠修改屬性描述對象
configurable
爲false
時,value
、writable
、enumerable
和configurable
都不能被修改了obj.p
的configurable設置
爲false
。而後,改動value
、writable
、enumerable
、configurable
,結果都報錯
writable
只有在false
改成true
會報錯,true
改成false
是容許的至於value
,只要writable
和configurable
有一個爲true
,就容許改動setter
,使用屬性描述對象的set
屬性getter
,使用屬性描述對象的get
屬性
var obj = Object.defineProperty({}, 'p', { get: function () { return 'getter'; }, set: function (value) { console.log('setter: ' + value); } }); obj.p // "getter" obj.p = 123 // "setter: 123"
var obj = { get p() { // 取值函數get不能接受參數 return 'getter'; }, set p(value) { // 存值函數set只能接受一個參數(即屬性的值) console.log('setter: ' + value); } };
存取器每每用於,屬性的值依賴對象內部數據的場合。code
var obj ={ $n : 5, get next() { return this.$n++ }, set next(n) { if (n >= this.$n){ this.$n = n; }else{ throw new Error('新的值必須大於當前值'); } } }; obj.next // 5 obj.next = 10; obj.next // 10 obj.next = 5; // Uncaught Error: 新的值必須大於當前值
var extend = function (to, from) { for (var property in from) { to[property] = from[property]; } return to; }
Object.defineProperty
方法來拷貝屬性var extend = function (to, from) { for (var property in from) { if (!from.hasOwnProperty(property)){
// 來過濾掉繼承的屬性,不然會報錯,由於讀不到繼承屬性的屬性描述對象 continue; } Object.defineProperty( to, property, Object.getOwnPropertyDescriptor(from, property) ); } return to; } extend({}, { get a(){ return 1 } }) // { get a(){ return 1 } })hasOwnPropertyObject.getOwnPropertyDescriptor
控制對象狀態對象
有時須要凍結對象的讀寫狀態,防止對象被改變
blog
JavaScript 提供了 強度依次遞增的三種凍結方法是,
var obj = new Object(); Object.preventExtensions(obj); Object.defineProperty(obj, 'p', { value: 'hello' }); // TypeError: Cannot define property:p, object is not extensible. obj.p = 1; obj.p // undefined
Object.isExtensible()
方法
Object.preventExtensions
方法。var obj = new Object(); Object.isExtensible(obj); // true Object.preventExtensions(obj); Object.isExtensible(obj); // fal
Object.seal
實質是把屬性描述對象的configurable
屬性設爲false
,所以屬性描述對象再也不能改變Object.seal
只是禁止新增或刪除屬性,並不影響修改某個屬性的值Object.isSealed
方法用於檢查一個對象是否使用了Object.seal
方法
Object.isExtensible
方法返回false
Object.isFrozen()
方法用於檢查一個對象是否使用了Object.freeze
方法
Object.freeze
方法之後,Object.isSealed
將會返回true
,Object.isExtensible
返回false
var obj = new Object(); Object.preventExtensions(obj); var proto = Object.getPrototypeOf(obj); proto.t = 'hello'; obj.t
// hello
obj
的原型也凍結住
var obj = new Object(); Object.preventExtensions(obj); var proto = Object.getPrototypeOf(obj); Object.preventExtensions(proto); proto.t = 'hello'; obj.t // undefined
var obj = { foo: 1, bar: ['a', 'b'] }; Object.freeze(obj); obj.bar.push('c'); obj.bar // ["a", "b", "c"]
function deepFreeze(obj){ if(typeof obj !== "object"){ return obj; }; object.freeze(obj); for(var attr in obj){ deepFreeze(obj[attr]); }; };