一篇文章帶你進一步瞭解object屬性

走在前端的大道上javascript

最後更新 2018.12.27html

本篇將本身讀過的相關 javascript Object方法 文章中,對本身有啓發的章節片斷總結在這(會對原文進行刪改),會不斷豐富提煉總結更新。前端

1.Object.keys遍歷

返回一個數組,包括對象自身的(不含繼承的)全部可枚舉屬性

示例代碼:vue

(1) 數組Array對象(返回索引值)java

var arr=[1,2,3];            
Object.keys(arr)         //  ["0", "1", "2」]

(2) object對象(返回key值)面試

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

(3) 類數組,對象segmentfault

var obj = { 0 : "a", 1 : "b", 2 : "c」};
Object.keys(obj)       // ["0", "1", "2"]

(4) 類數組對象 隨機key排序api

var Obj = { 100: 'a’, 2: 'b’,7: 'c’ };
console.log(Object.keys(Obj));     // ['2', '7', '100’]. 返回從小到大排序後的結果

(5) Object.keys僅遍歷對象自己,並將全部可枚舉的屬性組合成一個數組返回數組

var Person = function({name='none', age=18, height=170}={}){
  this.name = name;
  this.age = age;
  this.height = height;
}

Person.prototype = {
  type: 'Animal'
}

var qiu = new Person()

// 將height屬性設置爲 不可枚舉
Object.defineProperty(qiu, 'height', {
  enumerable: false
})

var keys = Object.keys(qiu);
console.log(keys)
// output: ['name', 'age']

(6) 將鍵值類型的查詢param轉換成url的query瀏覽器

const searchObj = {
  title: 'javascript',
  author: 'Nicolas',
  publishing: "O'RELLY",
  language: 'cn'
}
let searchStr = Object.keys(searchObj)
                .map(item => `${item}=${searchObj[item]}`)
                .join('&');
let url = `localhost:8080/api/test?${searchStr}`

遍歷鍵值對的數據時,使用Object.keys真是不二之選。

2.Object.values()

方法返回一個給定對象本身的全部可枚舉屬性值的數組,值的順序與使用for..in循環相同,返回的對象的value值, 與Object.key()相反

(1) 正常對象

var obj={a:1,b:2,c:3};
console.log(Object.values(obj))         //  [1, 2, 3]

(2) 類數組對象

var obj ={0:'a',1:'b',2:'c'};
console.log(Object.values(obj)).       //  [a,b,c]

(3) key值爲無序number

var obj={100:'a',10:'b',1:'1'};
console.log(Object.values(obj)).   // ["1", "b", "a"]

3.Object.getOwnPropertyNames遍歷

返回一個數組,包含對象自身(不含繼承)的全部屬性名

示例代碼:

var Person = function({name='none', age=18, height=170}={}){
  this.name = name;
  this.age = age;
  this.height = height;
}

Person.prototype = {
  type: 'Animal'
}

var qiu = new Person()

// 將height屬性設置爲 不可枚舉
Object.defineProperty(qiu, 'height', {
  enumerable: false
})

var keys = Object.getOwnPropertyNames(qiu);
console.log(keys)
// output: ['name', 'age', 'height']

與Object.keys的區別在於Object.getOwnPropertyNames會把不可枚舉的屬性也返回。除此以外,與Object.keys的表現一致。

3.Object.getPrototypeOf()

javascript中提供Object.getPrototypeOf()方法來得到對象的直接原型。

function Person() {
    this.name = 'sillywa'
}
var person1 = new Person()
Object.getPrototypeOf(person1)  // {constructor: ƒ Person()}
Object.getPrototypeOf(person1.__proto__)  // Object.prototype

var person = {
    name: 'sillywa'
}
var person2 = Object.create(person)
Object.getPrototypeOf(person2)  // {name: "sillywa"}

javascript有如下幾種方法檢測一個對象的原型:

  • isPrototypeOf():檢測一個對象是不是另外一個對象的原型
  • obj.constructor.prototype:檢測非Object.create()建立的對象的原型
var obj1 = {
    name: 'sillywa'
}
var obj2 = Object.create(obj1)

// isPrototypeOf()方法
Object.prototype.isPrototypeOf(obj1)  // true
obj1.isPrototypeOf(obj2)  // true
Object.prototype.isPrototypeOf(obj2)  // true

// obj.constructor.prototype
obj1.constructor.prototype === Object.prototype  // true
// obj1是obj2的原型,如下等式應爲true
obj2.constructor.prototype === obj1  // false
// 而實際上
obj2.constructor.prototype === Object.prototype  // true

以上代碼中obj1obj2的原型,obj2.constructor.prototype === obj1應爲true可是實際上倒是false,由於obj2__proto__裏面並無一個constructor屬性,obj2.constructor其實是obj1__proto__裏面的constructor,因此obj2.constructor.prototype === Object.prototype

4.Object.assign()

Object.assign()方法用於將全部可枚舉屬性的值從一個或多個源對象複製到目標對象,它將返回目標對象,可是 Object.assign() 進行的是淺拷貝,拷貝的是對象的屬性的引用,而不是對象自己。

Object.assign(target, ...sources)

參數:
target:目標對象;
sources:源對象;
返回值:目標對象

(1) 用來複制一個新對象,並不會影響原對象

var obj = { a: 1 };
var copy = Object.assign({}, obj);
console.log(copy);    // { a: 1 }

(2) 用來合併對象屬性,將源對象的全部可枚舉屬性,複製到目標對象

//object.assign(obj, obj2)  obj2是源對象,obj 是目標對象,返回目標對象

var obj = { a: 1 };
var obj2={b:2};

console.log(Object.assign(obj,obj2)===obj);  //true,返回目標對象
console.log(obj);       //{a:1,b:2} obj的值已被更改

(3) 若是目標對象和源對象中有相同的鍵,則屬性將被源對象的屬性覆蓋,後面的源屬性會覆蓋以前的相同鍵的源屬性

var obj = { a: 1 };
var obj2 = {a:5,b:2};
var obj3 = {b:1,d:0};
Object.assign(obj,obj2,obj3);

console.log(obj);       // {a: 5, b: 1, d: 0}
obj和obj2同時擁有相同的鍵a,但兩個值不一樣,obj是目標對象,因此會被源對象obj2的值覆蓋,obj2和obj3也同時擁有相同的鍵b,在拷貝時,obj3排在obj2的後面,因此obj2被覆蓋 ,最終打印結果是:{a:5,b:1,d:0}

(4) 當assign只有一個對象時,則直接返回這個對象,不作任何操做

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

(5) Object.assign()方法實行的是淺拷貝,而不是深拷貝

也就是說,若是源對象某個屬性的值是對象,那麼目標對象拷貝獲得的是這個對象的引用

var obj1 = { a: 0 , b: { c: 0}};
var obj2 = Object.assign({}, obj1);
obj1.b.c=5;

console.log(obj2)       //{a:0,b:{c:5}};

當咱們在改變obj1的值時,並無想改變obj2,但obj2的值也發生了改變,這違背了咱們的想法。

(6)深拷貝

var obj1 = { a: 0 , b: { c: 0}};
var obj3 = JSON.parse(JSON.stringify(obj1));
obj1.a = 4;
obj1.b.c = 4;
console.log(obj3);     //{ a: 0 , b: { c: 0}};

5.Object.create()

Object.create() 方法會使用指定的原型對象及其屬性去建立一個新的對象。

語法:

Object.create(proto[, propertiesObject])

參數

proto 新建立對象的原型對象。
propertiesObject 可選。
若是沒有指定爲 undefined,不然是要添加到新建立對象的可枚舉屬性(即其自身定義的屬性,而不是其原型鏈上的枚舉屬性)對象的屬性描述符以及相應的屬性名稱。這些屬性對應Object.defineProperties()的第二個參數。

返回值

在指定原型對象上添加新屬性後的對象。

例外

若是proto參數不是 null 或一個對象,則拋出一個 TypeError 異常。

使用 Object.create 的 propertyObject參數

var o;

// 建立一個原型爲null的空對象
o = Object.create(null);


o = {};
// 以字面量方式建立的空對象就至關於:
o = Object.create(Object.prototype);


o = Object.create(Object.prototype, {
  // foo會成爲所建立對象的數據屬性
  foo: { 
    writable:true,
    configurable:true,
    value: "hello" 
  },
  // bar會成爲所建立對象的訪問器屬性
  bar: {
    configurable: false,
    get: function() { return 10 },
    set: function(value) {
      console.log("Setting `o.bar` to", value);
    }
  }
});

function Constructor(){}
o = new Constructor();
// 上面的一句就至關於:
o = Object.create(Constructor.prototype);
// 固然,若是在Constructor函數中有一些初始化代碼,Object.create不能執行那些代碼


// 建立一個以另外一個空對象爲原型,且擁有一個屬性p的對象
o = Object.create({}, { p: { value: 42 } })

// 省略了的屬性特性默認爲false,因此屬性p是不可寫,不可枚舉,不可配置的:
o.p = 24
o.p
//42

o.q = 12
for (var prop in o) {
   console.log(prop)
}
//"q"

delete o.p
//false

//建立一個可寫的,可枚舉的,可配置的屬性p
o2 = Object.create({}, {
  p: {
    value: 42, 
    writable: true,
    enumerable: true,
    configurable: true 
  } 
});

咱們知道經過Object.create()建立的對象實際上等於將該對象的__proto__指向Object.create()裏面的參數對象,那麼當涉及到原型時它是怎麼工做的呢?

var a = {
    name: 'sillywa'
}
var b = Object.create(a)

b.__proto__ === Object.prototype  // false
b.__proto__ === a  // true
b.__proto__.constructor === Object  // true
b.__proto__.hasOwnProperty('constructor')  // false

var b = Object.create(a)其實是把b__proto__指向了a。當訪問b.constructor時,實際上訪問的是b.__proto__.__proto__.constructor

6.delete

咱們要明確一點刪除屬性的方法只有一個是 delete ,可是在咱們的開發中咱們有時每每將屬性值設爲 null,undefined 就說成是將屬性刪除,這是不對的這樣作僅僅是取消了屬性和值之間的關聯。
咱們能夠經過 Object.hasOwnProperty() 這個方法來看一看;

let foo = {
    name: 'foo',
    firstChild: '1st foo',
    twoChild: '2th foo'
};

foo.name = undefined; // undefined
foo.firstChild = null; // null
delete foo.twoChild; // true
for (let key in foo) {
    console.log('key:' + key + ', value:' + foo[key]);
}
/* 
key:name, value:undefined
key:firstChild, value: null
*/

咱們發現若是用 undefined 和 null 至關於給屬性賦值,只有當用 delete 纔是刪除屬性。
注:定義屬性的名字時要使用通常的字符串並且是連續的字符串,屬性名的定義要避免JavaScript關鍵字,就像咱們有的公司定的對象屬性的訪問用 [] , 對象的方法用 . 。

7.for in

for … in 這個循環體來遍歷對象的屬性,包括對象原型鏈上的屬性。

let obj = {a:1, b:2, c:3}
for (let key in obj) {
    console.log(obj[key]);
}

/*
1
2
3
*/
// 自定義屬性是否可枚舉
function customObjectEnumerable(obj, prop, value, flag) {
    Object.defineProperty(obj, prop, {
        configurable: true,
        value: value,
        enumerable: flag,
        writable: true
    });
};

var obj = {};
customObjectEnumerable(obj, a, 1, false);
customObjectEnumerable(obj, b, 2, false);
for(let key in obj) {console.log(obj[key])}
// undefined

var obj2 = {};
customObjectEnumerable(obj2,'a', 1, true);
customObjectEnumerable(obj2, 'b', 2, true);
for(let key in obj2) {console.log(obj2[key])}
/*
1
2
*/
function Foo() {
    this.name = 'foo',
    this.age = '18'
};

Foo.prototype.geAge = function() {
    console.log(this.name)
};

function Bar() {
    this.name = 'bar';
};

Bar.prototype = new Foo();
Bar.prototype.constructor = Bar; // 修正Bar.prototype.constructor 指向它自己

// 實例化Bar
let myBar = new Bar();

'name' in myBar // true
myBar.hasOwnProperty('name'); // true
myBar.hasOwnProperty('age'); // false

clipboard.png

clipboard.png


8.9.10.11

Object的definePropertydefineProperties這兩個方法在js中的重要性十分重要,主要功能就是用來定義或修改這些內部屬性,與之相對應的getOwnPropertyDescriptorgetOwnPropertyDescriptors就是獲取這行內部屬性的描述


8.Object.defineProperty()

Object.defineProperty() 方法會直接在一個對象上定義一個新屬性,或者修改一個對象的現有屬性, 並返回這個對象。

該方法容許精確添加或修改對象的屬性。經過賦值來添加的普通屬性會建立在屬性枚舉期間顯示的屬性(for...in 或 Object.keys 方法), 這些值能夠被改變,也能夠被刪除。這種方法容許這些額外的細節從默認值改變。默認狀況下,使用Object.defineProperty()添加的屬性值是不可變的。

對象裏目前存在的 屬性描述符有兩種主要形式數據描述符存取描述符

  • 數據描述符 是一個具備值的屬性,該值多是可寫的,也可能不是可寫的。
  • 存取描述符 是由getter-setter函數對描述的屬性。

描述符必須是這兩種形式之一不能同時是二者

若是一個描述符同時設置了value,writable,get和set關鍵字,那麼它將被認爲是一個數據描述符。若是一個描述符同時有value或writable和get或set關鍵字,將會產生一個異常。

數據描述符存取描述符 均具備 如下可選鍵值:

configurable
當且僅當該屬性的 configurable 爲 true 時,該屬性描述符纔可以被改變,同時該屬性也能從對應的對象上被刪除。默認爲 false。
enumerable
當且僅當該屬性的enumerable爲true時,該屬性纔可以出如今對象的枚舉屬性中。默認爲 false。


數據描述符同時具備如下可選鍵值:
value
該屬性對應的值。能夠是任何有效的 JavaScript 值(數值,對象,函數等)。默認爲 undefined。
writable

當且僅當該屬性的writable爲true時,value才能被賦值運算符改變。默認爲 false。


存取描述符同時具備如下可選鍵值:
get
一個給屬性提供 getter 的方法,若是沒有 getter 則爲 undefined。該方法返回值被用做屬性值。默認爲 undefined。
set
一個給屬性提供 setter 的方法,若是沒有 setter 則爲 undefined。該方法將接受惟一參數,並將該參數的新值分配給該屬性。默認爲 undefined。

clipboard.png

語法
Object.defineProperty(obj, prop, descriptor)

參數
obj 要在其上定義屬性的對象。
prop 要定義或修改的屬性的名稱。
descriptor 將被定義或修改的屬性描述符。

返回值
被傳遞給函數的對象。

建立屬性

若是對象中不存在指定的屬性,Object.defineProperty()就建立這個屬性。當描述符中省略某些字段時,這些字段將使用它們的默認值。擁有布爾值的字段的默認值都是false。value,get和set字段的默認值爲undefined。一個沒有get/set/value/writable定義的屬性被稱爲「通用的」,並被「鍵入」爲一個數據描述符。

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; 
  } 
});
// throws a TypeError: value appears only in data descriptors, get appears only in accessor descriptors

