Javascript基礎鞏固系列——標準庫Object物件
全手打原創,轉載請標明出處:https://www.cnblogs.com/dreamsqin/p/13714848.html, 多謝,=。=~(如果對你有幫助的話請幫我點個贊啦)
重新學習JavaScript是因為當年轉前端有點兒趕鴨子上架的意味,我一直在反思我的知識點總是很零散,不能在腦海中形成一個完整的體系,所以這次想通過再次學習將知識點都串聯起來,結合日常開發的專案,達到溫故而知新的效果。與此同時,總結一下我認為很重要但又被我遺漏的知識點~
Object()
方法
可以當作工具方法使用,將任意值轉為物件,如果引數為空(或者為undefined
和null
),返回一個空物件;如果引數是原始型別的值,會轉為對應的包裝物件;如果引數是一個物件,則直接返回該物件(特殊用法,用於判斷變數是否為物件)。
var obj = Object(1);
obj instanceof Object // true
obj instanceof Number // true
// 判斷變數是否為物件
function isObject(value) {
return value === Object(value);
}
isObject([]) // true
isObject(true) // false
Object
的靜態方法
指部署在Object
物件自身的方法。
Object.keys()
和Object.getOwnPropertyNames()
引數為一個物件,返回一個數組,陣列為該物件自身的(而不是繼承的)所有屬性名,區別是前者只返回可列舉(enumerable: true
var a = ['Hello', 'World'];
Object.keys(a) // ["0", "1"]
Object.getOwnPropertyNames(a) // ["0", "1", "length"]
var obj = {
p1: 123,
p2: 456
};
Object.keys(obj).length // 2
Object.getOwnPropertyNames(obj).length // 2
Object.getOwnPropertyDescriptor()
獲取某個屬性的描述物件(屬性描述物件說明見下文),第一個引數是目標物件,第二個引數是一個字串,對應目標物件的某個屬性名,只能用於物件自身的屬性,不能用於繼承的屬性。
var obj = { p: 'a' };
Object.getOwnPropertyDescriptor(obj, 'p')
// Object { value: "a",
// writable: true,
// enumerable: true,
// configurable: true
// }
Object.defineProperty()
通過描述物件(屬性描述物件說明見下文),定義或修改某個屬性,然後返回修改後的物件,引數:屬性所在物件、屬性名字串、屬性描述物件。
var obj = Object.defineProperty({}, 'p', {
value: 123,
writable: false, // 如果原型物件的某個屬性的writable為false,那麼子物件將無法自定義這個屬性,但可以通過defineProperty修改value來繞過限制。
enumerable: true,
configurable: false
});
obj.p // 123
obj.p = 246; // 正常模式下只是默默失敗,嚴格模式(use strict)下會報錯
obj.p // 123
Object.defineProperties()
通過描述物件(屬性描述物件說明見下文),定義或修改多個屬性,然後返回修改後的物件,引數:屬性所在物件、屬性名與屬性描述物件的鍵值對物件。
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"
Object.create()
可以指定原型物件和屬性,返回一個新的物件。Object.getPrototypeOf()
獲取物件的Prototype物件。
Object
的例項方法
指定義在Object.prototype
物件上的方法,所有Object
的例項物件都繼承了這些方法。
Object.prototype.valueOf()
返回當前物件對應的值,預設情況下返回物件本身,主要用途是JavaScript自動型別轉換時會預設呼叫這個方法。
var obj = new Object();
1 + obj // "1[object Object]"
Object.prototype.toString()
返回當前物件對應的字串形式,預設情況下返回型別字串"[object object]"
(第二個值表示該物件的建構函式),陣列、字串、函式、Date 物件都分別部署了自定義的toString
方法,覆蓋了原生的Object.prototype.toString
方法。
var o = {a:1};
o.toString() // "[object Object]"
// 陣列
[1, 2, 3].toString() // "1,2,3"
// 字串
'123'.toString() // "123"
// 函式
(function () {
return 123;
}).toString()
// "function () {
// return 123;
// }"
// Date物件
(new Date()).toString()
// "Tue May 10 2016 09:11:31 GMT+0800 (CST)"
特殊應用:用於判斷資料型別,由於例項物件可能會自定義toString
方法,覆蓋掉Object.prototype.toString
方法,所以可以利用call
直接呼叫原型方法。
Object.prototype.toString.call(value)
//數值:返回[object Number]
//字串:返回[object String]
//布林值:返回[object Boolean]
//undefined:返回[object Undefined]
//null:返回[object Null]
//陣列:返回[object Array]
//arguments 物件:返回[object Arguments]
//函式:返回[object Function]
Object.prototype.toString.call(Math) // "[object Math]"
//Error 物件:返回[object Error]
//Date 物件:返回[object Date]
//RegExp 物件:返回[object RegExp]
//其他物件:返回[object Object]
//一個比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"
Object.prototype.toLocaleString()
返回當前物件對應的本地字串形式,主要作用是留出一個介面,讓各種不同的物件實現自己版本的toLocaleString
,用來返回針對某些地域的特定的值,目前Array
、Number
、Date
自定義了toLocaleString
方法。
var person = {
toString: function () {
return 'Henry Norman Bethune';
},
toLocaleString: function () {
return '白求恩';
}
};
person.toString() // Henry Norman Bethune
person.toLocaleString() // 白求恩
var date = new Date();
date.toString() // "Tue Jan 01 2018 12:01:33 GMT+0800 (CST)"
date.toLocaleString() // "1/01/2018, 12:01:33 PM"
Object.prototype.hasOwnProperty()
判斷某個屬性是否為當前物件自身的屬性,還是繼承自原型物件的屬性。
var obj = {
p: 123
};
obj.hasOwnProperty('p') // true
obj.hasOwnProperty('toString') // false
Object.prototype.isPrototypeOf()
判斷當前物件是否為另一個物件的原型。Object.prototype.propertyIsEnumerable()
判斷某個屬性是否可列舉,只能用於判斷物件自身的屬性,對於繼承的屬性一律返回false。
var obj = {};
obj.p = 123;
obj.propertyIsEnumerable('p') // true
obj.propertyIsEnumerable('toString') // false
屬性描述物件
JavaScript 提供了一個內部資料結構,用來描述物件的屬性,控制它的行為,比如該屬性是否可寫、可遍歷等等。這個內部資料結構稱為“屬性描述物件”(attributes object)。每個屬性都有自己對應的屬性描述物件,儲存該屬性的一些元資訊。
PS:value
+writable:true
屬性與get
+set
不能共存,在Object.defineProperty()
和Object.defineProperties()
引數裡面的屬性描述物件,writable
、configurable
、enumerable
這三個屬性的預設值都為false
。
// 屬性描述物件的各個屬性稱為“元屬性”,因為它們可以看作是控制屬性的屬性
{
value: 123, // 屬性值,預設為undefined
writable: false, // 布林值,表示屬性值(value)是否可改變(即是否可寫),預設為true
enumerable: true, // 布林值,表示該屬性是否可遍歷,預設為true(不可遍歷時for...in迴圈、Object.keys()、JSON.stringify會跳過該屬性)
configurable: false, // 布林值,表示可配置性,預設為true,控制了屬性描述物件的可寫性(不可配置時無法刪除該屬性,也不得改變該屬性的屬性描述物件(value屬性在writable為true時除外,writable的true改false除外))
get: undefined, // 表示該屬性的取值函式(getter),預設為undefined,取值時會呼叫
set: undefined // 表示該屬性的存值函式(setter),預設為undefined,存值時會呼叫
}
- 存取器
setter
和getter
存值函式稱為setter
,使用屬性描述物件的set
屬性;取值函式稱為getter
,使用屬性描述物件的get
屬性。
// 寫法一(enumerable、configurable預設為false)
var obj = Object.defineProperty({}, 'p', {
get: function () {
return 'getter';
},
set: function (value) {
console.log('setter: ' + value);
}
});
obj.p // "getter"
obj.p = 123 // "setter: 123"
// 寫法二(更推薦,因為enumerable、configurable預設為true)
var obj = {
get p() {
return 'getter';
},
set p(value) {
console.log('setter: ' + value);
}
};
物件的拷貝
將一個物件的所有屬性,拷貝到另一個物件,為了能把存取器定義的屬性也成功拷貝,可以使用以下方法。
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 } })
控制物件狀態
有時需要凍結物件的讀寫狀態,防止物件被改變(但有漏洞:可以通過改變原型物件,來為物件增加屬性;如果屬性值是物件,就只能凍結屬性指向的物件(即無法指向其他值),而不能凍結物件本身的內容)。JavaScript 提供了三種凍結方法,最弱的一種是Object.preventExtensions
,其次是Object.seal
,最強的是Object.freeze
。
Object.preventExtensions()
可以使得一個物件無法再新增新的屬性。
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) // false
Object.seal()
使得一個物件既無法新增新屬性,也無法刪除舊屬性,實質是把屬性描述物件的configurable
屬性設為false
。
var obj = { p: 'hello' };
Object.seal(obj);
delete obj.p;
obj.p // "hello"
obj.x = 'world';
obj.x // undefined
Object.isSealed()
用於檢查一個物件是否使用了Object.seal
方法。
var obj = { p: 'a' };
Object.seal(obj);
Object.isSealed(obj) // true
Object.isExtensible(obj) // false
Object.freeze()
可以使得一個物件無法新增新屬性、無法刪除舊屬性、也無法改變屬性的值,使得這個物件實際上變成了常量。
var obj = {
p: 'hello'
};
Object.freeze(obj);
obj.p = 'world';
obj.p // "hello"
obj.t = 'hello';
obj.t // undefined
delete obj.p // false
obj.p // "hello"
Object.isFrozen()
用於檢查一個物件是否使用了Object.freeze
方法。
var obj = {
p: 'hello'
};
Object.freeze(obj);
Object.isFrozen(obj) // true
Object.isExtensible(obj) // false
參考資料
JavaScript 語言入門教程 :https://wangdoc.com/javascript/index.html