Javascript Object常用方法總結

fozero發表於2019-06-10

Object.keys方法

Object.keys方法是JavaScript中用於遍歷物件屬性的一個方法 。它傳入的引數是一個物件,返回的是一個陣列,陣列中包含的是該物件所有的屬性名。
如:

var cat= { 
name:’mini’, 
age:2, 
color:’yellow’, 
desc:”cute” 
}
console.log(Object.keys(cat)); // ["name", "age", "color", "desc"]

這裡有一道關於Object.keys的題目

輸出物件中值大於2的key的陣列

var data = {a: 1, b: 2, c: 3, d: 4};
Object.keys(data).filter(function(x) { return 1 ;})

期待輸出:[“c”,”d”]
請問1處填什麼?

正確答案:1 :data[x]>2

Object.keys是es5中新增的方法,用來獲取物件自身所有的可列舉的屬性名,但不包括原型中的屬性,然後返回一個由屬性名組成的陣列。注意它同for..in一樣不能保證屬性按物件原來的順序輸出。
Object.getOwnPropertyNames也是es5中新增的方法,返回物件的所有自身屬性的屬性名(包括不可列舉的屬性)組成的陣列,但不會獲取原型鏈上的屬性。

Array.filter(function)對陣列進行過濾返回符合條件的陣列。

Object.values()方法

Object.values方法返回一個陣列,成員是引數物件自身的(不含繼承的)所有可遍歷( enumerable )屬性的鍵值。

var obj = { foo: "bar", baz: 42 };  
Object.values(obj)  
// ["bar", 42]  

返回陣列的成員順序,屬性名為數值的屬性,是按照數值大小,從小到大遍歷的,因此返回的順序是b、c、a。Object.values只返回物件自身的可遍歷屬性。

var obj = { 100: 'a', 2: 'b', 7: 'c' };  
Object.values(obj)  
// ["b", "c", "a"]  

如果Object.values方法的引數是一個字串,會返回各個字元組成的一個陣列。

Object.values('foo')  
// ['f', 'o', 'o']  

上面程式碼中,字串會先轉成一個類似陣列的物件。字串的每個字元,就是該物件的一個屬性。因此,Object.values返回每個屬性的鍵值,就是各個字元組成的一個陣列。
如果引數不是物件,Object.values會先將其轉為物件。由於數值和布林值的包裝物件,都不會為例項新增非繼承的屬性。所以,Object.values會返回空陣列。

Object.create()

Object.create()方法建立一個新物件,使用現有的物件來提供新建立的物件的__proto__。
語法
Object.create(proto, [propertiesObject])
引數
proto
新建立物件的原型物件。
propertiesObject
可選。如果沒有指定為 undefined,則是要新增到新建立物件的可列舉屬性(即其自身定義的屬性,而不是其原型鏈上的列舉屬性)物件的屬性描述符以及相應的屬性名稱。這些屬性對應Object.defineProperties()的第二個引數。
返回值
一個新物件,帶著指定的原型物件和屬性。
如:

var parent = {
    x : 1,
    y : 1
}
var child = Object.create(parent,{
    z : {                           // z會成為建立物件的屬性
        writable:true,
        configurable:true,
        value: "newAdd"
    }
});
console.log(child)//{z: "newAdd"}z: "newAdd"__proto__: x: 1y: 1__proto__: Object

Object.create()建立繼承

function A(){
  this.a = 1;
  this.b = 2;
}
A.prototype.drive = function(){
  console.log('drivvvvvvvvvv');
}
//方式1
function B(){}
B.prototype = Object.create(new A()); //這裡採用了new 一個例項
//方式2
function C(){
  A.call(this);
}
C.prototype = Object.create(A.prototype) //這裡使用的是父類的原型

以上兩種方式有什麼區別?
1的缺點:
執行了 new,相當於執行了一遍 A ,如果在 A 裡做了一些其它事情(如改變全域性變數)就會有副作用。
用 A 建立的物件做原型,裡面可能會有一些冗餘的屬性。
2模擬了 new 的執行過程