Writable 屬性

當writable屬性設置爲false時,該屬性被稱爲「不可寫」。它不能被從新分配。

var o = {}; // Creates a new object

Object.defineProperty(o, 'a', {
  value: 37,
  writable: false
});

console.log(o.a); // logs 37
o.a = 25; // No error thrown
console.log(o.a); // logs 37. The assignment didn't work.

Enumerable 特性

enumerable定義了對象的屬性是否能夠在 for...in 循環和 Object.keys() 中被枚舉。

var o = {};
Object.defineProperty(o, "a", { value : 1, enumerable:true });
Object.defineProperty(o, "b", { value : 2, enumerable:false });
Object.defineProperty(o, "c", { value : 3 }); // enumerable defaults to false
o.d = 4; // 若是使用直接賦值的方式建立對象的屬性,則這個屬性的enumerable爲true

for (var i in o) {    
  console.log(i);  
}
// 打印 'a' 和 'd' (in undefined order)

Object.keys(o); // ["a", "d"]

o.propertyIsEnumerable('a'); // true
o.propertyIsEnumerable('b'); // false
o.propertyIsEnumerable('c'); // false
o.propertyIsEnumerable('d'); // true

Configurable 特性

configurable特性表示對象的屬性是否能夠被刪除,以及除writable特性外的其餘特性是否能夠被修改。

