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