摘要:返回值在指定原型對(duì)象上添加新屬性后的對(duì)象。該方法返回值被用作屬性值。這個(gè)方法返回值就是屬性存取表達(dá)式返回的值。
走在前端的大道上
最后更新 2018.12.27
本篇將自己讀過的相關(guān) javascript Object方法 文章中,對(duì)自己有啟發(fā)的章節(jié)片段總結(jié)在這(會(huì)對(duì)原文進(jìn)行刪改),會(huì)不斷豐富提煉總結(jié)更新。
1.Object.keys遍歷返回一個(gè)數(shù)組,包括對(duì)象自身的(不含繼承的)所有可枚舉屬性
示例代碼:
(1) 數(shù)組Array對(duì)象(返回索引值)
var arr=[1,2,3]; Object.keys(arr) // ["0", "1", "2”]
(2) object對(duì)象(返回key值)
var obj = { foo: "bar", baz: 42 }; Object.keys(obj) // ["foo", "baz”]
(3) 類數(shù)組,對(duì)象
var obj = { 0 : "a", 1 : "b", 2 : "c”}; Object.keys(obj) // ["0", "1", "2"]
(4) 類數(shù)組對(duì)象 隨機(jī)key排序
var Obj = { 100: "a’, 2: "b’,7: "c’ }; console.log(Object.keys(Obj)); // ["2", "7", "100’]. 返回從小到大排序后的結(jié)果
(5) Object.keys僅遍歷對(duì)象本身,并將所有可枚舉的屬性組合成一個(gè)數(shù)組返回
var Person = function({name="none", age=18, height=170}={}){ this.name = name; this.age = age; this.height = height; } Person.prototype = { type: "Animal" } var qiu = new Person() // 將height屬性設(shè)置為 不可枚舉 Object.defineProperty(qiu, "height", { enumerable: false }) var keys = Object.keys(qiu); console.log(keys) // output: ["name", "age"]
(6) 將鍵值類型的查詢param轉(zhuǎn)換成url的query
const searchObj = { title: "javascript", author: "Nicolas", publishing: "O"RELLY", language: "cn" } let searchStr = Object.keys(searchObj) .map(item => `${item}=${searchObj[item]}`) .join("&"); let url = `localhost:8080/api/test?${searchStr}`
遍歷鍵值對(duì)的數(shù)據(jù)時(shí),使用Object.keys真是不二之選。
2.Object.values()方法返回一個(gè)給定對(duì)象自己的所有可枚舉屬性值的數(shù)組,值的順序與使用for..in循環(huán)相同,返回的對(duì)象的value值,與Object.key()相反
(1) 正常對(duì)象
var obj={a:1,b:2,c:3}; console.log(Object.values(obj)) // [1, 2, 3]
(2) 類數(shù)組對(duì)象
var obj ={0:"a",1:"b",2:"c"}; console.log(Object.values(obj)). // [a,b,c]
(3) key值為無序number
var obj={100:"a",10:"b",1:"1"}; console.log(Object.values(obj)). // ["1", "b", "a"]3.Object.getOwnPropertyNames遍歷
返回一個(gè)數(shù)組,包含對(duì)象自身(不含繼承)的所有屬性名
示例代碼:
var Person = function({name="none", age=18, height=170}={}){ this.name = name; this.age = age; this.height = height; } Person.prototype = { type: "Animal" } var qiu = new Person() // 將height屬性設(shè)置為 不可枚舉 Object.defineProperty(qiu, "height", { enumerable: false }) var keys = Object.getOwnPropertyNames(qiu); console.log(keys) // output: ["name", "age", "height"]
與Object.keys的區(qū)別在于Object.getOwnPropertyNames會(huì)把不可枚舉的屬性也返回。除此之外,與Object.keys的表現(xiàn)一致。
3.Object.getPrototypeOf()javascript中提供Object.getPrototypeOf()方法來獲得對(duì)象的直接原型。
function Person() { this.name = "sillywa" } var person1 = new Person() Object.getPrototypeOf(person1) // {constructor: ? Person()} Object.getPrototypeOf(person1.__proto__) // Object.prototype var person = { name: "sillywa" } var person2 = Object.create(person) Object.getPrototypeOf(person2) // {name: "sillywa"}
javascript有以下幾種方法檢測(cè)一個(gè)對(duì)象的原型:
isPrototypeOf():檢測(cè)一個(gè)對(duì)象是否是另一個(gè)對(duì)象的原型
obj.constructor.prototype:檢測(cè)非Object.create()創(chuàng)建的對(duì)象的原型
var obj1 = { name: "sillywa" } var obj2 = Object.create(obj1) // isPrototypeOf()方法 Object.prototype.isPrototypeOf(obj1) // true obj1.isPrototypeOf(obj2) // true Object.prototype.isPrototypeOf(obj2) // true // obj.constructor.prototype obj1.constructor.prototype === Object.prototype // true // obj1是obj2的原型,以下等式應(yīng)為true obj2.constructor.prototype === obj1 // false // 而實(shí)際上 obj2.constructor.prototype === Object.prototype // true
以上代碼中obj1是obj2的原型,obj2.constructor.prototype === obj1應(yīng)為true但是實(shí)際上卻是false,因?yàn)?b>obj2的__proto__里面并沒有一個(gè)constructor屬性,obj2.constructor實(shí)際上是obj1的__proto__里面的constructor,所以obj2.constructor.prototype === Object.prototype。
4.Object.assign()Object.assign()方法用于將所有可枚舉屬性的值從一個(gè)或多個(gè)源對(duì)象復(fù)制到目標(biāo)對(duì)象,它將返回目標(biāo)對(duì)象,但是 Object.assign() 進(jìn)行的是淺拷貝,拷貝的是對(duì)象的屬性的引用,而不是對(duì)象本身。
Object.assign(target, ...sources)
參數(shù):
target:目標(biāo)對(duì)象;
sources:源對(duì)象;
返回值:目標(biāo)對(duì)象
(1) 用來復(fù)制一個(gè)新對(duì)象,并不會(huì)影響原對(duì)象
var obj = { a: 1 }; var copy = Object.assign({}, obj); console.log(copy); // { a: 1 }
(2) 用來合并對(duì)象屬性,將源對(duì)象的所有可枚舉屬性,復(fù)制到目標(biāo)對(duì)象
//object.assign(obj, obj2) obj2是源對(duì)象,obj 是目標(biāo)對(duì)象,返回目標(biāo)對(duì)象 var obj = { a: 1 }; var obj2={b:2}; console.log(Object.assign(obj,obj2)===obj); //true,返回目標(biāo)對(duì)象 console.log(obj); //{a:1,b:2} obj的值已被更改
(3) 如果目標(biāo)對(duì)象和源對(duì)象中有相同的鍵,則屬性將被源對(duì)象的屬性覆蓋,后面的源屬性會(huì)覆蓋之前的相同鍵的源屬性
var obj = { a: 1 }; var obj2 = {a:5,b:2}; var obj3 = {b:1,d:0}; Object.assign(obj,obj2,obj3); console.log(obj); // {a: 5, b: 1, d: 0}
obj和obj2同時(shí)擁有相同的鍵a,但兩個(gè)值不同,obj是目標(biāo)對(duì)象,所以會(huì)被源對(duì)象obj2的值覆蓋,obj2和obj3也同時(shí)擁有相同的鍵b,在拷貝時(shí),obj3排在obj2的后面,所以obj2被覆蓋 ,最終打印結(jié)果是:{a:5,b:1,d:0}
(4) 當(dāng)assign只有一個(gè)對(duì)象時(shí),則直接返回這個(gè)對(duì)象,不做任何操作
var obj = { a: 1 } Object.assign(obj); console.log(obj); //{a:1}
(5) Object.assign()方法實(shí)行的是淺拷貝,而不是深拷貝
也就是說,如果源對(duì)象某個(gè)屬性的值是對(duì)象,那么目標(biāo)對(duì)象拷貝得到的是這個(gè)對(duì)象的引用
var obj1 = { a: 0 , b: { c: 0}}; var obj2 = Object.assign({}, obj1); obj1.b.c=5; console.log(obj2) //{a:0,b:{c:5}};
當(dāng)我們?cè)诟淖僶bj1的值時(shí),并沒有想改變obj2,但obj2的值也發(fā)生了改變,這違背了我們的想法。
(6)深拷貝
var obj1 = { a: 0 , b: { c: 0}}; var obj3 = JSON.parse(JSON.stringify(obj1)); obj1.a = 4; obj1.b.c = 4; console.log(obj3); //{ a: 0 , b: { c: 0}};5.Object.create()
Object.create() 方法會(huì)使用指定的原型對(duì)象及其屬性去創(chuàng)建一個(gè)新的對(duì)象。語法:
Object.create(proto[, propertiesObject])
參數(shù)proto 新創(chuàng)建對(duì)象的原型對(duì)象。
propertiesObject 可選。
如果沒有指定為 undefined,否則是要添加到新創(chuàng)建對(duì)象的可枚舉屬性(即其自身定義的屬性,而不是其原型鏈上的枚舉屬性)對(duì)象的屬性描述符以及相應(yīng)的屬性名稱。這些屬性對(duì)應(yīng)Object.defineProperties()的第二個(gè)參數(shù)。
在指定原型對(duì)象上添加新屬性后的對(duì)象。
例外如果proto參數(shù)不是 null 或一個(gè)對(duì)象,則拋出一個(gè) TypeError 異常。
使用 Object.create 的 propertyObject參數(shù)var o; // 創(chuàng)建一個(gè)原型為null的空對(duì)象 o = Object.create(null); o = {}; // 以字面量方式創(chuàng)建的空對(duì)象就相當(dāng)于: o = Object.create(Object.prototype); o = Object.create(Object.prototype, { // foo會(huì)成為所創(chuàng)建對(duì)象的數(shù)據(jù)屬性 foo: { writable:true, configurable:true, value: "hello" }, // bar會(huì)成為所創(chuàng)建對(duì)象的訪問器屬性 bar: { configurable: false, get: function() { return 10 }, set: function(value) { console.log("Setting `o.bar` to", value); } } }); function Constructor(){} o = new Constructor(); // 上面的一句就相當(dāng)于: o = Object.create(Constructor.prototype); // 當(dāng)然,如果在Constructor函數(shù)中有一些初始化代碼,Object.create不能執(zhí)行那些代碼 // 創(chuàng)建一個(gè)以另一個(gè)空對(duì)象為原型,且擁有一個(gè)屬性p的對(duì)象 o = Object.create({}, { p: { value: 42 } }) // 省略了的屬性特性默認(rèn)為false,所以屬性p是不可寫,不可枚舉,不可配置的: o.p = 24 o.p //42 o.q = 12 for (var prop in o) { console.log(prop) } //"q" delete o.p //false //創(chuàng)建一個(gè)可寫的,可枚舉的,可配置的屬性p o2 = Object.create({}, { p: { value: 42, writable: true, enumerable: true, configurable: true } });
我們知道通過Object.create()創(chuàng)建的對(duì)象實(shí)際上等于將該對(duì)象的__proto__指向Object.create()里面的參數(shù)對(duì)象,那么當(dāng)涉及到原型時(shí)它是怎么工作的呢?
var a = { name: "sillywa" } var b = Object.create(a) b.__proto__ === Object.prototype // false b.__proto__ === a // true b.__proto__.constructor === Object // true b.__proto__.hasOwnProperty("constructor") // false
var b = Object.create(a)實(shí)際上是把b的__proto__指向了a。當(dāng)訪問b.constructor時(shí),實(shí)際上訪問的是b.__proto__.__proto__.constructor。
6.delete我們要明確一點(diǎn)刪除屬性的方法只有一個(gè)是 delete ,但是在我們的開發(fā)中我們有時(shí)往往將屬性值設(shè)為 null,undefined 就說成是將屬性刪除,這是不對(duì)的這樣做僅僅是取消了屬性和值之間的關(guān)聯(lián)。
我們可以通過 Object.hasOwnProperty() 這個(gè)方法來看一看;
let foo = { name: "foo", firstChild: "1st foo", twoChild: "2th foo" }; foo.name = undefined; // undefined foo.firstChild = null; // null delete foo.twoChild; // true for (let key in foo) { console.log("key:" + key + ", value:" + foo[key]); } /* key:name, value:undefined key:firstChild, value: null */
我們發(fā)現(xiàn)如果用 undefined 和 null 相當(dāng)于給屬性賦值,只有當(dāng)用 delete 才是刪除屬性。
注:定義屬性的名字時(shí)要使用一般的字符串而且是連續(xù)的字符串,屬性名的定義要避免JavaScript關(guān)鍵字,就像我們有的公司定的對(duì)象屬性的訪問用 [] , 對(duì)象的方法用 . 。
for … in 這個(gè)循環(huán)體來遍歷對(duì)象的屬性,包括對(duì)象原型鏈上的屬性。
let obj = {a:1, b:2, c:3} for (let key in obj) { console.log(obj[key]); } /* 1 2 3 */
// 自定義屬性是否可枚舉 function customObjectEnumerable(obj, prop, value, flag) { Object.defineProperty(obj, prop, { configurable: true, value: value, enumerable: flag, writable: true }); }; var obj = {}; customObjectEnumerable(obj, a, 1, false); customObjectEnumerable(obj, b, 2, false); for(let key in obj) {console.log(obj[key])} // undefined var obj2 = {}; customObjectEnumerable(obj2,"a", 1, true); customObjectEnumerable(obj2, "b", 2, true); for(let key in obj2) {console.log(obj2[key])} /* 1 2 */
function Foo() { this.name = "foo", this.age = "18" }; Foo.prototype.geAge = function() { console.log(this.name) }; function Bar() { this.name = "bar"; }; Bar.prototype = new Foo(); Bar.prototype.constructor = Bar; // 修正Bar.prototype.constructor 指向它本身 // 實(shí)例化Bar let myBar = new Bar(); "name" in myBar // true myBar.hasOwnProperty("name"); // true myBar.hasOwnProperty("age"); // false8.9.10.11
Object的defineProperty和defineProperties這兩個(gè)方法在js中的重要性十分重要,主要功能就是用來定義或修改這些內(nèi)部屬性,與之相對(duì)應(yīng)的getOwnPropertyDescriptor和getOwnPropertyDescriptors就是獲取這行內(nèi)部屬性的描述。
8.Object.defineProperty()Object.defineProperty() 方法會(huì)直接在一個(gè)對(duì)象上定義一個(gè)新屬性,或者修改一個(gè)對(duì)象的現(xiàn)有屬性, 并返回這個(gè)對(duì)象。
該方法允許精確添加或修改對(duì)象的屬性。通過賦值來添加的普通屬性會(huì)創(chuàng)建在屬性枚舉期間顯示的屬性(for...in 或 Object.keys 方法), 這些值可以被改變,也可以被刪除。這種方法允許這些額外的細(xì)節(jié)從默認(rèn)值改變。默認(rèn)情況下,使用Object.defineProperty()添加的屬性值是不可變的。
對(duì)象里目前存在的 屬性描述符有兩種主要形式:數(shù)據(jù)描述符和存取描述符。
數(shù)據(jù)描述符 是一個(gè)具有值的屬性,該值可能是可寫的,也可能不是可寫的。
存取描述符 是由getter-setter函數(shù)對(duì)描述的屬性。
描述符必須是這兩種形式之一;不能同時(shí)是兩者。
如果一個(gè)描述符同時(shí)設(shè)置了value,writable,get和set關(guān)鍵字,那么它將被認(rèn)為是一個(gè)數(shù)據(jù)描述符。如果一個(gè)描述符同時(shí)有value或writable和get或set關(guān)鍵字,將會(huì)產(chǎn)生一個(gè)異常。
數(shù)據(jù)描述符和存取描述符 均具有 以下可選鍵值:
configurable
當(dāng)且僅當(dāng)該屬性的 configurable 為 true 時(shí),該屬性描述符才能夠被改變,同時(shí)該屬性也能從對(duì)應(yīng)的對(duì)象上被刪除。默認(rèn)為 false。
enumerable
當(dāng)且僅當(dāng)該屬性的enumerable為true時(shí),該屬性才能夠出現(xiàn)在對(duì)象的枚舉屬性中。默認(rèn)為 false。
數(shù)據(jù)描述符同時(shí)具有以下可選鍵值:
value
該屬性對(duì)應(yīng)的值。可以是任何有效的 JavaScript 值(數(shù)值,對(duì)象,函數(shù)等)。默認(rèn)為 undefined。
writable
當(dāng)且僅當(dāng)該屬性的writable為true時(shí),value才能被賦值運(yùn)算符改變。默認(rèn)為 false。
存取描述符同時(shí)具有以下可選鍵值:
get
一個(gè)給屬性提供 getter 的方法,如果沒有 getter 則為 undefined。該方法返回值被用作屬性值。默認(rèn)為 undefined。
set
一個(gè)給屬性提供 setter 的方法,如果沒有 setter 則為 undefined。該方法將接受唯一參數(shù),并將該參數(shù)的新值分配給該屬性。默認(rèn)為 undefined。
語法
Object.defineProperty(obj, prop, descriptor)
參數(shù)
obj 要在其上定義屬性的對(duì)象。
prop 要定義或修改的屬性的名稱。
descriptor 將被定義或修改的屬性描述符。
返回值
被傳遞給函數(shù)的對(duì)象。
如果對(duì)象中不存在指定的屬性,Object.defineProperty()就創(chuàng)建這個(gè)屬性。當(dāng)描述符中省略某些字段時(shí),這些字段將使用它們的默認(rèn)值。擁有布爾值的字段的默認(rèn)值都是false。value,get和set字段的默認(rèn)值為undefined。一個(gè)沒有g(shù)et/set/value/writable定義的屬性被稱為“通用的”,并被“鍵入”為一個(gè)數(shù)據(jù)描述符。
var o = {}; // 創(chuàng)建一個(gè)新對(duì)象 // 在對(duì)象中添加一個(gè)屬性與數(shù)據(jù)描述符的示例 Object.defineProperty(o, "a", { value : 37, writable : true, enumerable : true, configurable : true }); // 對(duì)象o擁有了屬性a,值為37 // 在對(duì)象中添加一個(gè)屬性與存取描述符的示例 var bValue; Object.defineProperty(o, "b", { get : function(){ return bValue; }, set : function(newValue){ bValue = newValue; }, enumerable : true, configurable : true }); o.b = 38; // 對(duì)象o擁有了屬性b,值為38 // o.b的值現(xiàn)在總是與bValue相同,除非重新定義o.b // 數(shù)據(jù)描述符和存取描述符不能混合使用 Object.defineProperty(o, "conflict", { value: 0x9f91102, get: function() { return 0xdeadbeef; } }); // throws a TypeError: value appears only in data descriptors, get appears only in accessor descriptorsWritable 屬性
當(dāng)writable屬性設(shè)置為false時(shí),該屬性被稱為“不可寫”。它不能被重新分配。
var o = {}; // Creates a new object Object.defineProperty(o, "a", { value: 37, writable: false }); console.log(o.a); // logs 37 o.a = 25; // No error thrown console.log(o.a); // logs 37. The assignment didn"t work.Enumerable 特性
enumerable定義了對(duì)象的屬性是否可以在 for...in 循環(huán)和 Object.keys() 中被枚舉。
var o = {}; Object.defineProperty(o, "a", { value : 1, enumerable:true }); Object.defineProperty(o, "b", { value : 2, enumerable:false }); Object.defineProperty(o, "c", { value : 3 }); // enumerable defaults to false o.d = 4; // 如果使用直接賦值的方式創(chuàng)建對(duì)象的屬性,則這個(gè)屬性的enumerable為true for (var i in o) { console.log(i); } // 打印 "a" 和 "d" (in undefined order) Object.keys(o); // ["a", "d"] o.propertyIsEnumerable("a"); // true o.propertyIsEnumerable("b"); // false o.propertyIsEnumerable("c"); // false o.propertyIsEnumerable("d"); // trueConfigurable 特性
configurable特性表示對(duì)象的屬性是否可以被刪除,以及除writable特性外的其他特性是否可以被修改。
var o = {}; Object.defineProperty(o, "a", { get : function(){return 1;}, configurable : false } ); // throws a TypeError Object.defineProperty(o, "a", {configurable : true}); // throws a TypeError Object.defineProperty(o, "a", {enumerable : true}); // throws a TypeError (set was undefined previously) Object.defineProperty(o, "a", {set : function(){}}); // throws a TypeError (even though the new get does exactly the same thing) Object.defineProperty(o, "a", {get : function(){return 1;}}); // throws a TypeError Object.defineProperty(o, "a", {value : 12}); console.log(o.a); // logs 1 delete o.a; // Nothing happens console.log(o.a); // logs 1
如果o.a的configurable屬性為true,則不會(huì)拋出任何錯(cuò)誤,并且該屬性將在最后被刪除
添加多個(gè)屬性和默認(rèn)值考慮特性被賦予的默認(rèn)特性值非常重要,通常,使用點(diǎn)運(yùn)算符和Object.defineProperty()為對(duì)象的屬性賦值時(shí),數(shù)據(jù)描述符中的屬性默認(rèn)值是不同的,如下例所示。
var o = {}; o.a = 1; // 等同于 : Object.defineProperty(o, "a", { value : 1, writable : true, configurable : true, enumerable : true }); // 另一方面, Object.defineProperty(o, "a", { value : 1 }); // 等同于 : Object.defineProperty(o, "a", { value : 1, writable : false, configurable : false, enumerable : false });一般的 Setters 和 Getters
下面的例子展示了如何實(shí)現(xiàn)一個(gè)自存檔對(duì)象。 當(dāng)設(shè)置temperature 屬性時(shí),archive 數(shù)組會(huì)獲取日志條目。
function Archiver() { var temperature = null; var archive = []; Object.defineProperty(this, "temperature", { get: function() { console.log("get!"); return temperature; }, set: function(value) { temperature = value; archive.push({ val: temperature }); } }); this.getArchive = function() { return archive; }; } var arc = new Archiver(); arc.temperature; // "get!" arc.temperature = 11; arc.temperature = 13; arc.getArchive(); // [{ val: 11 }, { val: 13 }]
或
var pattern = { get: function () { return "I alway return this string,whatever you have assigned"; }, set: function () { this.myname = "this is my name string"; } }; function TestDefineSetAndGet() { Object.defineProperty(this, "myproperty", pattern); } var instance = new TestDefineSetAndGet(); instance.myproperty = "test"; // "I alway return this string,whatever you have assigned" console.log(instance.myproperty); // "this is my name string" console.log(instance.myname);
當(dāng)我們查詢存儲(chǔ)器屬性時(shí)會(huì)調(diào)用getter方法(無參數(shù))。這個(gè)方法返回值就是屬性存取表達(dá)式返回的值。
當(dāng)我們?cè)O(shè)置存儲(chǔ)器屬性時(shí)會(huì)調(diào)用setter方法(有參數(shù))。這個(gè)方法修改存儲(chǔ)器屬性的值。
var obj = { num: 12, age: 13, get num1 () { return this.num }, set num1 (value) { this.num = value }, get age1 () { return this.age } } obj.num1 // 12 obj.num1 = 120 obj.num1 // 120 obj.age1 // 13 obj.age1 = 130 obj.age1 // 13
存儲(chǔ)器屬性定義為一個(gè)或者兩個(gè)和屬性同名的函數(shù),這個(gè)函數(shù)定義沒有使用function關(guān)鍵字而是使用get和set。
可以看出如果該屬性只有g(shù)etter方法則只能讀取該屬性不能設(shè)置該屬性,同樣如果只有setter方法就只能設(shè)置該屬性,不能讀取該屬性,只有當(dāng)兩者都有時(shí)才能正常讀取和設(shè)置屬性。
描述符的原型與默認(rèn)值一般情況,我們會(huì)創(chuàng)建一個(gè)descriptor對(duì)象,然后傳給defineProperty方法。如下:
var descriptor = { writable: false } Object.defineProperty(obj, "key", descriptor);
這種情況是有風(fēng)險(xiǎn)的,如果descriptor的原型上面有相關(guān)特性,也會(huì)通過原型鏈被訪問到,算入在對(duì)key的定義中。比如:
descriptor.__proto__.enumerable = true; Object.defineProperty(obj, "key", descriptor); Object.getOwnPropertyDescriptor(obj,"key"); //返回的enumerable為true
為了避免發(fā)生這樣的意外情況,官方建議使用Object.freeze凍結(jié)對(duì)象,或者是使用Object.create(null)創(chuàng)建一個(gè)純凈的對(duì)象(不含原型)來使用。
接下來的注意點(diǎn)是默認(rèn)值,首先我們會(huì)想普通的賦值語句會(huì)生成怎樣的描述符,如obj.key="value"。
可以使用Object.getOwnPropertyDescriptor來返回一個(gè)屬性的描述符:
obj = {}; obj.key = "value"; Object.getOwnPropertyDescriptor(obj, "key"); /*輸出 { configurable:true, enumerable:true, value:"value", writable:true, } */
這也是復(fù)合我們預(yù)期的,通過賦值語句添加的屬性,相關(guān)描述符都為true,可寫可配置可枚舉。但是使用defineProperty定義的屬性,默認(rèn)值就不是這樣了,其規(guī)則是這樣的:
configurable: false enumerable: false writable: false value: undefined
所以這里還是要注意下的,使用的時(shí)候把描述符寫全,免得默認(rèn)都成false了。
vue的雙向數(shù)據(jù)綁定這個(gè)問題在很多前端面試中,會(huì)提及,是用Object.defineProperty( ),來監(jiān)聽數(shù)據(jù)get和set,來實(shí)現(xiàn)數(shù)據(jù)劫持的
var blog = { name: "文章1" }; console.log(blog.name); // 文章1
如果想要在執(zhí)行console.log(blog.name)的同時(shí),直接給 文章1 加個(gè)書名號(hào),那要怎么處理呢?或者說要通過什么監(jiān)聽對(duì)象 blog的屬性值。這時(shí)候Object.defineProperty( )就派上用場(chǎng)了,代碼如下:
var blog= {} var name = ""; Object.defineProperty(blog, "name", { set: function (value) { name = value; console.log("歡迎查看" + value); }, get: function () { return "《" + name + "》" } }) blog.name = "文章1"; // 歡迎查看文章1 console.log(blog.name); // 《文章1》篡改瀏覽器userAgent
比如你想把瀏覽器的userAgent給改了,直接寫navigator.userAgent = "iPhoneX".你再輸出一下userAgent,發(fā)現(xiàn)并沒有修改。這是為什么呢?我們用這行代碼看一下:
Object.getOwnPropertyDescriptor(window, "navigator"); //輸出 { configurable:true, enumerable:true, get:? (), set:undefined }
原因就找到了,navigator是有setter的,每次取值總會(huì)執(zhí)行這個(gè)set函數(shù)來做返回。但是好消息是什么呢?configurable為true,那就意味這我們可以通過defineProperty來修改這個(gè)屬性,代碼就相當(dāng)簡(jiǎn)單了:
Object.defineProperty(navigator, "userAgent", {get: function(){return "iphoneX"}}) console.log(navigator.userAgent); //輸出iphoneXObject.prototype.isPrototypeOf()
isPrototypeOf() 與 instanceof 運(yùn)算符不同。在表達(dá)式 "object instanceof AFunction"中,object 的原型鏈?zhǔn)轻槍?duì) AFunction.prototype 進(jìn)行檢查的,而不是針對(duì) AFunction 本身。isPrototypeOf() 方法允許你檢查一個(gè)對(duì)象是否存在于另一個(gè)對(duì)象的原型鏈上。語法
prototypeObj.isPrototypeOf(object)
參數(shù)object
在該對(duì)象的原型鏈上搜尋
Boolean,表示調(diào)用對(duì)象是否在另一個(gè)對(duì)象的原型鏈上。
報(bào)錯(cuò)TypeError
如果 prototypeObj 為 undefined 或 null,會(huì)拋出 TypeError。
本示例展示了 Baz.prototype, Bar.prototype, Foo.prototype 和 Object.prototype 在 baz 對(duì)象的原型鏈上:
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 if (Foo.prototype.isPrototypeOf(baz)) { // do something safe } Baz.prototype.isPrototypeOf(baz) //true baz instanceof Baz //true baz instanceof Bar //true baz instanceof Foo //true baz instanceof Bar //true
var obj1 = { name: "eeee" } var obj2 = Object.create(obj1) // isPrototypeOf()方法 Object.prototype.isPrototypeOf(obj1) // true obj1.isPrototypeOf(obj2) // true Object.prototype.isPrototypeOf(obj2) // trueObject.prototype.hasOwnProperty()
hasOwnProperty() 方法會(huì)返回一個(gè)布爾值,指示對(duì)象自身屬性中是否具有指定的屬性語法
obj.hasOwnProperty(prop)
參數(shù)prop 要檢測(cè)的屬性 字符串 名稱或者 Symbol。
返回值用來判斷某個(gè)對(duì)象是否含有指定的屬性的 Boolean 。
描述所有繼承了 Object 的對(duì)象都會(huì)繼承到 hasOwnProperty 方法。這個(gè)方法可以用來檢測(cè)一個(gè)對(duì)象是否含有特定的自身屬性;和 in 運(yùn)算符不同,該方法會(huì)忽略掉那些從原型鏈上繼承到的屬性。
示例1.判斷屬性是否存在
下面的例子檢測(cè)了對(duì)象 o 是否含有自身屬性 prop:
o = new Object(); o.prop = "exists"; function changeO() { o.newprop = o.prop; delete o.prop; } o.hasOwnProperty("prop"); // 返回 true changeO(); o.hasOwnProperty("prop"); // 返回 false o.hasOwnProperty("newprop"); // 返回 true
2.自身屬性與繼承屬性
下面的例子演示了 hasOwnProperty 方法對(duì)待自身屬性和繼承屬性的區(qū)別:
o = new Object(); o.prop = "exists"; o.hasOwnProperty("prop"); // 返回 true o.hasOwnProperty("toString"); // 返回 false o.hasOwnProperty("hasOwnProperty"); // 返回 false
3.遍歷一個(gè)對(duì)象的所有自身屬性
下面的例子演示了如何在遍歷一個(gè)對(duì)象的所有屬性時(shí)忽略掉繼承屬性,注意這里 for...in 循環(huán)只會(huì)遍歷可枚舉屬性,所以不應(yīng)該基于這個(gè)循環(huán)中沒有不可枚舉的屬性而得出 hasOwnProperty 是嚴(yán)格限制于可枚舉項(xiàng)目的(如同 Object.getOwnPropertyNames())。
var buz = { fog: "stack" }; for (var name in buz) { if (buz.hasOwnProperty(name)) { alert("this is fog (" + name + ") for sure. Value: " + buz[name]); } else { alert(name); // toString or something else } }
4.使用 hasOwnProperty 作為屬性名
JavaScript 并沒有保護(hù) hasOwnProperty 屬性名,因此某個(gè)對(duì)象是有可能存在使用這個(gè)屬性名的屬性,使用外部的 hasOwnProperty 獲得正確的結(jié)果是需要的:
var foo = { hasOwnProperty: function() { return false; }, bar: "Here be dragons" }; foo.hasOwnProperty("bar"); // 始終返回 false // 如果擔(dān)心這種情況,可以直接使用原型鏈上真正的 hasOwnProperty 方法 ({}).hasOwnProperty.call(foo, "bar"); // true // 也可以使用 Object 原型上的 hasOwnProperty 屬性 Object.prototype.hasOwnProperty.call(foo, "bar"); // true9.Object.defineProperties()
功能:方法直接在一個(gè)對(duì)象上定義一個(gè)或多個(gè)新的屬性或修改現(xiàn)有屬性,并返回該對(duì)象。
語法:
Object.defineProperties(obj, props) // obj: 將要被添加屬性或修改屬性的對(duì)象 // props: 該對(duì)象的一個(gè)或多個(gè)鍵值對(duì)定義了將要為對(duì)象添加或修改的屬性的具體配置
var obj = new Object(); Object.defineProperties(obj, { name: { value: "張三", configurable: false, writable: true, enumerable: true }, age: { value: 18, configurable: true } }) console.log(obj.name, obj.age) // 張三, 18
與Object.defineProperty()功能大體相同,對(duì)比一下
var obj = new Object(); Object.defineProperty(obj, "name", { configurable: false, writable: true, enumerable: true, value: "張三" }) console.log(obj.name) //張三10.Object.getOwnPropertyDescriptor()
功能:該方法返回指定對(duì)象上一個(gè)自有屬性對(duì)應(yīng)的屬性描述符。(自有屬性指的是直接賦予該對(duì)象的屬性,不需要從原型鏈上進(jìn)行查找的屬性)
語法: Object.getOwnPropertyDescriptor(obj, prop) // obj: 需要查找的目標(biāo)對(duì)象 // prop: 目標(biāo)對(duì)象內(nèi)屬性名稱
var person = { name: "張三", age: 18 } var desc = Object.getOwnPropertyDescriptor(person, "name"); console.log(desc) 結(jié)果如下 // { // configurable: true, // enumerable: true, // writable: true, // value: "張三" // }11.Object. getOwnPropertyDescriptors()
功能:所指定對(duì)象的所有自身屬性的描述符,如果沒有任何自身屬性,則返回空對(duì)象。
語法: Object.getOwnPropertyDescriptors(obj) obj: 需要查找的目標(biāo)對(duì)象
var person = { name: "張三", age: 18 } var desc = Object.getOwnPropertyDescriptors(person); console.log(desc) // 結(jié)果如下圖
推薦閱讀:
1.深入JS對(duì)象的遍歷
2.重新認(rèn)識(shí)javascript對(duì)象(一)——對(duì)象及其屬性
3.重新認(rèn)識(shí)javascript對(duì)象(三)——原型及原型鏈
4.[js中的Object.defineProperty()和defineProperties()
](https://segmentfault.com/a/11...
參考文章:
1.Object.defineProperty()
2.Object.create()
3.isPrototypeOf()
4.Object.prototype.hasOwnProperty()
5.理解defineProperty以及getter、setter
6.vue中v-model等父子組件通信
7.JavaScript 知識(shí)點(diǎn)串燒——對(duì)象
8.重新認(rèn)識(shí)javascript對(duì)象(三)——原型及原型鏈
9.教科書式的object方法
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/90695.html
摘要:方法實(shí)現(xiàn)將所有屬性掛載在觀察對(duì)象,將每一項(xiàng)做一個(gè)數(shù)據(jù)劫持就是將中每一項(xiàng)用定義新屬性并返回這個(gè)對(duì)象。當(dāng)和發(fā)生變化時(shí),自動(dòng)會(huì)觸發(fā)視圖更新,獲取得到的也就是最新值。 MVVM及Vue實(shí)現(xiàn)原理 Github源碼地址:https://github.com/wyj2443573... mvvm 雙向數(shù)據(jù)綁定數(shù)據(jù)影響視圖,視圖影響數(shù)據(jù)angular 臟值檢測(cè) vue數(shù)據(jù)劫持+發(fā)布訂閱模式vue 不...
摘要:在的反射包中提供了三個(gè)類以及來分別描述屬性方法和構(gòu)造器。獲取構(gòu)造器獲取方法可以看到我們可以通過一個(gè)類的對(duì)象很輕松的獲取他的屬性構(gòu)造器以及方法信息。返冋一個(gè)用于描述構(gòu)造器名的字符串。 想要獲取更多文章可以訪問我的博客?-?代碼無止境。 上周上班的時(shí)候解決一個(gè)需求,需要將一批數(shù)據(jù)導(dǎo)出到Excel。本來公司的中間件組已經(jīng)封裝好了使用POI生成Excel的工具方法,但是無奈產(chǎn)品的需求里面有個(gè)合...
摘要:簡(jiǎn)單來說就是把注冊(cè)的動(dòng)作異步化,當(dāng)異步執(zhí)行結(jié)束后會(huì)把執(zhí)行結(jié)果回填到中抽象類一般就是公共邏輯的處理,而這里的處理主要就是針對(duì)一些參數(shù)的判斷,判斷完了之后再調(diào)用方法。 閱讀這篇文章之前,建議先閱讀和這篇文章關(guān)聯(lián)的內(nèi)容。 1. 詳細(xì)剖析分布式微服務(wù)架構(gòu)下網(wǎng)絡(luò)通信的底層實(shí)現(xiàn)原理(圖解) 2. (年薪60W的技巧)工作了5年,你真的理解Netty以及為什么要用嗎?(深度干貨)...
摘要:初始化申明一個(gè)設(shè)置和獲取值使用設(shè)置新值或更新值申明設(shè)置值張三豐張三豐重復(fù)設(shè)置值如果鍵值存在則新值替換舊值張三豐使用獲取值,如果獲取的不存在返回分別獲取判斷是否存在使用判斷給定是否存在映射內(nèi)。 本文同步帶你入門 帶你玩轉(zhuǎn) JavaScript ES6 (六) - Map 映射,轉(zhuǎn)載請(qǐng)注明出處。 本章我們講學(xué)習(xí) ES6 中的 Map(映射)。上一章節(jié)我們學(xué)習(xí)了 [Set(集合)]()的相關(guān)...
摘要:走在前端的大道上本篇將自己讀過的相關(guān)數(shù)據(jù)類型文章中,對(duì)自己有啟發(fā)的章節(jié)片段總結(jié)在這會(huì)對(duì)原文進(jìn)行刪改會(huì)不斷豐富提煉總結(jié)更新。相當(dāng)于相當(dāng)于相當(dāng)于基礎(chǔ)類型不屬于包裝的對(duì)象類型參考文章基礎(chǔ)初談現(xiàn)有的數(shù)據(jù)類型 走在前端的大道上 本篇將自己讀過的相關(guān) javascript 數(shù)據(jù)類型 文章中,對(duì)自己有啟發(fā)的章節(jié)片段總結(jié)在這(會(huì)對(duì)原文進(jìn)行刪改),會(huì)不斷豐富提煉總結(jié)更新。 數(shù)據(jù)類型 js 目前有以下幾大...
閱讀 2950·2023-04-25 19:20
閱讀 799·2021-11-24 09:38
閱讀 2056·2021-09-26 09:55
閱讀 2442·2021-09-02 15:11
閱讀 2063·2019-08-30 15:55
閱讀 3619·2019-08-30 15:54
閱讀 3156·2019-08-30 14:03
閱讀 2969·2019-08-29 17:11