var o = {};
Object.defineProperty(o, "a", { get : function(){return 1;}, 
                                configurable : false } );

// throws a TypeError
Object.defineProperty(o, "a", {configurable : true}); 
// throws a TypeError
Object.defineProperty(o, "a", {enumerable : true}); 
// throws a TypeError (set was undefined previously) 
Object.defineProperty(o, "a", {set : function(){}}); 
// throws a TypeError (even though the new get does exactly the same thing) 
Object.defineProperty(o, "a", {get : function(){return 1;}});
// throws a TypeError
Object.defineProperty(o, "a", {value : 12});

console.log(o.a); // logs 1
delete o.a; // Nothing happens
console.log(o.a); // logs 1

若是o.a的configurable屬性爲true,則不會拋出任何錯誤,而且該屬性將在最後被刪除

添加多個屬性和默認值

考慮特性被賦予的默認特性值很是重要,一般,使用點運算符和Object.defineProperty()爲對象的屬性賦值時,數據描述符中的屬性默認值是不一樣的,以下例所示。

var o = {};

o.a = 1;
// 等同於 :
Object.defineProperty(o, "a", {
  value : 1,
  writable : true,
  configurable : true,
  enumerable : true
});


// 另外一方面,
Object.defineProperty(o, "a", { value : 1 });
// 等同於 :
Object.defineProperty(o, "a", {
  value : 1,
  writable : false,
  configurable : false,
  enumerable : false
});

