語法:數組
Object.defineProperty(obj, prop, descriptor)
參數說明:函數
obj:必需。目標對象
prop:必需。需定義或修改的屬性的名字
descriptor:必需。目標屬性所擁有的特性測試
返回值:this
傳入函數的對象。即第一個參數objspa
針對屬性,咱們能夠給這個屬性設置一些特性,好比是否只讀不能夠寫;是否能夠被for..in或Object.keys()遍歷。code
給對象的屬性添加特性描述,目前提供兩種形式:數據描述和存取器描述。對象
當修改或定義對象的某個屬性的時候,給這個屬性添加一些特性:blog
var obj = { test:"hello" } //對象已有的屬性添加特性描述 Object.defineProperty(obj,"test",{ configurable:true | false, enumerable:true | false, value:任意類型的值, writable:true | false }); //對象新添加的屬性的特性描述 Object.defineProperty(obj,"newKey",{ configurable:true | false, enumerable:true | false, value:任意類型的值, writable:true | false });
數據描述中的屬性都是可選的,來看一下設置每個屬性的做用。繼承
屬性對應的值,能夠使任意類型的值,默認爲undefined索引
var obj = {} //第一種狀況:不設置value屬性 Object.defineProperty(obj,"newKey",{ }); console.log( obj.newKey ); //undefined ------------------------------ //第二種狀況:設置value屬性 Object.defineProperty(obj,"newKey",{ value:"hello" }); console.log( obj.newKey ); //hello
屬性的值是否能夠被重寫。設置爲true能夠被重寫;設置爲false,不能被重寫。默認爲false。
var obj = {} //第一種狀況:writable設置爲false,不能重寫。 Object.defineProperty(obj,"newKey",{ value:"hello", writable:false }); //更改newKey的值 obj.newKey = "change value"; console.log( obj.newKey ); //hello //第二種狀況:writable設置爲true,能夠重寫 Object.defineProperty(obj,"newKey",{ value:"hello", writable:true }); //更改newKey的值 obj.newKey = "change value"; console.log( obj.newKey ); //change value
此屬性是否能夠被枚舉(使用for...in或Object.keys())。設置爲true能夠被枚舉;設置爲false,不能被枚舉。默認爲false。
var obj = {} //第一種狀況:enumerable設置爲false,不能被枚舉。 Object.defineProperty(obj,"newKey",{ value:"hello", writable:false, enumerable:false }); //枚舉對象的屬性 for( var attr in obj ){ console.log( attr ); } //第二種狀況:enumerable設置爲true,能夠被枚舉。 Object.defineProperty(obj,"newKey",{ value:"hello", writable:false, enumerable:true }); //枚舉對象的屬性 for( var attr in obj ){ console.log( attr ); //newKey }
是否能夠刪除目標屬性或是否能夠再次修改屬性的特性(writable, configurable, enumerable)。設置爲true能夠被刪除或能夠從新設置特性;設置爲false,不能被能夠被刪除或不能夠從新設置特性。默認爲false。
這個屬性起到兩個做用:
目標屬性是否能夠使用delete刪除
目標屬性是否能夠再次設置特性
//-----------------測試目標屬性是否能被刪除------------------------ var obj = {} //第一種狀況:configurable設置爲false,不能被刪除。 Object.defineProperty(obj,"newKey",{ value:"hello", writable:false, enumerable:false, configurable:false }); //刪除屬性 delete obj.newKey; console.log( obj.newKey ); //hello //第二種狀況:configurable設置爲true,能夠被刪除。 Object.defineProperty(obj,"newKey",{ value:"hello", writable:false, enumerable:false, configurable:true }); //刪除屬性 delete obj.newKey; console.log( obj.newKey ); //undefined //-----------------測試是否能夠再次修改特性------------------------ var obj = {} //第一種狀況:configurable設置爲false,不能再次修改特性。 Object.defineProperty(obj,"newKey",{ value:"hello", writable:false, enumerable:false, configurable:false }); //從新修改特性 Object.defineProperty(obj,"newKey",{ value:"hello", writable:true, enumerable:true, configurable:true }); console.log( obj.newKey ); //報錯:Uncaught TypeError: Cannot redefine property: newKey //第二種狀況:configurable設置爲true,能夠再次修改特性。 Object.defineProperty(obj,"newKey",{ value:"hello", writable:false, enumerable:false, configurable:true }); //從新修改特性 Object.defineProperty(obj,"newKey",{ value:"hello", writable:true, enumerable:true, configurable:true }); console.log( obj.newKey ); //hello
除了能夠給新定義的屬性設置特性,也能夠給已有的屬性設置特性
//定義對象的時候添加的屬性,是可刪除、可重寫、可枚舉的。 var obj = { test:"hello" } //改寫值 obj.test = 'change value'; console.log( obj.test ); //'change value' Object.defineProperty(obj,"test",{ writable:false }) //再次改寫值 obj.test = 'change value again'; console.log( obj.test ); //依然是:'change value'
提示:一旦使用Object.defineProperty給對象添加屬性,那麼若是不設置屬性的特性,那麼configurable、enumerable、writable這些值都爲默認的false
var obj = {}; //定義的新屬性後,這個屬性的特性中configurable,enumerable,writable都爲默認的值false //這就致使了neykey這個是不能重寫、不能枚舉、不能再次設置特性 // Object.defineProperty(obj,'newKey',{ }); //設置值 obj.newKey = 'hello'; console.log(obj.newKey); //undefined //枚舉 for( var attr in obj ){ console.log(attr); }
設置的特性總結:
value: 設置屬性的值
writable: 值是否能夠重寫。true | false
enumerable: 目標屬性是否能夠被枚舉。true | false
configurable: 目標屬性是否能夠被刪除或是否能夠再次修改特性 true | false
當使用存取器描述屬性的特性的時候,容許設置如下特性屬性:
var obj = {}; Object.defineProperty(obj,"newKey",{ get:function (){} | undefined, set:function (value){} | undefined configurable: true | false enumerable: true | false });
注意:當使用了getter或setter方法,不容許使用writable和value這兩個屬性
當設置或獲取對象的某個屬性的值的時候,能夠提供getter/setter方法。
getter 是一種得到屬性值的方法
setter是一種設置屬性值的方法。
在特性中使用get/set屬性來定義對應的方法。
var obj = {}; var initValue = 'hello'; Object.defineProperty(obj,"newKey",{ get:function (){ //當獲取值的時候觸發的函數 return initValue; }, set:function (value){ //當設置值的時候觸發的函數,設置的新值經過參數value拿到 initValue = value; } }); //獲取值 console.log( obj.newKey ); //hello //設置值 obj.newKey = 'change value'; console.log( obj.newKey ); //change value
注意:get或set不是必須成對出現,任寫其一就能夠。若是不設置方法,則get和set的默認值爲undefined
configurable和enumerable同上面的用法。
——————————————————————————————————————————————————————
基本用法
Object.assign方法用於對象的合併,將源對象( source )的全部可枚舉屬性,複製到目標對象( target )。
var target = { a: 1, b: 1 }; var source1 = { b: 2, c: 2 }; var source2 = { c: 3 }; Object.assign(target, source1, source2); target // {a:1, b:2, c:3}
若是隻有一個參數,Object.assign會直接返回該參數。
var obj = {a: 1}; Object.assign(obj) === obj // true
若是該參數不是對象,則會先轉成對象,而後返回。
typeof Object.assign(2) // "object"
因爲undefined和null沒法轉成對象,因此若是它們做爲參數,就會報錯。
Object.assign(undefined) // 報錯 Object.assign(null) // 報錯
若是非對象參數出如今源對象的位置(即非首參數),那麼處理規則有所不一樣。首先,這些參數都會轉成對象,若是沒法轉成對象,就會跳過。這意味着,若是undefined和null不在首參數,就不會報錯。
let obj = {a: 1}; Object.assign(obj, undefined) === obj // true Object.assign(obj, null) === obj // true
其餘類型的值(即數值、字符串和布爾值)不在首參數,也不會報錯。可是,除了字符串會以數組形式,拷貝入目標對象,其餘值都不會產生效果。
var v1 = 'abc'; var v2 = true; var v3 = 10; var obj = Object.assign({}, v1, v2, v3); console.log(obj); // { "0": "a", "1": "b", "2": "c" }
上面代碼中,v一、v二、v3分別是字符串、布爾值和數值,結果只有字符串合入目標對象(以字符數組的形式),數值和布爾值都會被忽略。這是由於只有字符串的包裝對象,會產生可枚舉屬性。
Object(true) // {[[PrimitiveValue]]: true} Object(10) // {[[PrimitiveValue]]: 10} Object('abc') // {0: "a", 1: "b", 2: "c", length: 3, [[PrimitiveValue]]: "abc"}
上面代碼中,布爾值、數值、字符串分別轉成對應的包裝對象,能夠看到它們的原始值都在包裝對象的內部屬性[[PrimitiveValue]]上面,這個屬性是不會被Object.assign拷貝的。只有字符串的包裝對象,會產生可枚舉的實義屬性,那些屬性則會被拷貝。
Object.assign拷貝的屬性是有限制的,只拷貝源對象的自身屬性(不拷貝繼承屬性),也不拷貝不可枚舉的屬性(enumerable: false)。
Object.assign({b: 'c'}, Object.defineProperty({}, 'invisible', { enumerable: false, value: 'hello' }) ) // { b: 'c' }
上面代碼中,Object.assign要拷貝的對象只有一個不可枚舉屬性invisible,這個屬性並無被拷貝進去。
屬性名爲 Symbol 值的屬性,也會被Object.assign拷貝。
Object.assign({ a: 'b' }, { [Symbol('c')]: 'd' }) // { a: 'b', Symbol(c): 'd' }
——————————————————————————————————————————————
傳入對象,返回屬性名
var obj = {'a':'123','b':'345'}; console.log(Object.keys(obj)); //['a','b'] var obj1 = { 100: "a", 2: "b", 7: "c"}; console.log(Object.keys(obj1)); // console: ["2", "7", "100"] var obj2 = Object.create({}, { getFoo : { value : function () { return this.foo } } }); obj2.foo = 1; console.log(Object.keys(obj2)); // console: ["foo"]
構造函數 返回空數組或者屬性名
function Pasta(name, age, gender) { this.name = name; this.age = age; this.gender = gender; this.toString = function () { return (this.name + ", " + this.age + ", " + this.gender); } } console.log(Object.keys(Pasta)); //console: [] var spaghetti = new Pasta("Tom", 20, "male"); console.log(Object.keys(spaghetti)); //console: ["name", "age", "gender", "toString"]
數組 返回索引
var arr = ["a", "b", "c"]; console.log(Object.keys(arr)); // console: ["0", "1", "2"]
傳入字符串,返回索引
var str = 'ab1234'; console.log(Object.keys(obj)); //[0,1,2,3,4,5]