Object.hasOwnProperty()方法

判斷物件自身屬性中是否具有指定的屬性。

在某個物件是否擁有某個屬性,判斷的方法有很多,常用的方法就是object.hasOwnProperty('×××'),這個方法是不包括物件原型鏈上的方法的

var obj = {
name:'fei'
}
console.log(obj.hasOwnProperty('name'))//true
console.log(obj.hasOwnProperty('toString'))//false


以上,obj物件存在的name屬性的時候,呼叫這個方法才是返回true,我們知道其實每個物件例項的原型鏈上存在toString方法,在這裡列印false,說明這個方法只是表明例項物件的屬性,不包括原型鏈上的屬性。

## Object.getOwnPropertyNames()方法
Object.getOwnPropertyNames()方法返回物件的所有自身屬性的屬性名(包括不可列舉的屬性)組成的陣列,但不會獲取原型鏈上的屬性。

function A(a,aa) {
this.a = a;
this.aa = aa;
this.getA = function() {
return this.a;
}
}
// 原型方法
A.prototype.aaa = function () {};

var B = new A('b', 'bb');
B.myMethodA = function() {};
// 不可列舉方法
Object.defineProperty(B, 'myMethodB', {
enumerable: false,
value: function() {}
});

Object.getOwnPropertyNames(B); // ["a", "aa", "getA", "myMethodA", "myMethodB"]


### Object.getOwnPropertyNames和Object.keysq區別
Object.getOwnPropertyNames和Object.keys的區別,即Object.keys只適用於可列舉的屬性,而Object.getOwnPropertyNames返回物件自動的全部屬性名稱。

'use strict';
(function(){
if(!Object.getOwnPropertyNames){
console.log('瀏覽器不支援getOwnPropertyNames');
return;
}

//人類的建構函式
var person = function(name, age, sex){
    this.name = name;
    this.age = age;
    this.sex = sex;
    
    this.sing = function(){
        console.log('sing');
    }
}
//new 一個ladygaga
var gaga = new person('ladygaga', 26, 'girl');

//給嘎嘎發放一個不可列舉的身份證
Object.defineProperty(gaga, 'id', {
    value : '1234567890',
    enumerable : false
});

//檢視gaga的個人資訊
var arr = Object.getOwnPropertyNames(gaga);
document.write(arr); //output: name,age,sex,sing,id

document.write('</br>');

   //注意和getOwnPropertyNames的區別,不可列舉的id沒有輸出
var arr1 = Object.keys(gaga);
document.write(arr1); //output: name,age,sex,sing
})();


## es6 javascript物件方法Object.assign()
Object.assign方法用於物件的合併,將源物件( source )的所有可列舉屬性,複製到目標物件( target )。

var target = { a: 1 };
var source1 = { b: 2 };
var source2 = { c: 3 };
Object.assign(target, source1, source2);
target // {a:1, b:2, c:3}

1、如果目標物件與源物件有同名屬性,或多個源物件有同名屬性,則後面的屬性會覆蓋前面的屬性。
2、如果只有一個引數,Object.assign會直接返回該引數。

var obj = {a: 1};
Object.assign(obj) === obj // true

3、如果該引數不是物件,則會先轉成物件,然後返回。
4、由於undefined和null無法轉成物件,所以如果它們作為引數,就會報錯。
5、Object.assign方法實行的是淺拷貝,而不是深拷貝。也就是說,如果源物件某個屬性的值是物件,那麼目標物件拷貝得到的是這個物件的引用。

var obj1 = {a: {b: 1}};
var obj2 = Object.assign({}, obj1);
obj1.a.b = 2;
obj2.a.b // 2

上面程式碼中,源物件obj1的a屬性的值是一個物件,Object.assign拷貝得到的是這個物件的引用。這個物件的任何變化,都會反映到目標物件上面。
### 常見用途
( 1 )為物件新增屬性