通常的 Setters 和 Getters

下面的例子展現瞭如何實現一個自存檔對象。 當設置temperature 屬性時,archive 數組會獲取日誌條目。

function Archiver() {
  var temperature = null;
  var archive = [];

  Object.defineProperty(this, 'temperature', {
    get: function() {
      console.log('get!');
      return temperature;
    },
    set: function(value) {
      temperature = value;
      archive.push({ val: temperature });
    }
  });

  this.getArchive = function() { return archive; };
}

var arc = new Archiver();
arc.temperature; // 'get!'
arc.temperature = 11;
arc.temperature = 13;
arc.getArchive(); // [{ val: 11 }, { val: 13 }]

var pattern = {
    get: function () {
        return 'I alway return this string,whatever you have assigned';
    },
    set: function () {
        this.myname = 'this is my name string';
    }
};


function TestDefineSetAndGet() {
    Object.defineProperty(this, 'myproperty', pattern);
}


var instance = new TestDefineSetAndGet();
instance.myproperty = 'test';

// 'I alway return this string,whatever you have assigned'
console.log(instance.myproperty);
// 'this is my name string'
console.log(instance.myname);

當咱們查詢存儲器屬性時會調用getter方法(無參數)。這個方法返回值就是屬性存取表達式返回的值。

當咱們設置存儲器屬性時會調用setter方法(有參數)。這個方法修改存儲器屬性的值。

