摘要:創建對象的兩種方式推薦該構造器可以接受任何類型的參數,并且會自動識別參數的類型,并選擇更合適的構造器來完成相關操作。比如二的成員該屬性指向用來構造該函數對象的構造器,在這里為該方法返回的是一個用于描述目標對象的字符串。
之前看到【深度長文】JavaScript數組所有API全解密和JavaScript字符串所有API全解密這兩篇高質量的文章。發現沒寫對象API解析(估計是博主覺得簡單,就沒寫)。剛好我看到《JavaScript面向對象編程指南(第2版)》,覺得有必要寫(或者說chao)一下,也好熟悉下對象的所有API用法。
創建對象的兩種方式:
var o = new Object(); var o = {}; // 推薦
該構造器可以接受任何類型的參數,并且會自動識別參數的類型,并選擇更合適的構造器來完成相關操作。比如:
var o = new Object("something"); o.constructor; // ? String() { [native code] } var n = new Object(123); n.constructor; // ? Number() { [native code] }一、Object構造器的成員 Object.prototype
該屬性是所有對象的原型(包括 Object對象本身),語言中的其他對象正是通過對該屬性上添加東西來實現它們之間的繼承關系的。所以要小心使用。
比如:
var s = new String("xuanyuan"); Object.prototype.custom = 1; console.log(s.custom); // 1二、Object.prototype 的成員 Object.prototype.constructor
該屬性指向用來構造該函數對象的構造器,在這里為Object()
Object.prototype.constructor === Object; // true var o = new Object(); o.constructor === Object; // trueObject.prototype.toString(radix)
該方法返回的是一個用于描述目標對象的字符串。特別地,當目標是一個Number對象時,可以傳遞一個用于進制數的參數radix,該參數radix,該參數的默認值為10。
var o = {prop:1}; o.toString(); // "[object Object]" var n = new Number(255); n.toString(); // "255" n.toString(16); // "ff"Object.prototype.toLocaleString()
該方法的作用與toString()基本相同,只不過它做一些本地化處理。該方法會根據當前對象的不同而被重寫,例如Date(),Number(),Array(),它們的值都會以本地化的形式輸出。當然,對于包括Object()在內的其他大多數對象來說,該方法與toString()是基本相同的。
在瀏覽器環境下,可以通過BOM對象Navigator的language屬性(在IE中則是userLanguage)來了解當前所使用的語言:
navigator.language; //"en-US"Object.prototype.valueOf()
該方法返回的是用基本類型所表示的this值,如果它可以用基本類型表示的話。如果Number對象返回的是它的基本數值,而Date對象返回的是一個時間戳(timestamp)。如果無法用基本數據類型表示,該方法會返回this本身。
// Object var o = {}; typeof o.valueOf(); // "object" o.valueOf() === o; // true // Number var n = new Number(101); typeof n; // "object" typeof n.vauleOf; // "function" typeof n.valueOf(); // "number" n.valueOf() === n; // false // Date var d = new Date(); typeof d.valueOf(); // "number" d.valueOf(); // 1503146772355Object.prototype.hasOwnProperty(prop)
該方法僅在目標屬性為對象自身屬性時返回true,而當該屬性是從原型鏈中繼承而來或根本不存在時,返回false。
var o = {prop:1}; o.hasOwnProperty("prop"); // true o.hasOwnProperty("toString"); // false o.hasOwnProperty("formString"); // falseObject.prototype.isPrototypeOf(obj)
如果目標對象是當前對象的原型,該方法就會返回true,而且,當前對象所在原型上的所有對象都能通過該測試,并不局限與它的直系關系。
var s = new String(""); Object.prototype.isPrototypeOf(s); // true String.prototype.isPrototypeOf(s); // true Array.prototype.isPrototypeOf(s); // falseObject.prototype.propertyIsEnumerable(prop)
如果目標屬性能在for in循環中被顯示出來,該方法就返回true
var a = [1,2,3]; a.propertyIsEnumerable("length"); // false a.propertyIsEnumerable(0); // true三、在ES5中附加的Object屬性
在ES3中,除了一些內置屬性(如:Math.PI),對象的所有的屬性在任何時候都可以被修改、插入、刪除。在ES5中,我們可以設置屬性是否可以被改變或是被刪除——在這之前,它是內置屬性的特權。ES5中引入了屬性描述符的概念,我們可以通過它對所定義的屬性有更大的控制權。這些屬性描述符(特性)包括:
value——當試圖獲取屬性時所返回的值。
writable——該屬性是否可寫。
enumerable——該屬性在for in循環中是否會被枚舉
configurable——該屬性是否可被刪除。
set()——該屬性的更新操作所調用的函數。
get()——獲取屬性值時所調用的函數。
另外,數據描述符(其中屬性為:enumerable,configurable,value,writable)與存取描述符(其中屬性為enumerable,configurable,set(),get())之間是有互斥關系的。在定義了set()和get()之后,描述符會認為存取操作已被 定義了,其中再定義value和writable會引起錯誤。
以下是ES3風格的屬性定義方式:
var person = {}; person.legs = 2;
以下是等價的ES5通過數據描述符定義屬性的方式:
var person = {}; Object.defineProperty(person, "legs", { value: 2, writable: true, configurable: true, enumerable: true });
其中, 除了value的默認值為undefined以外,其他的默認值都為false。這就意味著,如果想要通過這一方式定義一個可寫的屬性,必須顯示將它們設為true。
或者,我們也可以通過ES5的存儲描述符來定義:
var person = {}; Object.defineProperty(person, "legs", { set:function(v) { return this.value = v; }, get: function(v) { return this.value; }, configurable: true, enumerable: true }); person.legs = 2;
這樣一來,多了許多可以用來描述屬性的代碼,如果想要防止別人篡改我們的屬性,就必須要用到它們。此外,也不要忘了瀏覽器向后兼容ES3方面所做的考慮。例如,跟添加Array.prototype屬性不一樣,我們不能再舊版的瀏覽器中使用shim這一特性。
另外,我們還可以(通過定義nonmalleable屬性),在具體行為中運用這些描述符:
var person = {}; Object.defineProperty(person, "heads", {value: 1}); person.heads = 0; // 0 person.heads; // 1 (改不了) delete person.heads; // false person.heads // 1 (刪不掉)Object.defineProperty(obj, prop, descriptor) (ES5)
具體用法可參見上文,或者查看MDN。
MDN Object.defineProperty(obj, descriptor)
Vue.js文檔:如何追蹤變化 把一個普通 JavaScript 對象傳給 Vue 實例的 data 選項,Vue 將遍歷此對象所有的屬性,并使用 Object.defineProperty 把這些屬性全部轉為 getter/setter。Object.defineProperty 是僅 ES5 支持,且無法 shim 的特性,這也就是為什么 Vue 不支持 IE8 以及更低版本瀏覽器的原因。Object.defineProperties(obj, props) (ES5)
該方法的作用與defineProperty()基本相同,只不過它可以用來一次定義多個屬性。
比如:
var glass = Object.defineProperties({}, { "color": { value: "transparent", writable: true }, "fullness": { value: "half", writable: false } }); glass.fullness; // "half"Object.getPrototypeOf(obj) (ES5)
之前在ES3中,我們往往需要通過Object.prototype.isPrototypeOf()去猜測某個給定的對象的原型是什么,如今在ES5中,我們可以直接詢問改對象“你的原型是什么?”
Object.getPrototypeOf([]) === Array.prototype; // true Object.getPrototypeOf(Array.prototype) === Object.prototype; // true Object.getPrototypeOf(Object.prototype) === null; // trueObject.create(obj, descr) (ES5)
該方法主要用于創建一個新對象,并為其設置原型,用(上述)屬性描述符來定義對象的原型屬性。
var parent = {hi: "Hello"}; var o = Object.create(parent, { prop: { value: 1 } }); o.hi; // "Hello" // 獲得它的原型 Object.getPrototypeOf(parent) === Object.prototype; // true 說明parent的原型是Object.prototype Object.getPrototypeOf(o); // {hi: "Hello"} // 說明o的原型是{hi: "Hello"} o.hasOwnProperty("hi"); // false 說明hi是原型上的 o.hasOwnProperty("prop"); // true 說明prop是原型上的自身上的屬性。
現在,我們甚至可以用它來創建一個完全空白的對象,這樣的事情在ES3中可是做不到的。
var o = Object.create(null); typeof o.toString(); // "undefined"Object.getOwnPropertyDesciptor(obj, property) (ES5)
該方法可以讓我們詳細查看一個屬性的定義。甚至可以通過它一窺那些內置的,之前不可見的隱藏屬性。
Object.getOwnPropertyDescriptor(Object.prototype, "toString"); // {writable: true, enumerable: false, configurable: true, value: ? toString()}Object.getOwnPropertyNames(obj) (ES5)
該方法返回一個數組,其中包含了當前對象所有屬性的名稱(字符串),不論它們是否可枚舉。當然,也可以用Object.keys()來多帶帶返回可枚舉的屬性。
Object.getOwnPropertyNames(Object.prototype); // ["__defineGetter__", "__defineSetter__", "hasOwnProperty", "__lookupGetter__", "__lookupSetter__", "propertyIsEnumerable", "toString", "valueOf", "__proto__", "constructor", "toLocaleString", "isPrototypeOf"] Object.keys(Object.prototype); // [] Object.getOwnPropertyNames(Object); // ["length", "name", "arguments", "caller", "prototype", "assign", "getOwnPropertyDescriptor", "getOwnPropertyDescriptors", "getOwnPropertyNames", "getOwnPropertySymbols", "is", "preventExtensions", "seal", "create", "defineProperties", "defineProperty", "freeze", "getPrototypeOf", "setPrototypeOf", "isExtensible", "isFrozen", "isSealed", "keys", "entries", "values"] Object.keys(Object); // []Object.preventExtensions(obj) (ES5) Object.isExtensible(obj) (ES5)
preventExtensions()方法用于禁止向某一對象添加更多屬性,而isExtensible()方法則用于檢查某對象是否還可以被添加屬性。
var deadline = {}; Object.isExtensible(deadline); // true deadline.date = "yesterday"; // "yesterday" Object.preventExtensions(deadline); Object.isExtensible(deadline); // false deadline.date = "today"; deadline.date; // "today" // 盡管向某個不可擴展的對象中添加屬性不算是一個錯誤操作,但它沒有任何作用。 deadline.report = true; deadline.report; // undefinedObject.seal(obj) (ES5) Object.isSeal(obj) (ES5)
seal()方法可以讓一個對象密封,并返回被密封后的對象。
seal()方法的作用與preventExtensions()基本相同,但除此之外,它還會將現有屬性
設置成不可配置。也就是說,在這種情況下,我們只能變更現有屬性的值,但不能刪除或(用defineProperty())重新配置這些屬性,例如不能將一個可枚舉的屬性改成不可枚舉。
var person = {legs:2}; // person === Object.seal(person); // true Object.isSealed(person); // true Object.getOwnPropertyDescriptor(person, "legs"); // {value: 2, writable: true, enumerable: true, configurable: false} delete person.legs; // false (不可刪除,不可配置) Object.defineProperty(person, "legs",{value:2}); person.legs; // 2 person.legs = 1; person.legs; // 1 (可寫) Object.defineProperty(person, "legs", { get: function() { return "legs"; } }); // 拋出TypeError異常Object.freeze(obj) (ES5) Object.isFrozen(obj) (ES5)
freeze()方法用于執行一切不受seal()方法限制的屬性值變更。Object.freeze() 方法可以凍結一個對象,凍結指的是不能向這個對象添加新的屬性,不能修改其已有屬性的值,不能刪除已有屬性,以及不能修改該對象已有屬性的可枚舉性、可配置性、可寫性。也就是說,這個對象永遠是不可變的。該方法返回被凍結的對象。
var deadline = Object.freeze({date: "yesterday"}); deadline.date = "tomorrow"; deadline.excuse = "lame"; deadline.date; // "yesterday" deadline.excuse; // undefined Object.isSealed(deadline); // true; Object.isFrozen(deadline); // true Object.getOwnPropertyDescriptor(deadline, "date"); // {value: "yesterday", writable: false, enumerable: true, configurable: false} (不可配置,不可寫) Object.keys(deadline); // ["date"] (可枚舉)Object.keys(obj) (ES5)
該方法是一種特殊的for-in循環。它只返回當前對象的屬性(不像for-in),而且這些屬性也必須是可枚舉的(這點和Object.getOwnPropertyNames()不同,不論是否可以枚舉)。返回值是一個字符串數組。
Object.prototype.customProto = 101; Object.getOwnPropertyNames(Object.prototype); // [..., "constructor", "toLocaleString", "isPrototypeOf", "customProto"] Object.keys(Object.prototype); // ["customProto"] var o = {own: 202}; o.customProto; // 101 Object.keys(o); // ["own"]四、在ES6中附加的Object屬性 Object.is(value1, value2) (ES6)
該方法用來比較兩個值是否嚴格相等。它與嚴格比較運算符(===)的行為基本一致。
不同之處只有兩個:一是+0不等于-0,而是NaN等于自身。
Object.is("xuanyuan", "xuanyuan"); // true Object.is({},{}); // false Object.is(+0, -0); // false +0 === -0; // true Object.is(NaN, NaN); // true NaN === NaN; // false
ES5可以通過以下代碼部署Object.is
Object.defineProperty(Object, "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, writable: true });Object.assign(target, ...sources) (ES6)
該方法用來源對象(source)的所有可枚舉的屬性復制到目標對象(target)。它至少需要兩個對象作為參數,第一個參數是目標對象target,后面的參數都是源對象(source)。只有一個參數不是對象,就會拋出TypeError錯誤。
var target = {a: 1}; var source1 = {b: 2}; var source2 = {c: 3}; obj = Object.assign(target, source1, source2); target; // {a:1,b:2,c:3} obj; // {a:1,b:2,c:3} target === obj; // true // 如果目標對象與源對象有同名屬性,或多個源對象有同名屬性,則后面的屬性會覆蓋前面的屬性。 var source3 = {a:2,b:3,c:4}; Object.assign(target, source3); target; // {a:2,b:3,c:4}
Object.assign只復制自身屬性,不可枚舉的屬性(enumerable為false)和繼承的屬性不會被復制。
Object.assign({b: "c"}, Object.defineProperty({}, "invisible", { enumerable: false, value: "hello" }) ); // {b: "c"}
屬性名為Symbol值的屬性,也會被Object.assign()復制。
Object.assign({a: "b"}, {[Symbol("c")]: "d"}); // {a: "b", Symbol(c): "d"}
對于嵌套的對象,Object.assign()的處理方法是替換,而不是添加。
Object.assign({a: {b:"c",d:"e"}}, {a:{b:"hello"}}); // {a: {b:"hello"}}
對于數組,Object.assign()把數組視為屬性名為0、1、2的對象。
Object.assign([1,2,3], [4,5]); // [4,5,3]Object.getOwnPropertySymbols(obj) (ES6)
該方法會返回一個數組,該數組包含了指定對象自身的(非繼承的)所有 symbol 屬性鍵。
該方法和 Object.getOwnPropertyNames() 類似,但后者返回的結果只會包含字符串類型的屬性鍵,也就是傳統的屬性名。
Object.getOwnPropertySymbols({a: "b", [Symbol("c")]: "d"}); // [Symbol(c)]Object.setPrototypeOf(obj, prototype) (ES6)
該方法設置一個指定的對象的原型 ( 即, 內部[[Prototype]]屬性)到另一個對象或 null。
__proto__屬性用來讀取或設置當前對象的prototype對象。目前,所有瀏覽器(包括IE11)都部署了這個屬性。
// ES6寫法 var obj = { method: function(){ // code ... } }; // obj.__proto__ = someOtherObj; // ES5寫法 var obj = Object.create(someOtherObj); obj.method = function(){ // code ... };
該屬性沒有寫入ES6的正文,而是寫入了附錄。__proto__前后的雙下劃線說明它本質上是一個內部屬性,而不是正式對外的一個API。無論從語義的角度,還是從兼容性的角度,都不要使用這個屬性。而是使用Object.setPrototypeOf()(寫操作),Object.getPrototypeOf()(讀操作),或Object.create()(生成操作)代替。
在實現上,__proto__調用的Object.prototype.__proto__。
Object.setPrototypeOf()方法的作用與__proto__作用相同,用于設置一個對象的prototype對象。它是ES6正式推薦的設置原型對象的方法。
該方法基本與Object.getOwnPropertyDescriptor(obj, property)用法一致,只不過它可以用來獲取一個對象的所有自身屬性的描述符。
Object.getOwnPropertyDescriptor(Object.prototype, "toString"); // {writable: true, enumerable: false, configurable: true, value: ? toString()} Object.getOwnPropertyDescriptors(Object.prototype); // 可以自行在瀏覽器控制臺查看效果。Object.values(obj) (ES8)
Object.values() 方法與Object.keys類似。返回一個給定對象自己的所有可枚舉屬性值的數組,值的順序與使用for...in循環的順序相同 ( 區別在于for-in循環枚舉原型鏈中的屬性 )。
var obj = {a:1,b:2,c:3}; Object.keys(obj); // ["a","b","c"] Object.values(obj); // [1,2,3]Object.entries(obj) (ES8)
Object.entries() 方法返回一個給定對象自己的可枚舉屬性[key,value]對的數組,數組中鍵值對的排列順序和使用 for...in 循環遍歷該對象時返回的順序一致(區別在于一個for-in循環也枚舉原型鏈中的屬性)。
var obj = {a:1,b:2,c:3}; Object.keys(obj); // ["a","b","c"] Object.values(obj); // [1,2,3] Object.entries(obj); // [["a",1],["b",2],["c",3]]小結
您可能會發現MDN上還有一些API,本文沒有列舉到。因為那些是非標準的API。熟悉對象的API對理解原型和原型鏈相關知識會有一定幫助。常用的API主要有Object.prototype.toString(),Object.prototype.hasOwnProperty(), Object.getPrototypeOf(obj),Object.create(),Object.defineProperty,Object.keys(obj),Object.assign()。
參考資料MDN Object API
JavaScript面向對象編程指南(第2版)(豆瓣讀書鏈接)
阮一峰 ES6標準入門2
作者:常以軒轅Rowboat若川為名混跡于江湖。前端路上 | PPT愛好者 | 所知甚少,唯善學。
個人博客
segmentfault前端視野專欄,開通了前端視野專欄,歡迎關注
掘金專欄,歡迎關注
知乎前端視野專欄,開通了前端視野專欄,歡迎關注
github,歡迎follow~
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/87380.html
摘要:當這些異步任務發生的時候,它們將會被放入瀏覽器的事件任務隊列中去,等到運行時執行線程空閑時候才會按照隊列先進先出的原則被一一執行,但終究還是單線程。 瀏覽器是多進程的 showImg(https://segmentfault.com/img/remote/1460000019706956?w=815&h=517); Browser進程: 瀏覽器的主進程(負責協調、主控),只有一個。 負...
摘要:當這些異步任務發生的時候,它們將會被放入瀏覽器的事件任務隊列中去,等到運行時執行線程空閑時候才會按照隊列先進先出的原則被一一執行,但終究還是單線程。 瀏覽器是多進程的 showImg(https://segmentfault.com/img/remote/1460000019706956?w=815&h=517); Browser進程: 瀏覽器的主進程(負責協調、主控),只有一個。 負...
摘要:原文瀏覽器事件之間的關系程序采用了異步事件驅動編程模型,維基百科對它的解釋是事件驅動程序設計英語是一種電腦程序設計模型。 原文:https://keelii.github.io/2016/09/29/javascript-browser-event/ JavaScript、瀏覽器、事件之間的關系 JavaScript 程序采用了異步事件驅動編程(Event-driven program...
摘要:下面,我將自己閱讀的源碼的過程記錄下來。閱讀庫的代碼,首先先要知道這個庫的作用是一個輕量的時間日期處理庫,其用法和完全一樣。介紹首先,閱讀的源碼,我們應該從的入手。對象是不可變的,即所有改變的操作都會返回一個新的實例。 前言 作為一個程序員,閱讀別人優秀代碼是提升自己技術能力的一個很好的方法。下面,我將自己閱讀 dayjs(v1.6.10)的源碼的過程記錄下來。 閱讀庫的代碼,首先先要...
摘要:數據格式是一種輕量級的數據交換格式。為了對名為的對象進行轉換,只需執行相同形式的命令這就是與本系列討論的其他數據格式之間最大的差異。不過,我們讀起來費解的語言,恰恰是適合機器閱讀,所以通過的索引就能夠讀取黑龍江這個值。 JSON 數據格式 JSON(JavaScript Object Notation) 是一種輕量級的數據交換格式。JSON采用完全獨立于語言的文本格式,這些特性使...
閱讀 3539·2021-11-18 13:22
閱讀 2556·2021-09-23 11:53
閱讀 725·2019-08-30 13:17
閱讀 1346·2019-08-30 13:12
閱讀 895·2019-08-29 15:43
閱讀 1099·2019-08-29 12:53
閱讀 2828·2019-08-26 18:27
閱讀 1499·2019-08-26 11:52