摘要:對象創(chuàng)建字面量方式構(gòu)造函數(shù)方式也可以這樣不過這樣的話,為何不選擇字面量方式字面量方式和方式的寫法是等價的,返回的結(jié)果是同種類的對象。構(gòu)造函數(shù)產(chǎn)生實例時,實例通過其對應(yīng)原型對象的訪問對應(yīng)的構(gòu)造函數(shù)對象。
前端學(xué)習(xí):教程&模塊化/規(guī)范化/工程化/優(yōu)化&工具/調(diào)試&值得關(guān)注的博客/Git&面試資源匯總
歡迎提issues斧正:對象&對象使用
Object對象在 JavaScript 中,對象,是對一些具體事物的一種抽象,所有其他對象都繼承自這個對象。Object 是一個無序集合,將變量和值集合在一起,可以存放任意類型對象(JavaScript中的一切皆對象,這句話應(yīng)該沒有對錯,無論正反兩個方面,支持者都能說出他們的解釋)。
對象創(chuàng)建 字面量方式var obj = { key: "value", name : "xzavier", sex : "male", };構(gòu)造函數(shù)方式
var obj = new Object(); obj.key = "value"; obj.name = "xzavier"; obj.sex = "male";
也可以這樣(不過這樣的話,為何不選擇字面量方式):
var obj = new Object({ key: "value", name : "xzavier", sex : "male", });
字面量方式和new方式的寫法是等價的,返回的結(jié)果是同種類的對象。
字面量方式比較好的是你可以在聲明的時候一次性添多個屬性和值,即鍵/值對;
而構(gòu)造函數(shù)方式,你必須在構(gòu)造完成之后一個一個地添加屬性。
所以,你經(jīng)常都會被建議使用字面量的方式,我們也實踐得非常不錯。很多時候,我們只有在場景需要的情況下才會使用new 構(gòu)造函數(shù)的方式。比如說拋出錯誤、創(chuàng)建含有變量的正則等:
new Error(..) new RegExp("xzav" + i + "er");
所以,大多情況下我們都使用字面量方式,一般不需要明確地創(chuàng)建對象。JavaScript會在必要的時候自動地將一些基本類型轉(zhuǎn)換為對象類型,以便你能使用對象類型中的屬性:
var x = "xx"; x.length; // 2 擁有String類型對象的屬性 var z = "123.321"; z.toFixed(2); // "123.32" 擁有Number類型對象的方法內(nèi)置對象
JavaScript中,有很多內(nèi)置的Object的子類型,我們通常稱為內(nèi)置對象,它們實際上是內(nèi)建的函數(shù),每一個都可以作為構(gòu)造函數(shù) new 出一個新構(gòu)造的相應(yīng)子類型的實例,當(dāng)然,也是對象。
String Number Boolean Math Function Array Date RegExp Error
如上面所說,創(chuàng)建這些子類型也基本使用字面量的方法。檢測類型的話使用
Object.prototype.toString.call(obj);
檢測的最全。具體參考文章: 數(shù)據(jù)類型檢測
Object.prototype對象在JavaScript中,幾乎所有對象都是Object的實例。而Object有一個屬性prototype,指向原型對象(js里所有構(gòu)造函數(shù)都有一個prototype屬性,指向原型對象)。我們在實例化一個對象時,實例會繼承原型對象上的屬性和方法。
可以控制臺查看 String.prototype
然后再: var str = new String("xzavier");
我們的str繼承了String.prototype上的屬性和方法,String又繼承了Obeject.prototype上的方法。
不過說是繼承,說是指向引用比較好。因為對象在查找某個屬性的時候,會首先遍歷自身的屬性,如果沒有則會繼續(xù)查找[[Prototype]]引用的對象,如果再沒有則繼續(xù)查找[[Prototype]].[[Prototype]]引用的對象,依次類推,直到[[Prototype]].….[[Prototype]]為undefined
Object.prototype的[[Prototype]]就是undefined
在控制臺打印仔細(xì)去看:
String.prototype // ... ... Obeject.prototype // ... Obeject.prototype.prototype // undefined
你還可以在控制臺輸入:
var str = new String("xzavier"); str
然后一層層的查看__proto__,你自己創(chuàng)建的構(gòu)造函數(shù)同此。其實我們的實例沒有繼承到方法和屬性,只是添加了個原型屬性,使用的時候往原型鏈上查找,可以找到父級以及更上一層的原型鏈上的方法,然后使用。
具體參見: 原型鏈
回過頭來,修改Object.prototype就會影響到它的子孫后代。改變Object原型對象會修改到所有通過原型鏈繼承的對象,除非實例的相關(guān)屬性和方法沿原型鏈進(jìn)一步覆蓋。這是一個非常強(qiáng)大的,存在潛在危險的機(jī)制,可以覆蓋或擴(kuò)展對象的行為。
Object.prototype.xxx = function(){ console.log("xxx")}; var str = new String("xzavier"); str.xxx(); // xxx
所以:
Don’t modify objects you don’t own
不過,很多時候我們自己寫代碼,用原型屬性擴(kuò)展方法是非常實用的。
// 數(shù)組去重 Array.prototype.unique = function(){ return [...new Set(this)]; } [1,2,3,"4",3,4,3,1,"34",2].unique(); //[1, 2, 3, "4", 4, "34"]對象的遍歷
數(shù)組是對象,字符串是對象,都可以遍歷。遍歷詳解參考: 流程控制
這兒就說說對象{}類型的遍歷:
for...in 語句可以用來枚舉對象的屬性,為遍歷對象屬性設(shè)計的。
var xzavier = { "name" : "xzavier", "age" : 23, "job" : "Jser", "width" : 100, "height" : 100, "border" : 10 }; for (var i in xzavier) { console.log(i); } //name age job width height border for (var i in xzavier) { console.log(xzavier[i]); } //xzavier 23 Jser 100 100 10
在設(shè)計對象的時候,鍵值最好是以字符串,而非數(shù)字字符串,如"0", "123",這樣會導(dǎo)致對象重排。
比如:
var obj = { "0": 1, "abc": 2, "def": 3, "2": 4, "ghi": 5 };
打印obj:
Object {0: 1, 2: 4, abc: 2, def: 3, ghi: 5, __proto__: Object }
用for in 語句輸出:
for (var i in obj) { console.log(oo[i]); } // 1 4 2 3 5 for (var i in obj) { console.log(i); } // 0 2 abc def ghi
雖然我們平時使用不會受到什么影響,也不會這么設(shè)計。但是你在不在乎,它始終在這里。
react的for循環(huán)key值就建議不要以index為值,也有這個原因,具體不多述。
對象的判斷我們經(jīng)常會遇到判斷對象類型,這兒就不說typeof了,詳情請參考:數(shù)據(jù)類型判斷
這兒簡寫一下這個不會出錯的方法:
Object.prototype.toString.call("xz"); //"[object String]" Object.prototype.toString.call(123); //"[object Number]" Object.prototype.toString.call(true); //"[object Boolean]" Object.prototype.toString.call([1,2]); //"[object Array]" Object.prototype.toString.call({name:"xz"}); //"[object Object]" Object.prototype.toString.call(function(){}); //"[object Function]" Object.prototype.toString.call(null); //"[object Null]" Object.prototype.toString.call(undefined); //"[object Undefined]" Object.prototype.toString.call(); //"[object Undefined]" Object.prototype.toString.call(new Date()); //"[object Date]" Object.prototype.toString.call(/xz/); //"[object RegExp]" Object.prototype.toString.call(Symbol()); //"[object Symbol]" var obj = {name:"Xzavier", age:23}; var a = [1,2,3]; function isType(obj) { return Object.prototype.toString.call(obj).slice(8, -1); } isType(obj); // "Object" isType(a) // "Array"
但是,很多時候我們在處理數(shù)據(jù)的時候,需要判斷一個對象是否為{}:
var isEmptyObject = function(obj) { for (var name in obj) { return false; } return true; }; isEmptyObject({}); // true isEmptyObject({name: "xzavier"}); //false對象屬性值訪問
閱讀了溫故js系列(1)- 數(shù)據(jù)類型存儲,我們知道,引用數(shù)據(jù)類型值指保存在堆內(nèi)存中的對象。也就是,變量中保存的實際上的只是一個指針,這個指針指向內(nèi)存中的另一個位置,該位置保存著對象,訪問方式是按引用訪問。
var obj = { key: "value", name : "xzavier", sex : "male", "x-v": "xz", "xx!": "xxxx", };
在訪問一個對象的一個屬性時,使用.或["..."]操作符。obj.key 和 obj["key"] 都訪問obj中相同的位置,返回值都是"xzavier",所以這兩種方式都在代碼中經(jīng)常使用到。
而這兩種訪問方式的區(qū)別是,.操作符后面需要跟一個標(biāo)識符(Identifier)兼容的屬性名,而["..."]語法基本可以接收任何兼容UTF-8/unicode的字符串作為屬性名。
obj.x-v // 報錯 obj.xx! // 報錯 obj["x-v"] // "xz" obj["xx!"] // "xxxx"
因為x-z,xx!不是一個合法的標(biāo)識符屬性名。
["..."] 還可以動態(tài)組建屬性名,這在合適的場景下非常好用。
var obj = { number1: "xx", number2: "yy", number3: "zz" } var number = 2; var select_name = obj["number" + number]; // "yy"屬性描述符
var xz = {name: "xzavier"} Object.getOwnPropertyDescriptor( xz, "name" );
正如函數(shù)名,獲取屬性描述符,打印如下:
// configurable: true, 是否可配置 // writable: true, 是否可寫 // value: "xzavier", // enumerable: true 是否可枚舉 // __proto__: Object
我們很少關(guān)注到這些,若有需要,我們關(guān)注的莫過于configurable,writable,enumerable等。
可以通過Object的defineProperty方法修改值的屬性,一般我們使用defineProperty是給對象添加屬性,在這個使用的基礎(chǔ)上,可以對這個值的屬性進(jìn)行配置。
Object.defineProperty( obj, "name", { value: "xzavier-1", configurable: true, //是否可配置 writable: false, //是否可寫 enumerable: true //是否可枚舉 }); obj.name // xzavier-1 obj.name = "xzavier-2" // 不會報錯,但在"use strict"模式下,會報錯TypeError obj.name // xzavier-1 值沒有被修改
這是writable,接下來說說enumerable,是否可枚舉:
enumerable表述屬性是否能在特定的對象屬性枚舉操作中出現(xiàn),比如在for..in,for...of中遍歷。如果enumerable被設(shè)置為false,那么這個屬性將不會出現(xiàn)在枚舉中,不過它依然可以被屬性訪問方式訪問。
var obj = { number1: "xx", number2: "yy", number3: "zz" } Object.defineProperty( obj, "name0", { value: "xzavier-1", configurable: true, //是否可配置 writable: true, //是否可寫 enumerable: false //是否可枚舉 }); for(var i in obj) { console.log(i); // number1 number2 number3 不會出現(xiàn)number0 } for(var i of keys(obj)) { console.log(i); // number1 number2 number3 不會出現(xiàn)number0 }
再把enumerable設(shè)置為true就可以繼續(xù)在枚舉中遍歷到了。
Object.defineProperty( obj, "name0", { enumerable: true //是否可枚舉 }); for(var i in obj) { console.log(i); // number1 number2 number3 number0 } for(var i in keys(obj)) { console.log(i); // number1 number2 number3 number0 }
最后說下configurable ,表示屬性是否可以進(jìn)行以上操作,即是否可配置。它是一個單向操作,不可逆。
Object.defineProperty( obj, "name4", { value: "xzavier-4", configurable: false, //是否可配置 writable: false, //是否可寫 enumerable: true //是否可枚舉 });
屬性的configurable一旦被設(shè)為false,將不可逆轉(zhuǎn),再用defineProperty設(shè)置屬性將會報錯。
Object.defineProperty( obj, "name4", { value: "xzavier-4", configurable: true, //是否可配置 writable: true, //是否可寫 enumerable: true //是否可枚舉 }); // TypeErrorObject方法 Object.assign()
Object.assign(target, ...sources)方法用于從一個或多個源對象的所有可枚舉屬性的值復(fù)制到目標(biāo)對象上,有相同屬性的時候,目標(biāo)對象上的屬性會被覆蓋,最終返回目標(biāo)對象。
接收參數(shù):target目標(biāo)對象,...sources一到多個源對象 不傳則直接返回目標(biāo)對象
我們可以:
1.復(fù)制對象
var obj = { a: 1 }; var obj_1 = Object.assign({}, obj); // { a: 1 }
2.合并對象
var o1 = { a: 1 }; var o2 = { b: 2 }; var o3 = { c: 3 }; var obj = Object.assign({}, o1, o2, o3); // { a: 1, b: 2, c: 3 }Object.create()
Object.create(prototype, descriptors) 方法創(chuàng)建一個具有指定原型且可選擇性地包含指定屬性的對象。接收參數(shù):prototype,必需,要用作原型的對象,可以為 null。descriptors,可選,包含一個或多個屬性描述符的 JavaScript 對象。數(shù)據(jù)屬性描述符包含value,以及 writable,enumerable,configurable,即上面所講。
我們可以:
1.創(chuàng)建一個新對象:
var obj = { name: "xzavier" } var o = Object.create(obj); o.name; // "xzavier" // 但是 name屬性并非o的自定義屬性 o.hasOwnProperty("name"); //false 你在瀏覽器操作之后展開也可以清晰的看到
2.創(chuàng)建一個空對象(沒有原型的對象)
Object.create(null)創(chuàng)建一個擁有空[[Prototype]]鏈接的對象,即這個對象沒有原形鏈。
var obj = Object.create(null); 在控制臺會看到返回 object[ No Properties ]
那這樣的東西創(chuàng)建來又什么用呢,它可以作為一種數(shù)據(jù)存儲方式,不用擔(dān)心它會被原型之類的污染,不用擔(dān)心會有原型鏈查找。它就是一個不會存在一個你意想不到的屬性的存儲結(jié)構(gòu)。所以,可以放心使用它。
3.繼承
function Parent() {} Parent.prototype.say = function() { console.info("Hello World"); }; function Childs() { Parent.call(this); } Childs.prototype = Object.create(Parent.prototype); var child = new Childs(); child instanceof Childs; //true. child instanceof Parent; //true. child.say(); // Hello WorldObject.is()
ES6之前,比較兩個值是否相等,使用相等運(yùn)算符(==)和嚴(yán)格相等運(yùn)算符(===)。具體參見:代碼中的哪些判斷。
而Object.is()的出現(xiàn)主要是讓以下情況出現(xiàn):
+0 === -0 //true NaN === NaN // false Object.is(+0, -0) // false Object.is(NaN, NaN) // true
Object.is()使用的是嚴(yán)格相等運(yùn)算符(===)做判斷,對+0,-0,NaN做了特殊處理
Object()Object() // {} Object({}) // {} Object(undefined) // {} Object(null) // {} Object(1) // 同 new Number(1) Object(NaN) // 同 new Number(NaN) Object("xzavier") // 同 new String("xzavier") Object(false) // 同 new Boolean(false) Object([1,2,3]) // [1,2,3] Object({name: "xzavier"}) // {name: "xzavier"} Object(function x(){}) // function x(){}
Object()創(chuàng)造一個“真”對象,返回的都是一個truthy值,是一個對象,所以在if()判斷中都是一個真值。
Object.prototype上的方法Object.prototype上的方法往往都會被繼承到你實例化的或者字面量形式聲明的數(shù)據(jù)類型中。我們可以直接在實例上使用:
[1,2,3].toString(); //"1,2,3" ({a: 1}).valueOf(); // {a: 1} ......對象的其他使用
關(guān)于對象的使用,上面所羅列的都是我們經(jīng)常遇到的。我們也經(jīng)常使用對象的特性,做一些事情。
數(shù)組去重:
Array.prototype.unique = function() { var arr = []; var hash = {}; for (var i = 0; i < this.length; i++) { var item = this[i]; var key = typeof(item) + item if (hash[key] !== 1) { arr.push(item); hash[key] = 1; } } return arr; } [1,2,3,"4",3,4,3,1,"34",2].unique(); //[1, 2, 3, "4", 4, "34"]
hash去重的核心是構(gòu)建了一個 hash 對象來替代 indexOf。判斷hash的key是否已經(jīng)存在來去重。
最后說一下,文章里面提到的[[Prototype]],__proto__,prototype。
你打印來看,我們只會看到__proto__,所以起作用的是__proto__,__proto__是對象的內(nèi)置屬性,是每個對象都有的屬性,但是這個屬性使用不標(biāo)準(zhǔn),所以不建議直接使用。但是,我們的原型鏈就是基于 __proto__的。通過構(gòu)造函數(shù)得到的實例的 __proto__ 屬性,指向其對應(yīng)的原型對象 String.prototype,這正如文中我們打印 var str = new String("xzavier") 中看到的一樣。
[[Prototype]]是一個隱藏屬性,指向的是這個對象的原型。幾乎每個對象有一個[[prototype]]屬性。
而prototype是每個函數(shù)對象都具有的屬性,指向原型對象,如果原型對象被添加屬性和方法,那么由應(yīng)的構(gòu)造函數(shù)創(chuàng)建的實例會繼承prototype上的屬性和方法,這也是我們在代碼中經(jīng)常遇到的。構(gòu)造函數(shù)產(chǎn)生實例時,實例通過其對應(yīng)原型對象的 constructor 訪問對應(yīng)的構(gòu)造函數(shù)對象。所以,我們繼承出來的實例往往沒有constructor,只是通過原型鏈查找,會讓我們產(chǎn)生錯覺,可參見本系列原型鏈文章。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/91319.html
摘要:業(yè)務(wù)越復(fù)雜,邏輯就越復(fù)雜,判斷就越多比較判斷比較判斷是比較兩個值,返回一個布爾值,表示是否滿足比較條件。對于非布爾值的數(shù)據(jù),取反運(yùn)算符會自動將其轉(zhuǎn)為布爾值。 前端學(xué)習(xí):教程&開發(fā)模塊化/規(guī)范化/工程化/優(yōu)化&工具/調(diào)試&值得關(guān)注的博客/Git&面試-前端資源匯總 歡迎提issues斧正:========== JavaScript-判斷 代碼中,多多少少會有判斷語句。業(yè)務(wù)越復(fù)雜,邏輯就越...
摘要:給添加屬性給的原型對象添加屬性原型鏈在中,每個對象都有一個屬性,其保存著的地址就構(gòu)成了對象的原型鏈。實例變量實例函數(shù)原型鏈繼承有了原型鏈,就可以借助原型鏈實現(xiàn)繼承。是中唯一一個處理屬性但是不查找原型鏈的函數(shù)。 前端學(xué)習(xí):教程&開發(fā)模塊化/規(guī)范化/工程化/優(yōu)化&工具/調(diào)試&值得關(guān)注的博客/Git&面試-前端資源匯總 歡迎提issues斧正:原型&原型鏈&原型繼承 JavaScript-原...
摘要:引用數(shù)據(jù)類型引用數(shù)據(jù)類型值指保存在堆內(nèi)存中的對象。訪問方式是按引用訪問。數(shù)據(jù)類型檢測操作符是檢測基本類型的最佳工具。未定義布爾值字符串?dāng)?shù)值對象或函數(shù)用于檢測引用類型,可以檢測到它是什么類型的實例。 前端學(xué)習(xí):教程&開發(fā)模塊化/規(guī)范化/工程化/優(yōu)化&工具/調(diào)試&值得關(guān)注的博客/Git&面試-前端資源匯總 歡迎提issues斧正:數(shù)據(jù)類型 回味,無窮! 數(shù)據(jù)類型定義 數(shù)據(jù)類型分類 基本數(shù)據(jù)...
摘要:該對象包含了函數(shù)的所有局部變量命名參數(shù)參數(shù)集合以及,然后此對象會被推入作用域鏈的前端。如果整個作用域鏈上都無法找到,則返回。此時的作用域鏈包含了兩個對象的活動對象和對象。 前端學(xué)習(xí):教程&開發(fā)模塊化/規(guī)范化/工程化/優(yōu)化&工具/調(diào)試&值得關(guān)注的博客/Git&面試-前端資源匯總 歡迎提issues斧正:閉包 JavaScript-閉包 閉包(closure)是一個讓人又愛又恨的somet...
摘要:接收響應(yīng)當(dāng)請求發(fā)送到服務(wù)器端,收到響應(yīng)后,響應(yīng)的數(shù)據(jù)會自動填充對象的屬性。一般而已狀態(tài)代碼為作為成功的標(biāo)志。必要時,可以將查詢字符串參數(shù)追加到的末尾,以便提交給服務(wù)器。后端實現(xiàn)可以自學(xué)一點后端知識,便于學(xué)習(xí)。 前端學(xué)習(xí):教程&開發(fā)模塊化/規(guī)范化/工程化/優(yōu)化&工具/調(diào)試&值得關(guān)注的博客/Git&面試-前端資源匯總 歡迎提issues斧正:Ajax JavaScript-Ajax&&no...
閱讀 3229·2021-11-11 16:55
閱讀 2490·2021-10-13 09:39
閱讀 2424·2021-09-13 10:27
閱讀 2163·2019-08-30 15:55
閱讀 3088·2019-08-30 15:54
閱讀 3133·2019-08-29 16:34
閱讀 1827·2019-08-29 12:41
閱讀 1072·2019-08-29 11:33