【前端基礎進階】JS-Object 功能詳解
Object.assign(target,source1,source2,...)
該方法主要用於物件的合併,將源物件source的所有可列舉屬性合併到目標物件target上,此方法只拷貝源物件的自身屬性,不拷貝繼承的屬性。
Object.assign方法實行的是淺拷貝,而不是深拷貝。也就是說,如果源物件某個屬性的值是物件,那麼目標物件拷貝得到的是這個物件的引用。同名屬性會替換。
Object.assign只能進行值的複製,如果要複製的值是一個取值函式,那麼將求值後再複製。
Object.assign可以用來處理陣列,但是會把陣列視為物件。
const target = { x : 0, y : 1 }; const source = { x : 1, z : 2 , fn : { number : 1 } }; Object.assign(target, source); // target{x : 1, y : 1, z : 2, fn : {number : 1}}// 同名屬性會被覆蓋 // source{x : 1, z : 2, fn : {number : 1}} target.fn.number = 2;// 拷貝為物件引用 // source{x : 1, z : 2, fn : {number : 2}} function Person(){ this.name = 1 }; Person.prototype.country = 'china'; let student = new Person(); student.age = 29 ; const young = {insterst : 'sport'}; Object.assign(young,student); // young {instest : 'sport' , age : 29, name: 1}// 只能拷貝自身的屬性,不能拷貝prototype Object.assign([1, 2, 3], [4, 5])// 把陣列當作物件來處理 // [4, 5, 3]
Object.create(prototype[,propertiesObject])
使用指定的原型物件及其屬性去建立一個新的物件
var parent = { x : 1, y : 1 } var child = Object.create(parent,{ z : {// z會成為建立物件的屬性 writable:true, configurable:true, value: "newAdd" } }); console.log(child)
Object.defineProperties(obj,props)
直接在一個物件上定義新的屬性或修改現有屬性,並返回該物件。
var obj = {}; Object.defineProperties(obj, { 'property1': { value: true, writable: true }, 'property2': { value: 'Hello', writable: false } // etc. etc. }); console.log(obj)// {property1: true, property2: "Hello"}
Object.defineProperty(obj,prop,descriptor)
在一個物件上定義一個新屬性,或者修改一個物件的現有屬性, 並返回這個物件。
Object.defineProperty(obj, 'is', { value: function(x, y) { if (x === y) { // 針對+0 不等於 -0的情況 return x !== 0 || 1 / x === 1 / y; } // 針對NaN的情況 return x !== x && y !== y; }, configurable: true, //是否可刪除 enumerable: false, //是否可forin列舉 writable: true //是否為只讀 }); console.log(obj) // 注意不能同時設定(writable,value) 和 get,set方法,否則瀏覽器會報錯 : Invalid property descriptor. Cannot both specify accessors and a value or writable attribute
Object.getOwnPropertyDescriptor()
功能:
該方法返回指定物件上一個自有屬性對應的屬性描述符。(自有屬性指的是直接賦予該物件的屬性,不需要從原型鏈上進行查詢的屬性)
語法: Object.getOwnPropertyDescriptor(obj, prop)
obj: 需要查詢的目標物件
prop: 目標物件內屬性名稱
var person = { name: '張三', age: 18 } var desc = Object.getOwnPropertyDescriptor(person, 'name'); console.log(desc)結果如下 // { //configurable: true, //enumerable: true, //writable: true, //value: "張三" // }
ps
Object的defineProperty和defineProperties這兩個方法在js中的重要性十分重要,主要功能就是用來定義或修改這些內部屬性,與之相對應的getOwnPropertyDescriptor和getOwnPropertyDescriptors就是獲取這行內部屬性的描述。
例如
在物件中新增存取描述符屬性 var obj = {}; var aValue; //如果不初始化變數, 不給下面的a屬性設定值,直接讀取會報錯aValue is not defined var b; Object.defineProperty(obj, 'a', { configurable : true, enumerable : true, get: function() { return aValue }, set: function(newValue) { aValue = newValue; b = newValue + 1 } }) console.log(b) // undefined console.log(obj.a)// undefined, 當讀取屬性值時,呼叫get方法,返回undefined obj.a = 2;// 當設定屬性值時,呼叫set方法,aValue為2 console.log(obj.a) // 2讀取屬性值,呼叫get方法,此時aValue為2 console.log(b) // 3再給obj.a賦值時,執行set方法,b的值被修改為2,額外說一句,vue中的計算屬性就是利用setter來實現的
vue的核心正是如此
簡易的資料雙向繫結
html程式碼:
<body> <p> input1=><input type="text" id="input1"> </p> <p> input2=> <input type="text" id="input2"> </p> <div> 我每次比input1的值加1=> <span id="span"></span> </div> </body> js程式碼: var oInput1 = document.getElementById('input1'); var oInput2 = document.getElementById('input2'); var oSpan = document.getElementById('span'); var obj = {}; Object.defineProperties(obj, { val1: { configurable: true, get: function() { oInput1.value = 0; oInput2.value = 0; oSpan.innerHTML = 0; return 0 }, set: function(newValue) { oInput2.value = newValue; oSpan.innerHTML = Number(newValue) ? Number(newValue) : 0 } }, val2: { configurable: true, get: function() { oInput1.value = 0; oInput2.value = 0; oSpan.innerHTML = 0; return 0 }, set: function(newValue) { oInput1.value = newValue; oSpan.innerHTML = Number(newValue)+1; } } }) oInput1.value = obj.val1; oInput1.addEventListener('keyup', function() { obj.val1 = oInput1.value; }, false) oInput2.addEventListener('keyup', function() { obj.val2 = oInput2.value; }, false)
Object.keys(obj)
返回一個由一個給定物件的自身可列舉屬性組成的陣列,陣列中屬性名的排列順序和使用 for...in 迴圈遍歷該物件時返回的順序一致 (兩者的主要區別是 一個 for-in 迴圈還會列舉其原型鏈上的屬性)。
let arr = ["a", "b", "c"]; console.log(Object.keys(arr)); // ['0', '1', '2'] /* Object 物件 */ let obj = { foo: "bar", baz: 42 }, keys = Object.keys(obj); console.log(keys); // ["foo","baz"]
Object.values()
方法返回一個給定物件自己的所有可列舉屬性值的陣列,值的順序與使用for...in迴圈的順序相同 ( 區別在於 for-in 迴圈列舉原型鏈中的屬性 )。
Object.values會過濾屬性名為 Symbol 值的屬性。
var an_obj = { 100: 'a', 2: 'b', 7: 'c' }; console.log(Object.values(an_obj)); // ['b', 'c', 'a'] var obj = { 0: 'a', 1: 'b', 2: 'c' }; console.log(Object.values(obj)); // ['a', 'b', 'c']
Object.entries()
返回一個給定物件自身可列舉屬性的鍵值對陣列,其排列與使用 for...in 迴圈遍歷該物件時返回的順序一致(區別在於 for-in 迴圈也列舉原型鏈中的屬性)。
const obj = { foo: 'bar', baz: 42 }; console.log(Object.entries(obj)); // [ ['foo', 'bar'], ['baz', 42] ] const simuArray = { 0: 'a', 1: 'b', 2: 'c' }; console.log(Object.entries(simuArray)); // [ ['0', 'a'], ['1', 'b'], ['2', 'c'] ]
hasOwnProperty() 判斷物件自身屬性中是否具有指定的屬性。
Object.getOwnPropertyDescriptor(obj,prop)
返回指定物件上一個自有屬性對應的屬性描述符。(自有屬性指的是直接賦予該物件的屬性,不需要從原型鏈上進行查詢的屬性).
如果指定的屬性存在於物件上,則返回其屬性描述符物件(property descriptor),否則返回 undefined。
var arr = ['name','age'] ; arr.forEach(val => console.log(Object.getOwnPropertyDescriptor(obj,val))) // {value: "js", writable: true, enumerable: true, configurable: true} // undefined
Object.getOwnPropertyDescriptors(obj)
獲取一個物件的所有自身屬性的描述符。
var obj = { name : 'js', age : 20 } console.log(Object.getOwnPropertyDescriptors(obj)) const source = { set foo(value) { console.log(value); } }; const target2 = {}; Object.defineProperties(target2, Object.getOwnPropertyDescriptors(source)); Object.getOwnPropertyDescriptor(target2, 'foo') const obj = Object.create( some_obj, Object.getOwnPropertyDescriptors({ foo: 123, }) );
Object.getOwnPropertyNames()
返回一個由指定物件的所有自身屬性的屬性名(包括不可列舉屬性但不包括Symbol值作為名稱的屬性)組成的陣列。
var obj = { 0: "a", 1: "b", 2: "c"}; Object.getOwnPropertyNames(obj).forEach(function(val) { console.log(val); }); var obj = { x : 1, y : 2 } Object.defineProperty(obj,'z',{ enumerable : false }) console.log(Object.getOwnPropertyNames(obj))// ["x", "y", "z"] 包含不可列舉屬性 。 console.log(Object.keys(obj))// ["x", "y"]只包含可列舉屬性 。
Object.getOwnPropertySymbols()
返回一個給定物件自身的所有 Symbol 屬性的陣列。
Object.getPrototypeOf()
返回指定物件的原型(內部[[Prototype]]屬性的值,即__proto__,而非物件的prototype)。
Object.isPrototypeOf()
判斷一個物件是否存在於另一個物件的原型鏈上。
Object.setPrototypeOf(obj,prototype)
設定物件的原型物件
Object.is()
判斷兩個值是否相同。
如果下列任何一項成立,則兩個值相同:
兩個值都是 undefined
兩個值都是 null
兩個值都是 true 或者都是 false
兩個值是由相同個數的字元按照相同的順序組成的字串
兩個值指向同一個物件
兩個值都是數字並且
都是正零 +0
都是負零 -0
都是 NaN
都是除零和 NaN 外的其它同一個數字
Object.is('foo', 'foo');// true Object.is(window, window);// true Object.is('foo', 'bar');// false Object.is([], []);// false var test = { a: 1 }; Object.is(test, test);// true Object.is(null, null);// true // 特例 Object.is(0, -0);// false Object.is(-0, -0);// true Object.is(NaN, 0/0);// true
Object.freeze()
凍結一個物件,凍結指的是不能向這個物件新增新的屬性,不能修改其已有屬性的值,不能刪除已有屬性,以及不能修改該物件已有屬性的可列舉性、可配置性、可寫性。也就是說,這個物件永遠是不可變的。該方法返回被凍結的物件。
var obj = { prop: function() {}, foo: 'bar' }; // 新的屬性會被新增, 已存在的屬性可能 // 會被修改或移除 obj.foo = 'baz'; obj.lumpy = 'woof'; delete obj.prop; // 作為引數傳遞的物件與返回的物件都被凍結 // 所以不必儲存返回的物件(因為兩個物件全等) var o = Object.freeze(obj); o === obj; // true Object.isFrozen(obj); // === true // 現在任何改變都會失效 obj.foo = 'quux'; // 靜默地不做任何事 // 靜默地不新增此屬性 obj.quaxxor = 'the friendly duck'; console.log(obj)
Object.isFrozen()
判斷一個物件是否被凍結 .
Object.preventExtensions()
物件不能再新增新的屬性。可修改,刪除現有屬性,不能新增新屬性。
var obj = { name :'lilei', age : 30 , sex : 'male' } obj = Object.preventExtensions(obj); console.log(obj);// {name: "lilei", age: 30, sex: "male"} obj.name = 'haha'; console.log(obj)// {name: "haha", age: 30, sex: "male"} delete obj.sex ; console.log(obj);// {name: "haha", age: 30} obj.address= 'china'; console.log(obj)// {name: "haha", age: 30}
Object.isExtensible()
判斷物件是否是可擴充套件的,Object.preventExtensions,Object.seal 或 Object.freeze 方法都可以標記一個物件為不可擴充套件(non-extensible)
Object.seal()
Object.seal() 方法可以讓一個物件密封,並返回被密封后的物件。密封一個物件會讓這個物件變的不能新增新屬性,且所有已有屬性會變的不可配置。屬性不可配置的效果就是屬性變的不可刪除,以及一個數據屬性不能被重新定義成為訪問器屬性,或者反之。但屬性的值仍然可以修改。嘗試刪除一個密封物件的屬性或者將某個密封物件的屬性從資料屬性轉換成訪問器屬性,結果會靜默失敗或丟擲TypeError 異常. 不會影響從原型鏈上繼承的屬性。但 proto ( ) 屬性的值也會不能修改。
var obj = { prop: function () {}, foo: "bar" }; // 可以新增新的屬性,已有屬性的值可以修改,可以刪除 obj.foo = "baz"; obj.lumpy = "woof"; delete obj.prop; var o = Object.seal(obj); assert(o === obj); assert(Object.isSealed(obj) === true); // 仍然可以修改密封物件上的屬性的值. obj.foo = "quux"; // 但你不能把一個數據屬性重定義成訪問器屬性. Object.defineProperty(obj, "foo", { get: function() { return "g"; } }); // 丟擲TypeError異常 // 現在,任何屬性值以外的修改操作都會失敗. obj.quaxxor = "the friendly duck"; // 靜默失敗,新屬性沒有成功新增 delete obj.foo; // 靜默失敗,屬性沒有刪除成功 // ...在嚴格模式中,會丟擲TypeError異常 function fail() { "use strict"; delete obj.foo; // 丟擲TypeError異常 obj.sparky = "arf"; // 丟擲TypeError異常 } fail(); // 使用Object.defineProperty方法同樣會丟擲異常 Object.defineProperty(obj, "ohai", { value: 17 }); // 丟擲TypeError異常 Object.defineProperty(obj, "foo", { value: "eit" }); // 成功將原有值改變
Object.isSealed()
判斷一個物件是否被密封