var obj = {
    num: 12,
    age: 13,
    get num1 () {
        return this.num
    },
    set num1 (value) {
        this.num = value
    },
    get age1 () {
        return this.age
    }
}
obj.num1   // 12
obj.num1 = 120
obj.num1  // 120

obj.age1  // 13
obj.age1 = 130
obj.age1  // 13

存儲器屬性定義爲一個或者兩個和屬性同名的函數,這個函數定義沒有使用function關鍵字而是使用get和set。

能夠看出若是該屬性只有getter方法則只能讀取該屬性不能設置該屬性,一樣若是隻有setter方法就只能設置該屬性,不能讀取該屬性,只有當二者都有時才能正常讀取和設置屬性。

描述符的原型與默認值

通常狀況,咱們會建立一個descriptor對象,而後傳給defineProperty方法。以下:

var descriptor = {
    writable: false
}
Object.defineProperty(obj, 'key', descriptor);

這種狀況是有風險的,若是descriptor的原型上面有相關特性,也會經過原型鏈被訪問到,算入在對key的定義中。好比:

descriptor.__proto__.enumerable = true;
Object.defineProperty(obj, 'key', descriptor);
Object.getOwnPropertyDescriptor(obj,'key'); //返回的enumerable爲true

爲了不發生這樣的意外狀況,官方建議使用Object.freeze凍結對象,或者是使用Object.create(null)建立一個純淨的對象(不含原型)來使用。

接下來的注意點是默認值,首先咱們會想普通的賦值語句會生成怎樣的描述符,如obj.key="value"

可使用Object.getOwnPropertyDescriptor來返回一個屬性的描述符:

obj = {};
obj.key = "value";
Object.getOwnPropertyDescriptor(obj, 'key');
/*輸出
{
    configurable:true,
    enumerable:true,
    value:"value",
    writable:true,
}
*/

這也是複合咱們預期的,經過賦值語句添加的屬性,相關描述符都爲true,可寫可配置可枚舉。可是使用defineProperty定義的屬性,默認值就不是這樣了,其規則是這樣的:

configurable: false
enumerable: false
writable: false
value: undefined

因此這裏仍是要注意下的,使用的時候把描述符寫全,省得默認都成false了。

vue的雙向數據綁定