class Point {
constructor(x, y) {
Object.assign(this, {x, y});
}
}

上面方法通過Object.assign方法,將x屬性和y屬性新增到Point類的物件例項。

( 2 )為物件新增方法

Object.assign(SomeClass.prototype, {
someMethod(arg1, arg2) {
···
},
anotherMethod() {
···
}
});
// 等同於下面的寫法
SomeClass.prototype.someMethod = function (arg1, arg2) {
···
};
SomeClass.prototype.anotherMethod = function () {
···
};

上面程式碼使用了物件屬性的簡潔表示法,直接將兩個函式放在大括號中,再使用 assign 方法新增到 SomeClass.prototype 之中。
( 3 )克隆物件

function clone(origin) {
return Object.assign({}, 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) {
let options = Object.assign({}, DEFAULTS, options);
}

上面程式碼中,DEFAULTS物件是預設值,options物件是使用者提供的引數。Object.assign方法將DEFAULTS和options合併成一個新物件,如果兩者有同名屬性,則option的屬性值會覆蓋DEFAULTS的屬性值。
注意,由於存在深拷貝的問題,DEFAULTS物件和options物件的所有屬性的值,都只能是簡單型別,而不能指向另一個物件。否則,將導致DEFAULTS物件的該屬性不起作用。
> 參考https://blog.csdn.net/qq_30100043/article/details/53422657


## Object.defineProperty()方法理解
> Object.defineProperty可以用來定義新屬性或修改原有的屬性

使用建構函式定義物件和屬性

var obj = new Object; //obj = {}
obj.name = "張三"; //新增描述
obj.say = function(){}; //新增行為


### 語法

Object.defineProperty(obj, prop, descriptor)

引數說明
obj:必需。目標物件 
prop:必需。需定義或修改的屬性的名字
descriptor:必需。目標屬性所擁有的特性

**給物件的屬性新增特性描述,目前提供兩種形式:資料描述和存取器描述**
### 資料描述
修改或定義物件的某個屬性的時候,給這個屬性新增一些特性, 資料描述中的屬性都是可選的

var obj = {
test:"hello"
}
//物件已有的屬性新增特性描述Object.defineProperty(obj,"test",{
configurable:true | false,
enumerable:true | false,
value:任意型別的值,
writable:true | false
});
//物件新新增的屬性的特性描述Object.defineProperty(obj,"newKey",{
configurable:true | false,
enumerable:true | false,
value:任意型別的值,
writable:true | false
});

value: 設定屬性的值
writable: 值是否可以重寫。true | false
enumerable: 目標屬性是否可以被列舉。true | false
configurable: 目標屬性是否可以被刪除或是否可以再次修改特性 true | false

### 存取器描述
使用存取器描述屬性的特性的時候,允許設定以下特性屬性, 當使用了getter或setter方法,不允許使用writable和value這兩個屬性

var obj = {};
Object.defineProperty(obj,"newKey",{
get:function (){} | undefined,
set:function (value){} | undefined
configurable: true | false
enumerable: true | false
});

**getter/setter**
getter 是一種獲得屬性值的方法
setter是一種設定屬性值的方法。
使用get/set屬性來定義對應的方法

var obj = {};
var initValue = 'hello';
Object.defineProperty(obj,"newKey",{
get:function (){
//當獲取值的時候觸發的函式
return initValue;
},
set:function (value){
//當設定值的時候觸發的函式,設定的新值通過引數value拿到
initValue = value;
}
});
//獲取值console.log( obj.newKey ); //hello

//設定值
obj.newKey = 'change value';

console.log( obj.newKey ); //change value
```

相容性

在ie8下只能在DOM物件上使用,嘗試在原生的物件使用 Object.defineProperty()會報錯。
參考https://segmentfault.com/a/1190000007434923

相關文章