全手打原創,轉載請標明出處: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
)的屬性,由於 JavaScript 沒有提供計算對象屬性個數的方法,所以可以用這兩個方法代替。
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