這個問題在不少前端面試中,會說起,是用Object.defineProperty( ),來監聽數據get和set,來實現數據劫持的

var blog = {
  name: '文章1'
};
console.log(blog.name);  // 文章1

若是想要在執行console.log(blog.name)的同時,直接給 文章1 加個書名號,那要怎麼處理呢?或者說要經過什麼監聽對象 blog的屬性值。這時候Object.defineProperty( )就派上用場了,代碼以下:

var blog= {}
var name = '';
Object.defineProperty(blog, 'name', {
  set: function (value) {
    name = value;
    console.log('歡迎查看' + value);
  },
  get: function () {
    return '《' + name + '》'
  }
})

blog.name = '文章1';  // 歡迎查看文章1
console.log(blog.name);  // 《文章1》

篡改瀏覽器userAgent

好比你想把瀏覽器的userAgent給改了,直接寫navigator.userAgent = 'iPhoneX'.你再輸出一下userAgent,發現並無修改。這是爲何呢?咱們用這行代碼看一下:

Object.getOwnPropertyDescriptor(window, 'navigator');
//輸出
{
    configurable:true,
    enumerable:true,
    get:ƒ (),
    set:undefined
}

緣由就找到了,navigator是有setter的,每次取值總會執行這個set函數來作返回。可是好消息是什麼呢?configurable爲true,那就意味這咱們能夠經過defineProperty來修改這個屬性,代碼就至關簡單了:

Object.defineProperty(navigator, 'userAgent', {get: function(){return 'iphoneX'}})
console.log(navigator.userAgent); //輸出iphoneX

Object.prototype.isPrototypeOf()

isPrototypeOf() 與 instanceof 運算符不一樣。在表達式 "object instanceof AFunction"中,object 的原型鏈是針對 AFunction.prototype 進行檢查的,而不是針對 AFunction 自己。isPrototypeOf() 方法容許你檢查一個對象是否存在於另外一個對象的原型鏈上。

語法

prototypeObj.isPrototypeOf(object)

參數

object
在該對象的原型鏈上搜尋

返回值

Boolean,表示調用對象是否在另外一個對象的原型鏈上。

報錯

TypeError
若是 prototypeObj 爲 undefined 或 null,會拋出 TypeError。

示例

本示例展現了 Baz.prototype, Bar.prototype, Foo.prototypeObject.prototypebaz 對象的原型鏈上:

function Foo() {}
function Bar() {}
function Baz() {}

Bar.prototype = Object.create(Foo.prototype);
Baz.prototype = Object.create(Bar.prototype);

var baz = new Baz();

console.log(Baz.prototype.isPrototypeOf(baz)); // true
console.log(Bar.prototype.isPrototypeOf(baz)); // true
console.log(Foo.prototype.isPrototypeOf(baz)); // true
console.log(Object.prototype.isPrototypeOf(baz)); // true

if (Foo.prototype.isPrototypeOf(baz)) {
  // do something safe
}

Baz.prototype.isPrototypeOf(baz) //true
baz instanceof Baz  //true
baz instanceof Bar //true
baz instanceof Foo //true
baz instanceof Bar //true
var obj1 = {
    name: 'eeee'
}
var obj2 = Object.create(obj1)

// isPrototypeOf()方法
Object.prototype.isPrototypeOf(obj1)  // true
obj1.isPrototypeOf(obj2)  // true
Object.prototype.isPrototypeOf(obj2)  // true

Object.prototype.hasOwnProperty()

hasOwnProperty() 方法會返回一個布爾值,指示對象自身屬性中是否具備指定的屬性

語法

obj.hasOwnProperty(prop)

參數

prop 要檢測的屬性 字符串 名稱或者 Symbol。

返回值

用來判斷某個對象是否含有指定的屬性的 Boolean 。

描述

全部繼承了 Object 的對象都會繼承到 hasOwnProperty 方法。這個方法能夠用來檢測一個對象是否含有特定的自身屬性;和 in 運算符不一樣,該方法會忽略掉那些從原型鏈上繼承到的屬性。

示例

1.判斷屬性是否存在

下面的例子檢測了對象 o 是否含有自身屬性 prop:

o = new Object();
o.prop = 'exists';

function changeO() {
  o.newprop = o.prop;
  delete o.prop;
}

o.hasOwnProperty('prop');   // 返回 true
changeO();
o.hasOwnProperty('prop');   // 返回 false
o.hasOwnProperty('newprop');  // 返回 true

