所謂「靜態方法」,是指部署在Object
對象自身的方法 ---(此句話摘自 阮一峯博客)數組
Object.keys()方法與Object.getOwnPropertyNames方法很類似,通常用來遍歷對象的(屬性名,索引),並返回一個數組,該數組成員都是對象自身的(不是繼承的),區別在於Object.keys方法只返回可枚舉的屬性,Object.getOwnPropertyNames方法還能返回不可枚舉的屬性名函數
1.Object.keysthis
// 定義一個 Array 對象 let arr = ["a", "b", "c"]; // 定義一個 Object 對象 let obj = { foo: "bar", baz: 42 }; // 定義一個 類數組 對象 let ArrayLike = { 0 : "a", 1 : "b", 2 : "c"}; // 類數組 對象, 隨機 key 排序 let anObj = { 100: 'a', 2: 'b', 7: 'c' }; /* getFoo 是個不可枚舉的屬性 */ var my_obj = Object.create({}, { getFoo : { value : function () { return this.foo } } } ); my_obj.foo = 1; // 打印結果 console.log(Object.keys(arr)); // ['0', '1', '2'] console.log(Object.keys(obj)); // ["foo","baz"] console.log(Object.keys(ArrayLike)); // ['0', '1', '2'] console.log(Object.keys(anObj)); // ['2', '7', '100'] console.log(Object.keys(my_obj)); // ['foo']
返回數組中的排序與for..in是一致的,區別在於for..in循環還能夠枚舉原型鏈上的屬性spa
2.Object.getOwnPropertyNamesprototype
// 定義一個數組 var arr = ["a", "b", "c"]; // 定義一個 類數組對象 var obj = { 0: "a", 1: "b", 2: "c"}; //定義一個 不可枚舉屬性 var my_obj = Object.create({}, { getFoo: { value: function() { return this.foo; }, enumerable: false } }); my_obj.foo = 1; // 打印結果 console.log(Object.getOwnPropertyNames(arr).sort()); // ["0", "1", "2", "length"] console.log(Object.getOwnPropertyNames(obj).sort()); // ["0", "1", "2"] console.log(Object.getOwnPropertyNames(my_obj).sort()); // ["foo", "getFoo"]
3.對象屬性相關的方法翻譯
// 看此方法以前,我以爲應該先了解一下,對象的屬性分爲哪兩種,插句題外話,O(∩_∩)O哈哈~
對象裏目前存在的屬性描述符有兩種主要形式:數據描述符 和 存取描述符。code
數據描述符: 是一個具備值的屬性,該值多是可寫的,也可能不是可寫的。對象
訪問器描述符: 是由getter-setter函數對描述的屬性。描述符必須是這兩種形式之一;不能同時是二者。blog
數據描述符和存取描述符均具備如下可選鍵值:排序
configurable: 當且僅當該屬性的 configurable 爲 true 時,該屬性描述符
纔可以被改變,同時該屬性也能從對應的對象上被刪除。默認爲 false。
enumerable: 當且僅當該屬性的enumerable
爲true
時,該屬性纔可以出如今對象的枚舉屬性中。默認爲 false。
value: 該屬性對應的值。能夠是任何有效的 JavaScript 值(數值,對象,函數等)。默認爲 undefined。
writable: 當且僅當該屬性的writable
爲true
時,value
才能被賦值運算符改變。默認爲 false。
getter: 一個給屬性提供 getter 的方法,若是沒有 getter 則爲 undefined
。該方法返回值被用做屬性值。默認爲 undefined。
setter: 一個給屬性提供 setter 的方法,若是沒有 setter 則爲 undefined
。該方法將接受惟一參數,並將該參數的新值分配給該屬性。默認爲 undefined。
記住,這些選項不必定是自身屬性,若是是繼承來的也要考慮。爲了確認保留這些默認值,你可能要在這以前凍結 Object.prototype
,明確指定全部的選項,或者將 __proto__
屬性指向null
。
a).Object.getOwnPropertyDescriptor( obj, prop) 返回一個指定對象上的自有屬性對應的屬性描述 (自由屬性指,直接賦值的屬性,不須要從原型上查找的屬性)
參數:
obj 須要查找的目標對象
prop 目標對象內的屬性名稱
let o = { get foo() { return 17; } }; let d = Object.getOwnPropertyDescriptor(o, "foo"); let o1 = { bar: 42 }; let d1 = Object.getOwnPropertyDescriptor(o1, "bar"); let o2 = {}; Object.defineProperty(o2, "baz", { value: 8675309, writable: false, enumerable: false }); let d2 = Object.getOwnPropertyDescriptor(o2, "baz"); console.log(d)// {configurable: true, enumerable: true, get: [Function: get foo],set: undefined} console.log(d1)//{configurable: true, enumerable: true, value: 42, writable: true} console.log(d2)// {value: 8675309, writable: false, enumerable: false, configurable: false}
注意事項:ES5第一個參數不是對象,就會產生TypeError, ES2015第一個參數不是對象的話,就會被強制轉換成對象
b).Object.defineProperty( obj, prop, decriptor) 直接在一個對象上定義一個新屬性,或修改一個對象的現有屬性,並返回這個對象,默認狀況下使用此方法添加的屬性值是不能被修改的
參數:
obj 要在其上定義屬性的對象
prop 要定義或修改的屬性名稱
decriptor 將被定義或修改的屬性描述符
var o = {}; // 建立一個新對象 // 在對象中添加一個屬性與數據描述符的示例 Object.defineProperty(o, "a", { value : 37, writable : true, enumerable : true, configurable : true }); // 對象o擁有了屬性a,值爲37 // 在對象中添加一個屬性與存取描述符的示例 var bValue; Object.defineProperty(o, "b", { get : function(){ return bValue; }, set : function(newValue){ bValue = newValue; }, enumerable : true, configurable : true }); o.b = 38; // 對象o擁有了屬性b,值爲38 // o.b的值如今老是與bValue相同,除非從新定義o.b // 數據描述符和存取描述符不能混合使用 Object.defineProperty(o, "conflict", { value: 0x9f91102, get: function() { return 0xdeadbeef; } }); // TypeError: Invalid property descriptor. Cannot both specify accessors and a value or writable attribute(無效的屬性描述符,不能同時指定訪問器和值或可寫屬性)
c).Object.defineProperties()
d).Object.getOwnPropertyNames()
4.控制對象狀態的方法
a).Object.preventExtensions() 防止對象擴展
b).Object.isExtensible() 判斷對象是否可擴展
c).Object.seal() 禁止對象配置
d).Object.isSealed() 判斷一個對象是否可配置
e).Object.freeze() 凍結一個對象
f).Object.isFrozen() 判斷一個對象是否被凍結
5.原型鏈相關方法
a).Object.creat() 能夠指定原型對象和屬性,返回一個新的對象
b).Object.getPrototypeOf() 獲取對的的Prototype對象
除了Object
對象自己的方法,還有很多方法是部署在Object.prototype
對象上的,全部Object
的實例對象都繼承了這些方法。Object
實例對象的方法,主要有如下六個。(此句摘自 --阮一峯 博客)
a). valueOf()
返回當前對象對應的值
b). toString()
返回當前對象對應的字符串形式,用來判斷一個值的類型
c). toLocaleString()
返回當前對象對應的本地字符串形式
d). hasOwnProperty()
判斷某個屬性是否爲當前對象自身的屬性,仍是繼承自原型對象的屬性
e). isPrototypeOf()
判斷當前對象是否爲另外一個對象的原型
f). propertyIsEnumerable()
判斷某個屬性是否可枚舉
(摘自 阮一峯ECMAScript 6 入門 )
1.屬性的簡潔寫法
ES6 容許在對象之中,直接寫變量。這時,屬性名爲變量名, 屬性值爲變量的值。
屬性簡寫
function f(x, y) { return {x, y}; } // 等同於 function f(x, y) { return {x: x, y: y}; } f(1, 2) // Object {x: 1, y: 2}
方法名簡寫
const o = { method() { return "Hello!"; } }; // 等同於 const o = { method: function() { return "Hello!"; } };
屬性簡寫與方法名簡寫,例:
let birth = '2000/01/01'; const Person = { name: '張三', //等同於birth: birth birth, // 等同於hello: function ()... hello() { console.log('個人名字是', this.name); } };
CommonJS 模塊輸出一組變量,就很是合適使用簡潔寫法
let ms = {}; function getItem (key) { return key in ms ? ms[key] : null; } function setItem (key, value) { ms[key] = value; } module.exports = { getItem, setItem }; // 等同於 module.exports = { getItem: getItem, setItem: setItem };
屬性的賦值器(setter)和取值器(getter),事實上也是採用這種寫法
const cart = { _wheels: 4, get wheels () { return this._wheels; }, set wheels (value) { if (value < this._wheels) { throw new Error('數值過小了!'); } this._wheels = value; } }
2.屬性名錶達式
方法一,是直接用標識符做爲屬性名
方法二,是用表達式做爲屬性名,這時要將表達式放在方括號以內。
// 方法一 obj.foo = true; // 方法二 obj['a' + 'bc'] = 123;
表達式還能夠用作方法名
let obj = { ['h' + 'ello']() { return 'hi'; } }; obj.hello() // hi
注意,屬性名錶達式與簡潔表示法,不能同時使用,會報錯。
// 報錯 const foo = 'bar'; const bar = 'abc'; const baz = { [foo] }; // 正確 const foo = 'bar'; const baz = { [foo]: 'abc'};
注意,屬性名錶達式若是是一個對象,默認狀況下會自動將對象轉爲字符串[object Object]
,這一點要特別當心。
const keyA = {a: 1}; const keyB = {b: 2}; const myObject = { [keyA]: 'valueA', [keyB]: 'valueB' }; myObject // Object {[object Object]: "valueB"}
上面代碼中,[keyA]
和[keyB]
獲得的都是[object Object]
,因此[keyB]
會把[keyA]
覆蓋掉,而myObject
最後只有一個[object Object]
屬性。
3.方法的 name 屬性
若是對象的方法使用了取值函數(getter
)和存值函數(setter
),則name
屬性不是在該方法上面,而是該方法的屬性的描述對象的get
和set
屬性上面,返回值是方法名前加上get
和set
。
4.Object.is() 它用來比較兩個值是否嚴格相等,與嚴格比較運算符(===)的行爲基本一致
ES5 比較兩個值是否相等,只有兩個運算符:相等運算符(==
)和嚴格相等運算符(===
)。它們都有缺點,前者會自動轉換數據類型,後者的NaN
不等於自身,以及+0
等於-0
。JavaScript 缺少一種運算,在全部環境中,只要兩個值是同樣的,它們就應該相等。
Object.is('foo', 'foo') // true Object.is({}, {}) // false
不一樣之處只有兩個:一是+0
不等於-0
,二是NaN
等於自身。
+0 === -0 //true NaN === NaN // false Object.is(+0, -0) // false Object.is(NaN, NaN) // true
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 });
5.Object.assign( target, source, source1 ) 方法用於對象的合併,將源對象(source)的全部可枚舉屬性,複製到目標對象(target)。拷貝的屬性是有限制的,只拷貝源對象的自身屬性(不拷貝繼承屬性),也不拷貝不可枚舉的屬性(enumerable: false
)
參數
target 目標對象
source 源對象
const target = { a: 1, b: 1 }; const source1 = { b: 2, c: 2 }; const source2 = { c: 3 }; Object.assign(target, source1, source2); target // {a:1, b:2, c:3}
注意,若是目標對象與源對象有同名屬性,或多個源對象有同名屬性,則後面的屬性會覆蓋前面的屬性。
let obj = {a: 1}; Object.assign(obj, undefined) === obj // true Object.assign(obj, null) === obj /
若是非對象參數出如今源對象的位置(即非首參數),那麼處理規則有所不一樣。首先,這些參數都會轉成對象,若是沒法轉成對象,就會跳過。這意味着,若是undefined
和null
不在首參數,就不會報錯。
注意:
a). Object.assign
方法實行的是淺拷貝,而不是深拷貝。也就是說,若是源對象某個屬性的值是對象,那麼目標對象拷貝獲得的是這個對象的引用。
const obj1 = {a: {b: 1}}; const obj2 = Object.assign({}, obj1); obj1.a.b = 2; console.log(obj2.a.b) //2 obj2.a.b = 3 console.log(obj1.a.b) //3
上面代碼中,源對象obj1
的a
屬性的值是一個對象,Object.assign
拷貝獲得的是這個對象的引用。這個對象的任何變化,都會反映到目標對象上面。
b). 數組的處理
Object.assign([1, 2, 3], [4, 5])// [4, 5, 3]
上面代碼中,Object.assign
把數組視爲屬性名爲 0、一、2 的對象,所以源數組的 0 號屬性4
覆蓋了目標數組的 0 號屬性1
。
常見用途
a). 爲對象添加屬性
class Point { constructor(x, y) { Object.assign(this, {x, y}); } }
上面方法經過Object.assign
方法,將x
屬性和y
屬性添加到Point
類的對象實例。
b). 爲對象添加方法
Object.assign(SomeClass.prototype, { someMethod(arg1, arg2) { ··· }, anotherMethod() { ··· } }); // 等同於下面的寫法 SomeClass.prototype.someMethod = function (arg1, arg2) { ··· }; SomeClass.prototype.anotherMethod = function () { ··· };
上面代碼使用了對象屬性的簡潔表示法,直接將兩個函數放在大括號中,再使用assign
方法添加到SomeClass.prototype
之中。
c). 克隆對象
function clone(origin) { return Object.assign({}, origin); }
上面代碼將原始對象拷貝到一個空對象,就獲得了原始對象的克隆。
不過,採用這種方法克隆,只能克隆原始對象自身的值,不能克隆它繼承的值。若是想要保持繼承鏈,能夠採用下面的代碼。
function clone(origin) { let originProto = Object.getPrototypeOf(origin); return Object.assign(Object.create(originProto), origin); }
d). 合併多個對象,將多個對象合併到某個對象。
const merge = (target, ...sources) => Object.assign(target,...sources); //若是但願合併後返回一個新對象,能夠改寫上面函數,對一個空對象合併。 const merge =(...sources) => Object.assign({}, ...sources);
e). 爲屬性指定默認值
6.屬性的可枚舉和可遍歷
可枚舉性
對象的每一個屬性都有一個描述對象(Descriptor),用來控制該屬性的行爲。
a). Object.getOwnPropertyDescriptor
方法能夠獲取該屬性的描述對象。
let obj = { foo: 123 }; Object.getOwnPropertyDescriptor(obj, 'foo') // { value: 123, writable: true, enumerable: true, configurable: true }
目前,有四個操做會忽略enumerable
爲false
的屬性。
for...in
循環:只遍歷對象自身的和繼承的可枚舉的屬性。
Object.keys()
:返回對象自身的全部可枚舉的屬性的鍵名。
JSON.stringify()
:只串行化對象自身的可枚舉的屬性。
Object.assign()
: 忽略enumerable
爲false
的屬性,只拷貝對象自身的可枚舉的屬性。
ES6 規定,全部 Class 的原型的方法都是不可枚舉的。
屬性的遍歷一共有5種:
for...in
循環遍歷對象自身的和繼承的可枚舉屬性(不含 Symbol 屬性)。
Object.keys
返回一個數組,包括對象自身的(不含繼承的)全部可枚舉屬性(不含 Symbol 屬性)的鍵名。
Object.getOwnPropertyNames
返回一個數組,包含對象自身的全部屬性(不含 Symbol 屬性,可是包括不可枚舉屬性)的鍵名。
Object.getOwnPropertySymbols
返回一個數組,包含對象自身的全部 Symbol 屬性的鍵名。
Reflect.ownKeys
返回一個數組,包含對象自身的全部鍵名,無論鍵名是 Symbol 或字符串,也不論是否可枚舉。
7.Object.getOwnPropertyDescriptors()
8.__proto__屬性,Object.setPrototypeOf(),Object.getPrototypeOf()
9.super 關鍵字
10.Object.keys(),Object.values(),Object.entries()
11.對象的擴展運算符
a). 解構賦值
b). 擴展運算符
12.Null 傳導運算符
// 未完待續,內容慢慢添加,\(^o^)/~