本文是 重溫基礎 系列文章的第十二篇。
今日感覺:須要總結下2018。前端
這幾天,重重的感冒發燒,在家休息好幾天,傷···。git
系列目錄:github
本章節複習的是JS中對象的使用,這是重點。 正則表達式
前置知識:
JavaScrip的設計是一個簡單的基於對象的範式。
對象是一系列屬性的集合,一個屬性包含一個鍵和一個值,也叫鍵值對。
若一個屬性的值,是一個函數,則稱這個屬性爲方法。 segmentfault
一個對象,能夠有不少方法,就像一個杯子,能夠有顏色,重量,形狀等屬性。 數組
注意:
對象的名稱,對大小寫敏感。微信
本文主要是複習對象的使用,至於對象的建立,下面這裏簡單介紹一下常見的建立對象的方法: ide
建立方法1:函數
let obj = new Object(); // 聲明一個空對象
建立方法2:post
let obj = {}; // 聲明一個空對象
上面的name
是對象obj
中的一個屬性,對應的值爲"leo"
。
設置對象屬性,也有兩種方法:
直接設置:
let obj = {}; obj.name = "leo"; // 爲對象添加屬性和值
建立時設置:
let obj = {name : 'leo'}; obj.name = "leo"; // 爲對象添加屬性和值
當一個對象定義了一個屬性,咱們能夠用點符號(.
)來訪問它。
obj.name; // "leo"
注意:
let obj = {}; let n = "name"; obj[n] = "leo"; // 屬性名使用變量 obj["height"] = 188; // 字符串 obj["age" + "Is"] = 15; // 字符串拼接 console.log(obj); /* obj = { ageIs: 15 height: 188 name: "leo" } */
let obj = {}; obj.getTime = function(){ return new Date(); } obj.getTime(); // 訪問屬性的方法 //Wed Jan 02 2019 21:07:59 GMT+0800 (中國標準時間)
從 ECMAScript 5 開始,有三種原生的方法用於列出或枚舉對象的屬性:
該方法依次訪問一個對象及其原型鏈中全部可枚舉的屬性。
let obj = {a:1, b:2, c:3}; for (let i in obj) { console.log("obj." + i + " = " + obj[i]); } /* "obj.a = 1" "obj.b = 2" "obj.c = 3" */
該方法返回一個對象 o
自身包含(不包括原型中)的全部屬性的名稱的數組。
let obj = {a:1, b:2, c:3}; let arr = Object.keys(obj); console.log(arr); /* ["a", "b", "c"] */ arr.forEach(function(val,index,array){ console.log("key:" + val+",val:"+obj[val]) }) /* key:a,val:1 key:b,val:2 key:c,val:3 */
該方法返回一個數組,它包含了對象 o
全部擁有的屬性(不管是否可枚舉)的名稱。
let obj = {a:1, b:2, c:3}; let arr = Object.getOwnPropertyNames(obj); console.log(arr); /* ["a", "b", "c"] */ arr.forEach(function(val,index,array){ console.log("key:" + val+",val:"+obj[val]) }) /* key:a,val:1 key:b,val:2 key:c,val:3 */
let a = 'a1'; let b = { a }; // b => { a : 'a1' } // 等同於 let b = { a : a }; function f(a, b){ return {a, b}; } // 等同於 function f (a, b){ return {a:a ,b:b}; } let a = { fun () { return 'leo'; } } // 等同於 let a = { fun : function(){ return 'leo'; } }
JavaScript
提供2種方法定義對象的屬性。
// 方法1 標識符做爲屬性名 a.f = true; // 方法2 字符串做爲屬性名 a['f' + 'un'] = true;
延伸出來的還有:
let a = 'hi leo'; let b = { [a]: true, ['a'+'bc']: 123, ['my' + 'fun'] (){ return 'hi'; } }; // b.a => undefined ; b.abc => 123 ; b.myfun() => 'hi' // b[a] => true ; b['abc'] => 123 ; b['myfun'] => ƒ ['my' + 'fun'] (){ return 'hi'; }
注意:
屬性名錶達式不能與簡潔表示法同時使用,不然報錯。
// 報錯 let a1 = 'aa'; let a2 = 'bb'; let b1 = {[a1]}; // 正確 let a1 = 'aa'; let b1 = { [a1] : 'bb'};
Object.is()
用於比較兩個值是否嚴格相等,在ES5時候只要使用相等運算符(==
)和嚴格相等運算符(===
)就能夠作比較,可是它們都有缺點,前者會自動轉換數據類型,後者的NaN
不等於自身,以及+0
等於-0
。
Object.is('a','a'); // true Object.is({}, {}); // false // ES5 +0 === -0 ; // true NaN === NaN; // false // ES6 Object.is(+0,-0); // false Object.is(NaN,NaN); // true
Object.assign()
方法用於對象的合併,將原對象的全部可枚舉屬性複製到目標對象。
基礎用法:
第一個參數是目標對象,後面參數都是源對象。
let a = {a:1}; let b = {b:2}; Object.assign(a,b); // a=> {a:1,b:2}
注意:
let a = {a:1, b:2}; let b = {b:3, c:4}; Object.assign(a, b); // a => {a:1, b:3, c:4}
let a = {a:1}; Object.assign(a) === a; // true
typeof Object.assign(2); // 'object'
undefined
或NaN
沒法轉成對象,因此作爲參數會報錯。Object.assign(undefined) // 報錯 Object.assign(NaN); // 報錯
Object.assign()
實現的是淺拷貝。Object.assign()
拷貝獲得的是這個對象的引用。這個對象的任何變化,都會反映到目標對象上面。
let a = {a: {b:1}}; let b = Object.assign({},a); a.a.b = 2; console.log(b.a.b); // 2
Object.assign([1, 2, 3], [4, 5]); // [4, 5, 3]
ES7中新增長的 Object.values()
和Object.entries()
與以前的Object.keys()
相似,返回數組類型。
回顧下Object.keys()
:
var a = { f1: 'hi', f2: 'leo'}; Object.keys(a); // ['f1', 'f2']
返回一個數組,成員是參數對象自身的(不含繼承的)全部可遍歷屬性的鍵值。
let a = { f1: 'hi', f2: 'leo'}; Object.values(a); // ['hi', 'leo']
若是參數不是對象,則返回空數組:
Object.values(10); // [] Object.values(true); // []
返回一個數組,成員是參數對象自身的(不含繼承的)全部可遍歷屬性的鍵值對數組。
let a = { f1: 'hi', f2: 'leo'}; Object.entries(a); // [['f1','hi'], ['f2', 'leo']]
遍歷對象屬性。
let a = { f1: 'hi', f2: 'leo'}; for (let [k, v] of Object.entries(a)){ console.log( `${JSON.stringfy(k)}:${JSON.stringfy(v)}` ) } // 'f1':'hi' // 'f2':'leo'
將對象轉爲真正的Map結構。
let a = { f1: 'hi', f2: 'leo'}; let map = new Map(Object.entries(a));
手動實現Object.entries()
方法:
// Generator函數實現: function* entries(obj){ for (let k of Object.keys(obj)){ yield [k ,obj[k]]; } } // 非Generator函數實現: function entries (obj){ let arr = []; for(let k of Object.keys(obj)){ arr.push([k, obj[k]]); } return arr; }
以前有Object.getOwnPropertyDescriptor
方法會返回某個對象屬性的描述對象,新增的Object.getOwnPropertyDescriptors()
方法,返回指定對象全部自身屬性(非繼承屬性)的描述對象,全部原對象的屬性名都是該對象的屬性名,對應的屬性值就是該屬性的描述對象
let a = { a1:1, get f1(){ return 100} } Object.getOwnPropetyDescriptors(a); /* { a:{ configurable:true, enumerable:true, value:1, writeable:true} f1:{ configurable:true, enumerable:true, get:f, set:undefined} } */
實現原理:
function getOwnPropertyDescriptors(obj) { const result = {}; for (let key of Reflect.ownKeys(obj)) { result[key] = Object.getOwnPropertyDescriptor(obj, key); } return result; }
引入這個方法,主要是爲了解決Object.assign()
沒法正確拷貝get
屬性和set
屬性的問題。
let a = { set f(v){ console.log(v) } } let b = {}; Object.assign(b, a); Object.a(b, 'f'); /* f = { configurable: true, enumable: true, value: undefined, writeable: true } */
value
爲undefined
是由於Object.assign
方法不會拷貝其中的get
和set
方法,使用getOwnPropertyDescriptors
配合Object.defineProperties
方法來實現正確的拷貝:
let a = { set f(v){ console.log(v) } } let b = {}; Object.defineProperties(b, Object.getOwnPropertyDescriptors(a)); Object.getOwnPropertyDescriptor(b, 'f') /* configurable: true, enumable: true, get: undefined, set: function(){...} */
Object.getOwnPropertyDescriptors
方法的配合Object.create
方法,將對象屬性克隆到一個新對象,實現淺拷貝。
const clone = Object.create(Object.getPrototypeOf(obj), Object.getOwnPropertyDescriptors(obj)); // 或者 const shallowClone = (obj) => Object.create( Object.getPrototypeOf(obj), Object.getOwnPropertyDescriptors(obj) );
對象的拓展運算符,即對象的Rest/Spread屬性,可將對象解構賦值用於從一個對象取值,搜鍵值對分配到指定對象上,與數組的拓展運算符相似:
let {x, y, ...z} = {x:1, y:2, a:3, b:4}; x; // 1 y; // 2 z; // {a:3, b:4}
對象的解構賦值要求等號右邊必須是個對象,因此若是等號右邊是undefined
或null
就會報錯沒法轉成對象。
let {a, ...b} = null; // 運行時報錯 let {a, ...b} = undefined; // 運行時報錯
解構賦值必須是最後一個參數,不然報錯。
let {...a, b, c} = obj; // 語法錯誤 let {a, ...b, c} = obj; // 語法錯誤
注意:
let a = {a1: {a2: 'leo'}}; let {...b} = a; a.a1.a2 = 'leo'; b.a1.a2 = 'leo';
let o1 = { a: 1 }; let o2 = { b: 2 }; o2.__proto__ = o1; let { ...o3 } = o2; o3; // { b: 2 } o3.a; // undefined
let a = { a1:1, a2:2 }; let b = { ...a }; b; // { a1:1, a2:2 } // 相似Object.assign方法
let a = { a1:1, a2:2 }; let b = { b1:11, b2:22 }; let ab = { ...a, ...b }; // {a1: 1, a2: 2, b1: 11, b2: 22} // 等同於 let ab = Object.assign({}, a, b);
let a = { a1:1, a2:2, a3:3 }; let r = { ...a, a3:666 }; // r {a1: 1, a2: 2, a3: 666} // 等同於 let r = { ...a, ...{ a3:666 }}; // r {a1: 1, a2: 2, a3: 666} // 等同於 let r = Object.assign({}, a, { a3:666 }); // r {a1: 1, a2: 2, a3: 666}
let a = { a1:1, a2:2 }; let r = { a3:666, ...a }; // r {a3: 666, a1: 1, a2: 2} // 等同於 let r = Object.assign({}, {a3:666}, a); // r {a3: 666, a1: 1, a2: 2} // 等同於 let r = Object.assign({a3:666}, a); // r {a3: 666, a1: 1, a2: 2}
let a = { ...(x>1? {a:!:{}), b:2 }
{...{}, a:1}; // {a:1}
null
或undefined
則忽略且不報錯。let a = { ...null, ...undefined }; // 不報錯
get
則會執行。// 不會打印 由於f屬性只是定義 而不沒執行 let a = { ...a1, get f(){console.log(1)} } // 會打印 由於f執行了 let a = { ...a1, ...{ get f(){console.log(1)} } }
1.MDN 使用對象
2.W3school JavaScript 對象
本部份內容到這結束
Author | 王平安 |
---|---|
pingan8787@qq.com | |
博 客 | www.pingan8787.com |
微 信 | pingan8787 |
每日文章推薦 | https://github.com/pingan8787... |
JS小冊 | js.pingan8787.com |
歡迎關注微信公衆號【前端自習課】天天早晨,與您一塊兒學習一篇優秀的前端技術博文 .