2.自身屬性與繼承屬性

下面的例子演示了 hasOwnProperty 方法對待自身屬性和繼承屬性的區別:

o = new Object();
o.prop = 'exists';
o.hasOwnProperty('prop');             // 返回 true
o.hasOwnProperty('toString');         // 返回 false
o.hasOwnProperty('hasOwnProperty');   // 返回 false

3.遍歷一個對象的全部自身屬性

下面的例子演示瞭如何在遍歷一個對象的全部屬性時忽略掉繼承屬性,注意這裏 for...in 循環只會遍歷可枚舉屬性,因此不該該基於這個循環中沒有不可枚舉的屬性而得出 hasOwnProperty 是嚴格限制於可枚舉項目的(如同 Object.getOwnPropertyNames())。

var buz = {
    fog: 'stack'
};

for (var name in buz) {
    if (buz.hasOwnProperty(name)) {
        alert("this is fog (" + name + ") for sure. Value: " + buz[name]);
    }
    else {
        alert(name); // toString or something else
    }
}

4.使用 hasOwnProperty 做爲屬性名
JavaScript 並無保護 hasOwnProperty 屬性名,所以某個對象是有可能存在使用這個屬性名的屬性,使用外部的 hasOwnProperty 得到正確的結果是須要的:

var foo = {
    hasOwnProperty: function() {
        return false;
    },
    bar: 'Here be dragons'
};

foo.hasOwnProperty('bar'); // 始終返回 false

// 若是擔憂這種狀況,能夠直接使用原型鏈上真正的 hasOwnProperty 方法
({}).hasOwnProperty.call(foo, 'bar'); // true

// 也可使用 Object 原型上的 hasOwnProperty 屬性
Object.prototype.hasOwnProperty.call(foo, 'bar'); // true

9.Object.defineProperties()

功能:方法直接在一個對象上定義一個或多個新的屬性或修改現有屬性,並返回該對象。

語法:

Object.defineProperties(obj, props)

// obj: 將要被添加屬性或修改屬性的對象
// props: 該對象的一個或多個鍵值對定義了將要爲對象添加或修改的屬性的具體配置
var obj = new Object();
Object.defineProperties(obj, {
    name: {
        value: '張三',
        configurable: false,
        writable: true,
        enumerable: true
    },
    age: {
        value: 18,
        configurable: true
    }
})

console.log(obj.name, obj.age) // 張三, 18

Object.defineProperty()功能大致相同,對比一下

var obj = new Object();

Object.defineProperty(obj, 'name', {
    configurable: false,
    writable: true,
    enumerable: true,
    value: '張三'
})

console.log(obj.name)  //張三

10.Object.getOwnPropertyDescriptor()

功能:該方法返回指定對象上一個自有屬性對應的屬性描述符。(自有屬性指的是直接賦予該對象的屬性,不須要從原型鏈上進行查找的屬性)
語法: Object.getOwnPropertyDescriptor(obj, prop)

// obj: 須要查找的目標對象
// prop: 目標對象內屬性名稱
var person = {
    name: '張三',
    age: 18
}

var desc = Object.getOwnPropertyDescriptor(person, 'name'); 
console.log(desc)  結果以下
// {
//     configurable: true,
//     enumerable: true,
//     writable: true,
//     value: "張三"
// }

11.Object. getOwnPropertyDescriptors()

功能:所指定對象的全部自身屬性的描述符,若是沒有任何自身屬性,則返回空對象。
語法: Object.getOwnPropertyDescriptors(obj)
obj: 須要查找的目標對象
var person = {
    name: '張三',
    age: 18
}
var desc = Object.getOwnPropertyDescriptors(person);
console.log(desc) // 結果以下圖

clipboard.png


推薦閱讀:
1.深刻JS對象的遍歷
2.從新認識javascript對象(一)——對象及其屬性
3.從新認識javascript對象(三)——原型及原型鏈
4.[js中的Object.defineProperty()和defineProperties()
](https://segmentfault.com/a/11...
參考文章:
1.Object.defineProperty()
2.Object.create()
3.isPrototypeOf()
4.Object.prototype.hasOwnProperty()
5.理解defineProperty以及getter、setter
6.vue中v-model等父子組件通訊
7.JavaScript 知識點串燒——對象
8.從新認識javascript對象(三)——原型及原型鏈
9.教科書式的object方法

相關文章
相關標籤/搜索