Object 靜態方法總結
create 創建一個對象
const obj = Object.create({a:1}, {b: {value: 2}})
第一個參數爲對象,對象爲函數調用之後返回新對象的原型對象,第二個參數爲對象本身的實例方法(默認不能修改,不能枚舉)
obj.__proto__.a === 1 // true
obj.b = 3;
console.log(obj.b) // 2
//創建一個可寫的,可枚舉的,可配置的屬性p
obj2 = Object.create({}, {
p: {
value: 2, // 屬性值
writable: true, // 是否可以重寫值
enumerable: true, //是否可枚舉
configurable: true //是否可以修改以上幾項配置
}
});
obj2.p = 3;
console.log(obj2.p) // 3
注意: enumerable 會影響以下
for…in 遍歷包括對象原型上屬性
Object.keys() 只能遍歷自身屬性
JSON.stringify 只能序列化自身屬性
defineProperty Object.defineProperty(object, prop, descriptor)定義對象屬性
添加數據屬性
var obj = {};
// 1.添加一個數據屬性
Object.defineProperty(obj, "newDataProperty", {
value: 101,
writable: true,
enumerable: true,
configurable: true
});
obj.newDataProperty // 101
// 2.修改數據屬性
Object.defineProperty(obj, "newDataProperty", {
writable:false
});
//添加訪問器屬性
var obj = {};
Object.defineProperty(obj, "newAccessorProperty", {
set: function (x) {
this.otherProperty = x;
},
get: function () {
return this.otherProperty;
},
enumerable: true,
configurable: true
});
注意: 1.第一個參數必須爲對象(屬性是屬於對象的)
2.descriptor 不能同時具有 (value 或 writable 特性)(get 或 set 特性)。
3.configurable 爲false 時,不能重新修改裝飾器
defineProperties Object.defineProperties(object, {prop1 : descriptor1, prop2 : descriptor2, ...) 定義多個屬性
var obj = {};
Object.defineProperties(obj, {
'property1': {
value: true,
writable: true
},
'property2': {
value: 'Hello',
writable: false
}
// etc. etc.
});
keys 遍歷可枚舉的屬性,只包含對象本身可枚舉屬性,不包含原型鏈可枚舉屬性
let arr = ["a", "b", "c"];
let obj = { foo: "bar", baz: 42 };
let ArrayLike = { 0 : "a", 1 : "b", 2 : "c"};
Object.keys(arr) // ['0', '1', '2']
Object.keys(obj) // ["foo","baz"]
Object.keys(ArrayLike) // ['0', '1', '2']
values 遍歷可枚舉的屬性值,只包含對象本身可枚舉屬性值,不包含原型鏈可枚舉屬性值
let arr = ["a", "b", "c"];
let obj = { foo: "bar", baz: 42 };
let ArrayLike = { 0 : "a", 1 : "b", 2 : "c"};
Object.values(arr) // ["a", "b", "c"]
Object.values(obj) // ["bar",42]
Object.values(ArrayLike) // ["a", "b", "c"]
assign Object.assign( target, source, source1 ) 方法用於對象的合併,將源對象(source)的所有可枚舉屬性,複製到目標對象(target)。拷貝的屬性是有限制的,只拷貝源對象的自身屬性(不拷貝繼承屬性),也不拷貝不可枚舉的屬性(enumerable: false)
const target = { a: 1, b: 1 };
const source1 = { b: 2, c: 2 };
const source2 = { c: 3 };
Object.assign(target, source1, source2); target // {a:1, b:2, c:3}
特殊情況:
let obj = {a: 1};
Object.assign(obj, undefined) === obj // true
Object.assign(obj, null) === obj // true
Object.assign([1, 2, 3], [4, 5]) // [4, 5, 3]
Object.assign方法實行的是淺拷貝,而不是深拷貝。
const obj1 = {a: {b: 1}};
const obj2 = Object.assign({}, obj1);
obj1.a.b = 2;
console.log(obj2.a.b) //2
obj2.a.b = 3
console.log(obj1.a.b) //3
getPrototypeOf 獲取指定對象的原型(內部[[Prototype]]屬性的值)
const prototype1 = {};
const object1 = Object.create(prototype1);
console.log(Object.getPrototypeOf(object1) === prototype1); // true
注意:Object.getPrototypeOf(Object) 不是 Object.prototype
Object.getPrototypeOf( Object ) === Function.prototype; // true
setPrototypeOf 設置一個指定的對象的原型
const obj = {a: 1}, proto = {b:2}
Object.setPrototypeOf(obj, proto)
obj.__proto__ === proto //true
getOwnPropertyNames 與keys相似,但包含遍歷包含不可枚舉屬性
var my_obj = Object.create({}, {
getFoo: {
value: function() { return this.foo; },
enumerable: false
}
});
my_obj.foo = 1;
Object.getOwnPropertyNames(my_obj).sort() // ["foo", "getFoo"]
getOwnPropertyDescriptor 獲取該屬性的描述對象
let obj = { foo: 123 };
Object.getOwnPropertyDescriptor(obj, 'foo')
// { value: 123, writable: true, enumerable: true, configurable: true }
getOwnPropertyDescriptors 返回指定對象所有自身屬性(非繼承屬性)的描述對象
Object.getOwnPropertyDescriptors 方法,返回指定對象所有自身屬性(非繼承屬性)的描述對象。
const obj = {
foo: 123,
get bar() { return 'abc' }
};
console.dir(Object.getOwnPropertyDescriptors(obj))
// { foo:{ value: 123,
// writable: true,
// enumerable: true,
// configurable: true },
// bar:{ get: [Function: bar],
// set: undefined,
// enumerable: true,
// configurable: true }
// }
使用場景:
Object.assign() 方法只能拷貝源對象的可枚舉的自身屬性,同時拷貝時無法拷貝屬性的特性,而且訪問器屬性會被轉換成數據屬性,也無法拷貝源對象的原型
Object.create() 方法可以實現上面說的這些,配合getPrototypeOf,以及getOwnPropertyDescriptors實現全面淺拷貝
Object.create(
Object.getPrototypeOf(obj),
Object.getOwnPropertyDescriptors(obj)
);
entries 分割對象
const obj = { foo: 'bar', baz: 42 };
console.log(Object.entries(obj)); // [ ['foo', 'bar'], ['baz', 42] ]
// array like object
const obj = { 0: 'a', 1: 'b', 2: 'c' };
console.log(Object.entries(obj)); // [ ['0', 'a'], ['1', 'b'], ['2', 'c'] ]
// string
Object.entries('abc') // [['0', 'a'], ['1', 'b'], ['2', 'c']]
Object.entries(100) // []
is 它用來比較兩個值是否嚴格相等,與嚴格比較運算符(===)的行爲基本一致
Object.is('foo', 'foo') // true
Object.is({}, {}) // false
不同於 === 之處
+0 === -0 //true
NaN === NaN // false
Object.is(+0, -0) // false
Object.is(NaN, NaN) // true
preventExtensions 讓一個對象變的不可擴展,也就是永遠不能再添加新的屬性&isExtensible 判斷一個對象是否可擴展
let empty = {}
Object.isExtensible(empty) //true
empty.a = 1 //添加成功
//將對象變爲不可拓展
Object.preventExtensions(empty)
Object.isExtensible(empty) //false
empty.b = 2 //靜默失敗,不拋出錯誤
empty.a = 5 //修改a屬性值爲5 修改成功
總結:
1.preventExtensions 可以讓這個對象變的不可擴展,也就是不能再有新的屬性。
2.需要注意的是不可擴展的對象的屬性通常仍然可以被刪除。
3.嘗試給一個不可擴展對象添加新屬性的操作將會失敗,不過可能是靜默失敗,也可能會拋出 TypeError 異常(嚴格模式)。
4.Object.preventExtensions 只能阻止一個對象不能再添加新的自身屬性,仍然可以爲該對象的原型添加屬性。
seal將一個對象密封 isSealed 判斷一個對象是否爲密封的
密封對象是指那些不能添加新的屬性,不能刪除已有屬性,以及不能修改已有屬性的可枚舉性、可配置性、可寫性,但可能可以修改已有屬性的值的對象。
1. 先講seal 方法:
var o2 = {b: 1}
o2.d = 2 //添加成功
var obj2 = Object.seal(o2);
obj2 === o2 //true 方法返回原對象,棧指針指向同一塊內存
Object.isSealed(o2) // true
o2.b = 111 //修改b屬性值成功
o2.f = 222 //靜默失敗,屬性f沒有成功添加
delete o2.b //靜默失敗,屬性b沒有成功刪除
2. 講isSealed 方法:
let o = {};
Object.isSealed(o) //false
// 之後通過Object.preventExtensions方法將空對象設置爲不可擴展。
Object.preventExtensions(o);
Object.isSealed(o) // true
但是如果爲非空對象呢?
let o2 = {a: 1}
Object.preventExtensions(o2);
Object.isSealed(o2) // false
因爲屬性 a 是可配置的(configurable爲true),所以不是密封的對象,修改方法如下:
let o2 = {a: 1}
Object.preventExtensions(o2);
Object.defineProperty(o2, "a", { configurable: false });
Object.isSealed(o2) //true
總結: 1.密封一個對象會讓這個對象變的不能添加新屬性,且所有已有屬性會變的不可配置。
2.屬性不可配置的效果就是屬性變的不可刪除,以及一個數據屬性不能被重新定義成爲訪問器屬性,或者反之。
3.但屬性的值仍然可以修改。
4.嘗試刪除一個密封對象的屬性或者將某個密封對象的屬性從數據屬性轉換成訪問器屬性,結果會靜默失敗或拋出TypeError 異常(嚴格模式)。
freeze 凍結一個對象&isFrozen 判斷一個對象是否已經被凍結
凍結對象是指那些不能添加新的屬性,不能修改已有屬性的值,不能刪除已有屬性,以及不能修改已有屬性的可枚舉性、可配置性、可寫性的對象。也就是說,這個對象永遠是不可變的。
1.先講freeze 方法:
let o3 = {a: 1}
o3.b = 2 //添加屬性b成功
Object.freeze(o3)
Object.isFrozen(o3) //true 對象已被凍結
o3.a = 2 //修改屬性a值失敗
o3.c = 5 //添加屬性c失敗
delete o3.b //刪除屬性b失敗
2.再講isfrozen 方法:
let o4 = {a: 1}
o4.b = 2 // 添加屬性b成功
Object.priventExtensions(o4)
Object.defineProperties(o4, {
a: {configurable: false, writable: false},
b: {configurable: false, writable: false}
})
Object.isFrozen(o4) //true o4 已經被凍結
總結:
1.凍結對象的所有自身屬性都不可能以任何方式被修改。
2.任何嘗試修改該對象的操作都會失敗,可能是靜默失敗,也可能會拋出異常(嚴格模式中)。
3.數據屬性的值不可更改,訪問器屬性(有getter和setter)也同樣(但由於是函數調用,給人的錯覺是還是可以修改這個屬性)。
4.如果一個屬性的值是個對象,則這個對象中的屬性是可以修改的,除非它也是個凍結對象。
淺凍結與深凍結:
(function () {
obj = {
internal :{}
};
Object.freeze(obj);//淺凍結
obj.internal.a = "aValue";
console.log(obj.internal.a);//"aValue"
//想讓一個對象變得完全凍結,凍結所有對象中的對象,可以使用下面的函數.
function deepFreeze(o){
var prop,propKey;
Object.freeze(o);//首先凍結第一層對象
for(propKey in o){
prop = o[propKey];
if(!o.hasOwnProperty(propKey) || !(typeof prop === "object") || Object.isFrozen(prop)){
continue;
}
deepFreeze(prop);//遞歸
}
}
deepFreeze(obj);
obj.internal.b = "bValue";//靜默失敗
console.log(obj.internal.b);//undefined
})();
hasOwnProperty
方法會返回一個布爾值,指示對象自身屬性中是否具有指定的屬性
let o = {a: 1 }
o.hasOwnProperty('a') //true
o.hasOwnProperty('b') //false 對象自身沒有屬性b
o.hasOwnProperty('toString'); //false 不能檢測對象原型鏈上的屬性
如何遍歷一個對象的所有自身屬性,例子:
var buz = {
fog: 'stack'
};
for (var name in buz) {
if (buz.hasOwnProperty(name)) {
console.log("this is fog (" + name + ") for sure. Value: " + buz[name]);
}
else {
console.log(name); // toString or something else
}
}
isPrototypeOf
isPrototypeOf方法用於測試一個對象是否存在於另一個對象的原型鏈上
function Foo() {}
function Bar() {}
function Baz() {}
Bar.prototype = Object.create(Foo.prototype);
Baz.prototype = Object.create(Bar.prototype);
var baz = new Baz();
console.log(Baz.prototype.isPrototypeOf(baz)); // true
console.log(Bar.prototype.isPrototypeOf(baz)); // true
console.log(Foo.prototype.isPrototypeOf(baz)); // true
console.log(Object.prototype.isPrototypeOf(baz)); // true
propertyIsEnumerable指定的屬性是否可枚舉
obj.propertyIsEnumerable(prop) prop爲被測試的屬性名
1. 一般情況下
var o = {};
var a = [];
o.prop = 'is enumerable';
a[0] = 'is enumerable';
o.propertyIsEnumerable('prop'); // 返回 true
a.propertyIsEnumerable(0); // 返回 true
2. 瀏覽器內置對象
var a = ['is enumerable'];
a.propertyIsEnumerable(0); // 返回 true
a.propertyIsEnumerable('length'); // 返回 false
Math.propertyIsEnumerable('random'); // 返回 false
this.propertyIsEnumerable('Math'); // 返回 false
3. 自身屬性和繼承屬性
(原型鏈上propertyIsEnumerable不被考慮)
var fn = function(){
this.prop = '123';
}
fn.prototype = { prototypeProp: true}
var o = new fn()
o.propertyIsEnumerable('prop') // true
o.propertyIsEnumerable('prototypeProp') // false
caller 返回當前函數的調用者
function test(){
if(test.caller == null){
alert("JavaScript頂層作用域調用了test()函數");
}else{
alert( test.caller + "函數調用了test()函數");
}
};
test(); // JavaScript頂層作用域調用了test()函數
function callTest(){
test();
}
callTest(); // function callTest(){ test(); }函數調用了test()函數
function callTest2(){
// setTimeout()或setInterval()中定時執行的函數也屬於頂層作用域調用
setTimeout(test, 5000); // JavaScript頂層作用域調用了test()函數
}
callTest2();
valueOf 需要返回對象的原始值
備註:js對象中的valueOf()方法和toString()方法非常類似,但是,當需要返回對象的原始值而非字符串的時候才調用它,尤其是轉換爲數字的時候。如果在需要使用原始值的上下文中使用了對象,JavaScript就會自動調用valueOf()方法。
const o = {a: 1, valueOf: function(){ return 123123 } }
Number(o) //123123
// 給大家出一個題
const o2 = {
x: 1,
valueOf: function(){
return this.x++
}
}
if(o2 == 1 && o2 == 2 && o2 == 3){
console.log('down')
console.log(o2.x)
}else{
console.log('faild')
}
// Array:返回數組對象本身
var array = ["CodePlayer", true, 12, -5];
array.valueOf() === array; // true
// Date:當前時間距1970年1月1日午夜的毫秒數
var date = new Date(2013, 7, 18, 23, 11, 59, 230);
date.valueOf() // 1376838719230
// Number:返回數字值
var num = 15.26540;
num.valueOf() // 15.2654
// 布爾:返回布爾值true或false
var bool = true;
bool.valueOf() === bool // true
// new一個Boolean對象
var newBool = new Boolean(true);
// valueOf()返回的是true,兩者的值相等
newBool.valueOf() == newBool // true
// 但是不全等,兩者類型不相等,前者是boolean類型,後者是object類型
newBool.valueOf() === newBool // false
// Function:返回函數本身
function foo(){
}
foo.valueOf() === foo // true
var foo2 = new Function("x", "y", "return x + y;");
foo2.valueOf() === foo2 // true
// Object:返回對象本身
var obj = {name: "張三", age: 18};
obj.valueOf() === obj // true
// String:返回字符串值
var str = "http://www.365mini.com";
str.valueOf() === str // true
// new一個字符串對象
var str2 = new String("http://www.365mini.com");
// 兩者的值相等,但不全等,因爲類型不同,前者爲string類型,後者爲object類型
str2.valueOf() === str2 // false
getOwnPropertySymbols在給定對象自身上找到的所有 Symbol 屬性的數組。
var obj = {};
var a = Symbol("a");
var b = Symbol.for("b");
obj[a] = "localSymbol";
obj[b] = "globalSymbol";
var objectSymbols = Object.getOwnPropertySymbols(obj);
console.log(objectSymbols.length); // 2
console.log(objectSymbols) // [Symbol(a), Symbol(b)]
console.log(objectSymbols[0]) // Symbol(a)
toString toLocalString
toString 方法不做過多介紹
區別:
當被轉化的值是個時間對象時,toLocaleString會將轉化的結果以本地表示。
(new Date).toString(); //"Mon Nov 06 2017 13:02:46 GMT+0800 (China Standard Time)"
(new Date).toLocaleString(); //"2017/11/6 下午1:03:12"
另外當被轉化的值是個時間戳時,toLocaleString會把時間戳每三位添加一個逗號,代碼如下。
(Date.parse(new Date())).toLocaleString() //"1,509,944,637,000"
(Date.parse(new Date())).toString() //"1509944643000"
call apply bind 大家自己回去研究
length
Object.length //1
name
Object.name //"Object"