const
簡單類型數據常量
// const實際上保證的,並不是變量的值不得改動,而是變量指向的那個內存地址不得改動。對於簡單類型的數據(數值、字符串、布爾值),值就保存在變量指向的那個內存地址,因此等同於常量。 const PI = 3.1415926; console.log(PI)
對象常量
const foo = Object.freeze({}); // 常規模式時,下面一行不起作用; // 嚴格模式時,該行會報錯 foo.prop = 123;
除了將對象本身凍結,對象的屬性也應該凍結。下面是一個將對象徹底凍結的函數。
var constantize = (obj) => { Object.freeze(obj); Object.keys(obj).forEach( (key, i) => { if ( typeof obj[key] === 'object' ) { constantize( obj[key] ); } }); };
屬性的簡潔表示
對象,函數都可以簡寫
var birth = '2000/01/01'; var Person = { name: '張三', //等同於birth: birth birth, // 等同於hello: function ()... hello() { console.log('我的名字是', this.name); } };
CommonJS模塊輸出變量,就非常合適使用簡潔寫法。
var ms = {}; function getItem(key) { return key in ms ? ms[key] : null; } function setItem(key, value) { ms[key] = value; } function clear() { ms = {}; } module.exports = { getItem, setItem, clear }; // 等同於 module.exports = { getItem: getItem, setItem: setItem, clear: clear };
Object.is()
+0 === -0 //true NaN === NaN // false Object.is(+0, -0) // false Object.is(NaN, NaN) // true
Object.assign()
用於對象的合並,如果目標對象與源對象有同名屬性,或多個源對象有同名屬性,則后面的屬性會覆蓋前面的屬性。
var target = { a: 1 }; var source1 = { b: 2 }; var source2 = { c: 3 }; Object.assign(target, source1, source2); target // {a:1, b:2, c:3}
注意點:
Object.assign 方法實行的是淺拷貝
var obj1 = {a: {b: 1}}; var obj2 = Object.assign({}, obj1); obj1.a.b = 2; obj2.a.b // 2
常見用途:
(1)為對象添加屬性
class Point { constructor(x, y) { Object.assign(this, {x, y}); } }
(2)為對象添加方法
Object.assign(SomeClass.prototype, { someMethod(arg1, arg2) { ··· }, anotherMethod() { ··· } }); // 等同於下面的寫法 SomeClass.prototype.someMethod = function (arg1, arg2) { ··· }; SomeClass.prototype.anotherMethod = function () { ··· };
(3)克隆對象
function clone(origin) { return Object.assign({}, origin); }
不過,采用這種方法克隆,只能克隆原始對象自身的值,不能克隆它繼承的值。
想要保持繼承鏈,可以采用下面的代碼。
function clone(origin) { let originProto = Object.getPrototypeOf(origin); return Object.assign(Object.create(originProto), origin); }
(4)合並多個對象
const merge =
(target, ...sources) => Object.assign(target, ...sources);
const merge =
(...sources) => Object.assign({}, ...sources);
(5)為屬性指定默認值
const DEFAULTS = { logLevel: 0, outputFormat: 'html' }; function processContent(options) { options = Object.assign({}, DEFAULTS, options); console.log(options); // ... }
由於存在深拷貝的問題,DEFAULTS
對象和options
對象的所有屬性的值,最好都是簡單類型,不要指向另一個對象。
屬性的遍歷
ES6一共有5種方法可以遍歷對象的屬性。
(1)for...in
for...in
循環遍歷對象自身的和繼承的可枚舉屬性(不含Symbol屬性)。
(2)Object.keys(obj)
Object.keys
返回一個數組,包括對象自身的(不含繼承的)所有可枚舉屬性(不含Symbol屬性)。
(3)Object.getOwnPropertyNames(obj)
Object.getOwnPropertyNames
返回一個數組,包含對象自身的所有屬性(不含Symbol屬性,但是包括不可枚舉屬性)。
(4)Object.getOwnPropertySymbols(obj)
Object.getOwnPropertySymbols
返回一個數組,包含對象自身的所有Symbol屬性。
(5)Reflect.ownKeys(obj)
Reflect.ownKeys
返回一個數組,包含對象自身的所有屬性,不管是屬性名是Symbol或字符串,也不管是否可枚舉。
(對象自身屬性遍歷):
for (var i in data) { if (data.hasOwnProperty(i) === true) { console.log(data[i]) } }
Object.keys(),Object.values(),Object.entries()
ES5 引入了Object.keys
方法,返回一個數組,成員是參數對象自身的(不含繼承的)所有可遍歷(enumerable)屬性的鍵名。
var obj = { foo: 'bar', baz: 42 }; Object.keys(obj) // ["foo", "baz"]
ES2017 引入了跟Object.keys配套的Object.values和Object.entries,作為遍歷一個對象的補充手段,供for...of循環使用。
var obj = { foo: 'bar', baz: 42 }; Object.values(obj) // ["bar", 42]
對象的擴展運算符
(1)解構賦值
let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 }; x // 1 y // 2 z // { a: 3, b: 4 }
(2)擴展運算符
let z = { a: 3, b: 4 }; let n = { ...z }; n // { a: 3, b: 4 }
Null 傳導運算符
編程實務中,如果讀取對象內部的某個屬性,往往需要判斷一下該對象是否存在。比如,要讀取message.body.user.firstName
,安全的寫法是寫成下面這樣。
const firstName = (message && message.body && message.body.user && message.body.user.firstName) || 'default';
這樣的層層判斷非常麻煩,因此現在有一個提案,引入了“Null 傳導運算符”(null propagation operator)?.
,簡化上面的寫法。
const firstName = message?.body?.user?.firstName || 'default';