JavaScript 精粹 基礎(chǔ) 進(jìn)階(4)對(duì)象

對(duì)象中包含一系列屬性,這些屬性是無(wú)序的。每個(gè)屬性都有一個(gè)字符串key和對(duì)應(yīng)的value散怖。

JavaScript 對(duì)象概述

概述

對(duì)象中包含一系列屬性喷兼,這些屬性是無(wú)序的篮绰。每個(gè)屬性都有一個(gè)字符串key和對(duì)應(yīng)的value。

var obj = {x : 1, y : 2};    //定義obj對(duì)象季惯, 有兩個(gè)屬性x和y
obj.x; // 1   //訪問(wèn)對(duì)應(yīng)obj.x屬性取到對(duì)應(yīng)的值
obj.y; // 2   //訪問(wèn)對(duì)應(yīng)obj.y屬性取到對(duì)應(yīng)的值

這里有兩個(gè)重點(diǎn)吠各,一個(gè)是屬性是無(wú)序的,再一個(gè)每一個(gè)key是字符串勉抓。

探索對(duì)象的key

var obj = {};    //定義對(duì)象obj
obj[1] = 1;      //動(dòng)態(tài)賦值數(shù)字1屬性值為1
obj['1'] = 2;    //動(dòng)態(tài)賦值字符串1屬性值為2
console.log(obj); // Object {1: 2}  //實(shí)際上結(jié)果指向的是同一個(gè)屬性

//每個(gè)屬性都有一個(gè)字符串key和對(duì)應(yīng)的value贾漏。

obj[{}] = true;    //[{}] 空對(duì)象作為key
obj[{x : 1}] = true;     //對(duì)象帶有屬性的對(duì)象作為key  //js都會(huì)把它轉(zhuǎn)換成字符串然后再去處理,最終指向的是同一個(gè)屬性
console.log(obj)// Object {1: 2, [object Object]: true}

回顧-數(shù)據(jù)類型

Paste_Image.png

函數(shù)藕筋,數(shù)組纵散,日期,正則等都是對(duì)象

對(duì)象結(jié)構(gòu)

var obj = {};    //字面量空對(duì)象
obj.y = 2;       //賦值創(chuàng)建屬性x
obj.x = 1;       //賦值創(chuàng)建屬性y

對(duì)象有個(gè)特點(diǎn)隐圾,他的屬性可以動(dòng)態(tài)的添加或刪除的

函數(shù)對(duì)象

function foo(){};
console.log(foo.prototype);
Paste_Image.png

創(chuàng)建一個(gè)函數(shù)聲明
每一個(gè)函數(shù)都會(huì)有一個(gè)foo.prototype對(duì)象屬性

function foo(){};
foo.prototype.z=1;
console.log(foo.prototype);
Paste_Image.png

foo.prototype對(duì)象屬性添加屬性z賦值為1伍掀,foo.prototype對(duì)象屬性下有個(gè)constructor屬性方法,該屬性其實(shí)是指向自己本身暇藏。

function foo(){};
foo.prototype.z=1;
console.log(foo.prototype);

var obj =new foo();
console.log(obj);
Paste_Image.png

通過(guò)new去實(shí)例化foo()函數(shù)var obj =new foo();那么這個(gè)obj原型就會(huì)指向構(gòu)造器的prototype屬性也就是foo.prototype硕盹,可以通過(guò)上圖看出打印輸出是一樣的。

JavaScript 創(chuàng)建對(duì)象叨咖,原型鏈

對(duì)象創(chuàng)建-字面量

var obj1 = {x : 1, y : 2};

對(duì)象字面量 瘩例,用{}設(shè)置屬性

var obj2 = {
    x : 1,
    y : 2,
    o : {
        z : 3,
        n : 4
    }
};

對(duì)象字面量也可以做一些嵌套啊胶,比如某些屬性值可以又是對(duì)象

創(chuàng)建對(duì)象-new/原型鏈

還有一種就是使用new構(gòu)造器的方法創(chuàng)建對(duì)象,先來(lái)了解javascript中的原型鏈垛贤。

什么是原型鏈

function foo(){}    //定義函數(shù)對(duì)象  
foo.prototype.z = 3;      //函數(shù)對(duì)象默認(rèn)帶foo.prototype對(duì)象屬性  對(duì)象添加z屬性=3

var obj =new foo();    //用構(gòu)造器方式構(gòu)造新的對(duì)象
obj.y = 2;    //通過(guò)賦值添加2個(gè)屬性給obj
obj.x = 1;   //通過(guò)new去構(gòu)造這樣一個(gè)對(duì)象他的主要特點(diǎn)是焰坪,他的原型會(huì)指向構(gòu)造器的foo.prototype屬性

obj.x; // 1  //訪問(wèn)obj.x發(fā)現(xiàn)對(duì)象上有x返回1
obj.y; // 2  //訪問(wèn)obj.y發(fā)現(xiàn)對(duì)象上有x返回2
obj.z; // 3  //obj上沒(méi)有z并不會(huì)停止查找,會(huì)去查找他的原型foo.prototype.z返回3
typeof obj.toString; // ‘function'  這是一個(gè)函數(shù)聘惦,toString是Object.prototype上面的每個(gè)對(duì)象都有
'z' in obj; // true     obj.z是從foo.prototype繼承而來(lái)的某饰,所以說(shuō)obj里面有z
obj.hasOwnProperty('z'); // false   表示z并不是obj直接對(duì)象上的,而是對(duì)象原型鏈上的善绎。

但是如果是賦值的話結(jié)果就一樣了黔漂。

比如我們賦值obj.z=5

如果給obj.z嘗試去賦值,就不會(huì)像原型鏈上去查找了禀酱。先看obj.z有沒(méi)有炬守,有的話修改它的值,沒(méi)有的話剂跟,在對(duì)象上添加obj.z减途。

Paste_Image.png
obj.z = 5;
obj.hasOwnProperty('z'); // true
foo.prototype.z; // still 3
obj.z; // 5

obj.z = undefined;
obj.z; // undefined

那么怎樣能拿到原型鏈上的z呢

delete obj.z; // true  刪除對(duì)象上的z屬性
obj.z; // 3  //這樣就能獲取原型鏈上的z

對(duì)象創(chuàng)建-Object.create

從字面量理解是對(duì)象創(chuàng)建

Object.create({x:1});是系統(tǒng)內(nèi)置的函數(shù),這個(gè)函數(shù)會(huì)接收一個(gè)參數(shù)曹洽,一般是一個(gè)對(duì)象鳍置。他會(huì)返回一個(gè)新創(chuàng)建的對(duì)象,并且讓這個(gè)對(duì)象的原型指向參數(shù)送淆,參數(shù)一般是個(gè)對(duì)象税产。

var obj = Object.create({
    x: 1
});
console.log(obj.x) // 1
console.log(typeof obj.toString) // "function"
console.log(obj.hasOwnProperty('x')); // false
console.dir(obj)
Paste_Image.png

JavaScript 屬性操作

讀寫(xiě)對(duì)象屬性

var obj = {
    x: 1,
    y: 2
};
console.log(obj.x); // 1
console.log(obj["y"]); // 2

obj["x"] = 3;
obj.y = 4;

創(chuàng)建對(duì)象字面量obj,有xy兩個(gè)屬性偷崩,可以用obj.y(點(diǎn))操作符去訪問(wèn)他的屬性砖第,也可以用obj["y"][中括號(hào)這里需要是字符串]

var obj = {
    x1: 1,
    x2: 2
};
var i = 1,
    n = 2;

for (; i <= n; i++) {
    console.log(obj['x' + i]);
}
// 輸出: 1, 2

obj['x']使用方法,obj['x']同等于obj.x环凿。obj['x']可以在[]內(nèi)拼接字符串梧兼,obj.x+""不是那么方便

var obj = {
    x1: 1,
    x2: 2
};
var p;
for (p in obj) {
    console.log(obj[p]);
}

用for...in遍歷所有屬性
需要注意的是用for...in去遍歷的話,有可能把原型鏈上的屬性也遍歷出來(lái)智听,并且他的順序是不確定的羽杰。

屬性讀寫(xiě)-異常

var obj = {
    x: 1
};//創(chuàng)建對(duì)象obj
console.log(obj.y); //如果訪問(wèn)一個(gè)不存在的屬性會(huì)進(jìn)行原型鏈查找如果找到末端還是找不到就會(huì)返回 undefined
var yz = obj.y.z; //不能獲取undefined的屬性z   TypeError: Cannot read property 'z' of undefined
obj.y.z = 2; //不能給undefined的屬性z去賦值 TypeError: Cannot set property 'z' of undefined



var yz;
if (obj.y) {
    yz = obj.y.z;
}//判斷當(dāng)obj.y存在把他取出來(lái)


//巧用運(yùn)算符
var yz = obj && obj.y && obj.y.z;

屬性刪除

var person = {
    age: 28,
    title: 'fe'
};
delete person.age; // true  表示刪除成功
delete person['title']; // true  表示刪除成功
person.age; // undefined
delete person.age; // true

delete Object.prototype; // false,  不允許刪除

//通過(guò)getOwnPropertyDescriptor方法去獲取一個(gè)屬性中所有的標(biāo)簽,第一個(gè)參數(shù)是你要查看的對(duì)象到推,第二個(gè)是你要去檢測(cè)的屬性這樣就能拿到屬性的描述器
var descriptor = Object.getOwnPropertyDescriptor(Object, 'prototype');
console.log(descriptor);

屬性檢測(cè)

var cat = new Object;  //使用new 構(gòu)造對(duì)象
cat.legs = 4;    //賦值屬性legs值為4
cat.name = "Kitty";  //賦值屬性name值為Kitty

'legs' in cat; // true   表示cat中有l(wèi)egs屬性 in操作符是會(huì)向原型鏈上查找的
'abc' in cat; // false   表示cat中沒(méi)有abc屬性
"toString" in cat; // true, 繼承 property有toString屬性

cat.hasOwnProperty('legs'); // true   表示cat直接量屬性有l(wèi)egs
cat.hasOwnProperty('toString'); // false   表示cat直接量屬性沒(méi)有toString   toString是在原型有

cat.propertyIsEnumerable('legs'); // true  legs可枚舉  查看是否可枚舉propertyIsEnumerable   for...in會(huì)被循環(huán)
cat.propertyIsEnumerable('toString'); // false   toString不可枚舉  查看是否可枚舉propertyIsEnumerable   for...in不會(huì)被循環(huán)

自定義對(duì)象屬性考赛,讓他的枚舉標(biāo)簽是false

var cat = new Object;  //使用new 構(gòu)造對(duì)象
cat.legs = 4;    //賦值屬性legs值為4
cat.name = "Kitty";  //賦值屬性name值為Kitty

'legs' in cat; // true   表示cat中有l(wèi)egs屬性 in操作符是會(huì)向原型鏈上查找的
'abc' in cat; // false   表示cat中沒(méi)有abc屬性
"toString" in cat; // true, 繼承 property有toString屬性

cat.hasOwnProperty('legs'); // true   表示cat直接量屬性有l(wèi)egs
cat.hasOwnProperty('toString'); // false   表示cat直接量屬性沒(méi)有toString   toString是在原型有

cat.propertyIsEnumerable('legs'); // true  legs可枚舉  查看是否可枚舉propertyIsEnumerable   for...in會(huì)被循環(huán)
cat.propertyIsEnumerable('toString'); // false   toString不可枚舉  查看是否可枚舉propertyIsEnumerable   for...in不會(huì)被循環(huán)

//通過(guò)Object.defineProperty給cat目標(biāo)對(duì)象去添加一個(gè)屬性price
//enumerable:是否能在for...in循環(huán)中遍歷出來(lái)或在Object.keys中列舉出來(lái)。
//value:屬性的值給屬性賦值
Object.defineProperty(cat, 'price', {enumerable: false, value: 1000});
cat.propertyIsEnumerable('price'); // false  price不可枚舉  查看是否可枚舉propertyIsEnumerable   for...in不會(huì)被循環(huán)
cat.hasOwnProperty('price'); // true   表示cat直接量屬性有price
console.log(cat)
for(var k in cat){
    console.log(cat[k]);//循環(huán)出來(lái)看看能不能被枚舉
}

判斷對(duì)象屬性是否存在進(jìn)行操作

if (cat && cat.legs) {
    cat.legs *= 2;
}//8

判斷cat是否存在且cat.legs不是undefined的時(shí)候莉测,讓cat.legs值乘等于2颜骤,表示cat.legs乘以2再賦值給cat.legs

if (cat.legs !== undefined) {
    // only if cat.legs is not undefined
}

判斷cat.legs不等于undefined的時(shí)候去做動(dòng)作

if (cat.legs !== undefined) {
    // only if cat.legs is not undefined
}

判斷cat.legs嚴(yán)格不等于undefined的時(shí)候去做動(dòng)作

屬性枚舉

var o = {
    x: 1,
    y: 2,
    z: 3
};
'toString' in o; // true
o.propertyIsEnumerable('toString'); // false
var key;
for (key in o) {
    console.log(key); // x, y, z
}

這樣寫(xiě)出來(lái)的對(duì)象原型鏈屬性默認(rèn)是不可枚舉的,所以for....in的時(shí)候原型鏈不會(huì)出來(lái)捣卤。

var o = {
    x: 1,
    y: 2,
    z: 3
};
var obj = Object.create(o);  //創(chuàng)建obj對(duì)象以o對(duì)象作為原型
obj.a = 4;

console.log(obj)
var key;
for (key in obj) {
    console.log(key); // a, x, y, z
}

創(chuàng)建obj對(duì)象以o對(duì)象作為原型
所有對(duì)象上的屬性忍抽,和原型上的屬性都會(huì)遍歷中顯示出來(lái)

那有時(shí)候我只想處理對(duì)象上的屬性八孝,不想遍歷我對(duì)象原型鏈上的屬性。

我們需要在加一個(gè)obj.hasOwnProperty(key)的判斷鸠项,來(lái)過(guò)濾掉原型鏈上的屬性就可以了干跛。

var o = {
    x: 1,
    y: 2,
    z: 3
};
var obj = Object.create(o);  //創(chuàng)建obj對(duì)象以o對(duì)象作為原型
obj.a = 4;

var key;
for (key in obj) {
    if (obj.hasOwnProperty(key)){
        console.log(key); // a
    }
}

JavaScript get/set方法

JavaScript get/set方法

var man = {
    name: 'huang',
    weibo: '@.com',
    get age() {
        return new Date().getFullYear() - 1993;
    },
    set age(val) {
        console.log('年齡不能設(shè)置' + val);
    }
}
console.log(man.age); //23
man.age = 100; //年齡不能設(shè)置100
console.log(man.age); //23

定義了一個(gè)對(duì)象man有屬性name值是huang,這里定義了一對(duì)getset方法祟绊,來(lái)去訪問(wèn)屬性age

語(yǔ)法

getset關(guān)鍵字開(kāi)頭楼入,空格,然后是屬性的名字牧抽,然后是括號(hào)再方括號(hào)嘉熊,里面是一個(gè)函數(shù)體,

get方法會(huì)返回當(dāng)前日期的年份減去我的出生日扬舒,會(huì)拿到我的年齡阐肤。

set方法會(huì)拿到括號(hào)賦值的值,唯一的參數(shù)創(chuàng)進(jìn)來(lái)呼巴。

當(dāng)訪問(wèn)console.log(man.age); //23會(huì)返回get方法,

當(dāng)使用man.age = 100;也就是說(shuō)給set去賦值的時(shí)候御蒲,就會(huì)去調(diào)用set方法衣赶,就會(huì)輸出年齡不能設(shè)置100

再去輸出console.log(man.age); //23會(huì)發(fā)現(xiàn)仍然是23,因?yàn)?code>set沒(méi)做任何的事情厚满。

var man = {
    name: 'huang',
    $age: null,
    get age() {
        if (this.$age == undefined) {
            return new Date().getFullYear() - 1993;
        } else {
            return this.$age;
        }
    },
    set age(val) {
        val = +val;
        if (!isNaN(val) && val > 0 && val < 150) {
            this.$age = +val;
        } else {
            throw new Error('Incorrect=' + val);
        }
    }
}
console.log(man.age); //23
man.age = 100;
console.log(man.age); //100
man.age = 'abn';
console.log(man.age);//Uncaught Error: Incorrect=NaN(…)

get/set與原型鏈

function foo() {};

Object.defineProperty(foo.prototype, 'z', {
    get: function() {
        return 1;
    }
});

var obj = new foo();

console.log(obj.z); //1
obj.z = 10;
console.log(obj.z); //還是輸出1

Object.defineProperty(obj, 'z', {
    value: 100,
    configurable: true
});

console.log(obj.z);//100
delete obj.z;
console.log(obj.z);//1

解釋

function foo() {};

創(chuàng)建一個(gè)foo函數(shù)府瞄,就會(huì)有一個(gè)foo.prototype

Paste_Image.png
Object.defineProperty(foo.prototype, 'z', {
    get: function() {
        return 1;
    }
});

通過(guò)definePropertygit方法來(lái)創(chuàng)建z屬性git方法只是固定的返回1碘箍。

var obj = new foo();

使用new方式來(lái)創(chuàng)建一個(gè)新的對(duì)象obj遵馆,這樣這個(gè)obj對(duì)象的原型會(huì)指向foo.prototype

console.log(obj.z); //1

當(dāng)我們?nèi)ピL問(wèn)obj.z的時(shí)候obj對(duì)象上沒(méi)有z直接量屬性,所以他會(huì)向上去查找丰榴,foo.prototype原型货邓,發(fā)現(xiàn)有一個(gè)z屬性用的是get方法,這樣就能返回1四濒,

obj.z = 10;
console.log(obj.z); //還是輸出1

那么我賦值换况,嘗試給z賦值為10,如果z不是用get方式賦值的是通過(guò)foo.prototype.z原型賦值的話盗蟆,再使用直接量去賦值是可以成功的戈二,值會(huì)返回到obj這個(gè)對(duì)象上,但是在這里賦值并沒(méi)有成功喳资。仍然返回1觉吭。

這是因?yàn)楫?dāng)obj對(duì)象上沒(méi)有z直接量屬性的時(shí)候,并且他的原型鏈查找發(fā)現(xiàn)有getset方法的時(shí)候仆邓,那么當(dāng)我們嘗試去賦值的時(shí)候鲜滩,實(shí)際上會(huì)走原型上getset方法的伴鳖,而不會(huì)再去通過(guò)給當(dāng)前對(duì)象obj添加新屬性。

Object.defineProperty(obj, 'z', {
    value: 100,
    configurable: true
});

通過(guò)Object.definePropertyobj目標(biāo)對(duì)象去添加一個(gè)屬性z

  • value:屬性的值給屬性賦值
  • writable:如果為false绒北,屬性的值就不能被重寫(xiě)黎侈。
  • get: 一旦目標(biāo)屬性被訪問(wèn)就會(huì)調(diào)回此方法,并將此方法的運(yùn)算結(jié)果返回用戶闷游。
  • set:一旦目標(biāo)屬性被賦值峻汉,就會(huì)調(diào)回此方法。
  • configurable:如果為false脐往,則任何嘗試刪除目標(biāo)屬性或修改屬性以下特性(writable, configurable, enumerable)的行為將被無(wú)效化休吠。
  • enumerable:是否能在for...in循環(huán)中遍歷出來(lái)或在Object.keys中列舉出來(lái)。
console.log(obj.z);//100

這個(gè)時(shí)候obj.z是obj的直接量返回100

delete obj.z;

由于configurable: true所以刪除是成功的

console.log(obj.z);//1

這里因?yàn)橹苯恿縵被刪除們說(shuō)以他會(huì)繼續(xù)去向上查找zget方法业簿。

小案例

var o={z:2};
Object.defineProperty(o,'x',{value:1});//默認(rèn)writable=false只讀,configurable=false不可寫(xiě)
o.z=6;
o.x=6;
console.log(o);
Paste_Image.png

案例解釋

var o={};
Object.defineProperty(o,'x',{value:1});//默認(rèn)writable=false只讀,configurable=false不可寫(xiě)
var obj=Object.create(o);//創(chuàng)建obj對(duì)象以o對(duì)象作為原型
console.log(obj.x);//1   會(huì)向上查找返回原型鏈x屬性值1
obj.x=200; //嘗試去賦值200
console.log(obj.x);//賦值后打印任然是1

//那么如何去在obj對(duì)象添加x屬性呢瘤礁?

//還是要用Object.defineProperty


//給obj對(duì)象添加一個(gè)自己的屬性x,這樣就可以覆蓋掉原型鏈上的不可寫(xiě)的x梅尤,writable:true,configurable:true,value:100
Object.defineProperty(obj,'x',{writable:true,configurable:true,value:100});
console.log(obj.x);//100   obj.x是直接量屬性
obj.x=500;   //直接量屬性可以賦值
console.log(obj.x);//500   //修改成功

JavaScropt屬性標(biāo)簽

屬性標(biāo)簽

怎樣去看某一個(gè)對(duì)象上的屬性上都有哪些標(biāo)簽

console.log(Object.getOwnPropertyDescriptor({pro:true}, 'pro'));檢查一個(gè)字面量的對(duì)象柜思,添加屬性`pro:true`看字面量下的屬性`pro`的屬性標(biāo)簽
//configurable:true,enumerable:true,value:true,writable:true
console.log(Object.getOwnPropertyDescriptor({pro:true}, 'a'));//去查一個(gè)根本不存在的屬性返回undefined
//undefined

通過(guò)Object.getOwnPropertyDescriptor(參數(shù)1,"參數(shù)2")方法可以返回一個(gè)對(duì)象,這個(gè)對(duì)象上會(huì)顯示 當(dāng)前這個(gè)屬性下所有的標(biāo)簽巷燥,這個(gè)函數(shù)會(huì)接收兩個(gè)參數(shù)赡盘,第一個(gè)是你要去判斷的對(duì)象,第二個(gè)是一個(gè)字符串的屬性名缰揪,

  • value:屬性的值給屬性賦值
  • writable:如果為false陨享,屬性的值就不能被重寫(xiě)。
  • get: 一旦目標(biāo)屬性被訪問(wèn)就會(huì)調(diào)回此方法钝腺,并將此方法的運(yùn)算結(jié)果返回用戶抛姑。
  • set:一旦目標(biāo)屬性被賦值,就會(huì)調(diào)回此方法艳狐。
  • configurable:如果為false定硝,則任何嘗試刪除目標(biāo)屬性或修改屬性以下特性(writable, configurable, enumerable)的行為將被無(wú)效化。
  • enumerable:是否能在for...in循環(huán)中遍歷出來(lái)或在Object.keys中列舉出來(lái)
console.log(Object.getOwnPropertyDescriptor({pro:true}, 'pro'));檢查一個(gè)字面量的對(duì)象毫目,添加屬性`pro:true`看字面量下的屬性`pro`的屬性標(biāo)簽

得到的結(jié)果是

//configurable:true,enumerable:true,value:true,writable:true

那么怎么去設(shè)置或者說(shuō)設(shè)置對(duì)象的屬性標(biāo)簽?zāi)兀?/strong>

var person = {};
Object.defineProperty(person, 'name', {
    configurable: false,
    writable: false,
    enumerable: false,
    value: "繼小鵬"
});
console.log(person.name); //繼小鵬
person.price = 100; //修改不了
console.log(person.name); //還是繼小鵬
console.log(delete person.name); //false  不可刪除

解釋例子

創(chuàng)建一個(gè)空對(duì)象

var person = {};

通過(guò)Object.defineProperty(參數(shù)1,"參數(shù)2",{參數(shù)1})第一個(gè)參數(shù)是要添加屬性的對(duì)象喷斋,第二個(gè)參數(shù)是一個(gè)字符串屬性的名字,第三個(gè)參數(shù)是一個(gè)對(duì)象蒜茴,這個(gè)對(duì)象里面就是具體每一個(gè)標(biāo)簽的值星爪,

Object.defineProperty(person, 'name', {
    configurable: false,//不可刪除
    writable: false,//屬性的值就不能被重寫(xiě)。
    enumerable: true,//可枚舉
    value: "繼小鵬"http://屬性的值給屬性賦值
});

結(jié)果符合預(yù)期

console.log(person.name); //繼小鵬
person.price = 100; //修改不了
console.log(person.name); //還是繼小鵬
console.log(delete person.name); //false  不可刪除

創(chuàng)建新的屬性使用Object.keys

var person = {};
Object.defineProperty(person, 'name', {
    configurable: false,
    writable: false,
    enumerable: true,
    value: "繼小鵬"
});

Object.defineProperty(person, 'type', {
    configurable: true,
    writable: true,
    enumerable: false,
    value: "繼小鵬222"
});


console.log(person);

console.log(Object.keys(person));
Paste_Image.png

新創(chuàng)建的屬性enumerable: false,不可枚舉粉私,可以通過(guò)Object.keys(person)的方法來(lái)去獲取對(duì)象上所有的key
因?yàn)樾聞?chuàng)建的屬性enumerable: false,不可枚舉所有不可見(jiàn)顽腾。

使用Object.defineProperties()定義多個(gè)對(duì)象屬性標(biāo)簽

Object.defineProperties(person, {
    title: {
        value: 'fe',
        enumerable: true,
    },
    corp: {
        value: 'SDF',
        enumerable: true,
    },
    salary: {
        value: '50000',
        enumerable: true,
        writable: true
    }
});


console.log(person);
console.log(Object.getOwnPropertyDescriptor(person, 'corp'));
console.log(Object.getOwnPropertyDescriptor(person, 'salary'));
Paste_Image.png

Object.defineProperties()這個(gè)函數(shù)接收兩個(gè)參數(shù),第一個(gè)參數(shù)是你要定義屬性的對(duì)象,第二個(gè)參數(shù)是一個(gè)對(duì)象抄肖,對(duì)象里包含屬性值列表集久信。

例子

var person = {};
Object.defineProperties(person, {
    title: {
        value: 'fe',
        enumerable: true,
    },
    corp: {
        value: 'SDF',
        enumerable: true,
    },
    salary: {
        value: '50000',
        enumerable: true,
        writable: true
    },
    luck: {
        get: function() {
            return Math.random() > 0.5 ? 'good' : 'bad';
        }
    },
    promote: {
        set: function(level) {
            this.salary *= 1 + level * 0.1;
        }
    }
});



console.log(Object.getOwnPropertyDescriptor(person, 'salary'));
console.log(Object.getOwnPropertyDescriptor(person, 'corp'));
console.log(person.salary);
person.promote = 3;
console.log(person.salary);
console.log(person.luck);
Paste_Image.png

JavaScropt對(duì)象標(biāo)簽、對(duì)象序列化

對(duì)象標(biāo)簽

對(duì)象級(jí)別也是有標(biāo)簽的漓摩,主要有三種

  1. [[proto]]

  2. [[class]]

  3. [[extensible]]

原型標(biāo)簽__proto__

__proto__實(shí)際上就是原型裙士,比如說(shuō)當(dāng)我們用new構(gòu)造器的方式去實(shí)例化函數(shù)對(duì)象,那么這個(gè)實(shí)例化對(duì)象的原型鏈會(huì)指向構(gòu)造器的prototype管毙,一般的對(duì)象也會(huì)有原型腿椎,指向 Object.prototype然后在往上就是nall

class標(biāo)簽

var toString = Object.prototype.toString;

function getType(o) {
    return toString.call(o).slice(8, -1);
};

console.log(toString.call(null)); //[object Null]

console.log(getType(null)); //Null
console.log(getType(undefined)); //Undefined
console.log(getType(1)); //Number
console.log(getType(new Number(1))); //Number
console.log(typeof new Number(1)); //object
console.log(getType(true)); //Boolean
console.log(getType(new Boolean(true))); //Boolean

class標(biāo)簽是沒(méi)有一個(gè)直接的方式去查看他或者是修改他夭咬,可以間接的通過(guò)Object.prototype.toString;的方式來(lái)去獲取class啃炸,

var toString = Object.prototype.toString;

先把Object.prototype.toString;這樣一個(gè)函數(shù)拿到,賦值給toString這樣方便后面代碼簡(jiǎn)短一些卓舵,

function getType(o) {
    return toString.call(o).slice(8, -1);
};

定義一個(gè)方法南用,返回toString.call(o) 來(lái)調(diào)用這個(gè)函數(shù)方法,并且把參數(shù)o作為this傳進(jìn)去掏湾,然后用slice(8, -1);表示是截取從第八個(gè)字符開(kāi)始裹虫,一直到最后。

調(diào)用getType(1); //NumbergetType(1)方法會(huì)返回類型融击。

extensible標(biāo)簽

extensible標(biāo)簽表示你這個(gè)對(duì)象是否可擴(kuò)展筑公,言外之意就是說(shuō)對(duì)象上的屬性是否可以被繼續(xù)添加。

var obj={x:1,y:2};//創(chuàng)建對(duì)象
Object.isExtensible(obj);//true

創(chuàng)建對(duì)象obj砚嘴,通過(guò)Object.isExtensible(obj);來(lái)判斷對(duì)象是否可擴(kuò)展十酣,一般情況下默認(rèn)返回true涩拙。表示可以擴(kuò)展际长。

那么怎么樣不讓他擴(kuò)展,不可修改不可刪除凍結(jié)對(duì)象

var obj={x:1,y:2};//創(chuàng)建對(duì)象
Object.isExtensible(obj);//true   obj對(duì)象可擴(kuò)展

Object.preventExtensions(obj);    //設(shè)置obj對(duì)象不可擴(kuò)展
Object.isExtensible(obj);//false   obj對(duì)象不可擴(kuò)展
obj.d=2;   //嘗試給obj添加新的屬性會(huì)發(fā)現(xiàn)添加失敗
console.log(obj.d);//undefined

//如果已經(jīng)組織對(duì)象可擴(kuò)展兴泥,那么對(duì)象上的屬性標(biāo)簽是否會(huì)發(fā)生變化呢工育?

console.log(Object.getOwnPropertyDescriptor(obj, 'x'));
//value: 1, writable: true, enumerable: true, configurable: true
//雖然我們阻止了對(duì)象不可添加新屬性,但是已有熟悉仍然可以修改和刪除搓彻,也是可以枚舉的如绸。

//可以通過(guò)
Object.seal(obj);//會(huì)把對(duì)象上的屬性的configurable設(shè)置為false不可刪除
console.log(Object.getOwnPropertyDescriptor(obj, 'x'));
//value: 1, writable: true, enumerable: true, configurable: false
console.log(Object.isSealed(obj));//true   判斷對(duì)象是否被隱藏不可刪除


Object.freeze(obj);//讓對(duì)象凍結(jié)不可寫(xiě)
console.log(Object.getOwnPropertyDescriptor(obj, 'x'));
//value: 1, writable: false, enumerable: true, configurable: false
console.log(Object.isFrozen(obj));//true   判斷對(duì)象是否被不可寫(xiě)

序列化

var obj = {
    x: 1,
    y: true,
    z: [1, 2, 3],
    nullval: null
};
console.log(obj);
console.log(JSON.stringify(obj)); //{"x":1,"y":true,"z":[1,2,3],"nullval":null}
var obj1 = {
    val: undefined,
    a: NaN,
    b: Infinity,
    c: Date()
};
console.log(obj1);
console.log(JSON.stringify(obj1)); //{"a":null,"b":null,"c":"Fri Dec 16 2016 22:25:04 GMT+0800 (中國(guó)標(biāo)準(zhǔn)時(shí)間)"}

var obj2 = JSON.parse('{"x":1}');
console.log(obj2); //Object {x: 1}
console.log(obj2.x); //1

定義obj 字面量對(duì)象,有一些屬性旭贬,通過(guò)JSON.stringify(obj));方法返回一個(gè)字符串{"x":1,"y":true,"z":[1,2,3],"nullval":null}返回的字符串就是這個(gè)對(duì)象的序列化的結(jié)果怔接。

需要注意一點(diǎn)這個(gè)序列化是有一些坑的,如果你的屬性值是undefined的話稀轨,那么就不會(huì)出現(xiàn)在序列化的結(jié)果當(dāng)中扼脐。

如果后端返回一個(gè)JSON數(shù)據(jù)我們?cè)趺窗阉D(zhuǎn)換成js對(duì)象呢?

使用JSON.parse('{"x":1}');方法,需要注意的是合法的json屬性必須以雙引號(hào)引起來(lái)瓦侮。

序列化-自定義

var obj = {
    x: 1,
    y: 2,
    o: {
        o1: 1,
        o2: 2,
        toJSON: function() {
            return this.o1 + this.o2;
        }
    }
};

console.log(JSON.stringify(obj)); //{"x":1,"y":2,"o":3}

obj對(duì)象下有個(gè)屬性o他的值是一個(gè)對(duì)象艰赞,那么這個(gè)對(duì)象序列化的結(jié)果我可能想要自定義,那么我們只需要在這個(gè)當(dāng)前的層級(jí)下寫(xiě)一個(gè)toJSON他的值是一個(gè)函數(shù)肚吏,toJSON是固定這個(gè)key一定要這樣寫(xiě)方妖,然后這個(gè)函數(shù)會(huì)返回return this.o1 + this.o2;這個(gè)this會(huì)指向當(dāng)前層級(jí)的數(shù)也就是o,

這時(shí)候去JSON.stringify(obj));的時(shí)候罚攀,這里面的o通過(guò)toJSON這樣一個(gè)方法來(lái)去返回的党觅。

其他對(duì)象方法

var obj = {   //定義對(duì)象obj
    x: 1,
    y: 2
};
obj.toString(); //"[object Object]"   調(diào)用對(duì)象的toString方法會(huì)返回"[object Object]"這樣的字符串實(shí)際上沒(méi)有太大意義

//定義自己對(duì)象上個(gè)的toString方法
obj.toString = function() {
    return this.x + this.y;    //返回對(duì)象的x和y相加作為結(jié)果
}

"Result" + obj; //"Result3"   左邊是字符串這樣會(huì)理解為字符串拼接那么他就會(huì)調(diào)用obj.toString所以返回結(jié)果"Result3"
+ obj; //3  用一員加號(hào)操作符是可以把對(duì)象嘗試轉(zhuǎn)換為數(shù)字的,如果定義了obj.toString也會(huì)去調(diào)用obj.toString返回3

//valueOf是嘗試把對(duì)象轉(zhuǎn)換為基本類型的時(shí)候會(huì)自動(dòng)去調(diào)用的一個(gè)函數(shù)坞生,這里自定義返回值
obj.valueOf = function() {
    return this.x + this.y + 100;
} + obj; //103   再去用一員加號(hào)操作符把他轉(zhuǎn)換為數(shù)字這次返回的結(jié)果是103是從這個(gè)valueOf而來(lái)的
"Result" + obj; //"Result103"

需要主要的是這里面valueOf和toString都存在的時(shí)候那么不管是一元的加號(hào)還是2元的字符串拼接在做具體操作時(shí)仔役,都會(huì)嘗試把對(duì)象轉(zhuǎn)換為基本類型,那么他會(huì)先去找valueOf是己。如果valueOf返回的是基本類型那么就以valueOf的值作為結(jié)果反之如果valueOf不存在或者返回的是對(duì)象又兵,那么就會(huì)去找toString。如果valueOf和toString都沒(méi)有或者都返回的對(duì)象卒废,那么就會(huì)報(bào)錯(cuò)沛厨。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市摔认,隨后出現(xiàn)的幾起案子逆皮,更是在濱河造成了極大的恐慌,老刑警劉巖参袱,帶你破解...
    沈念sama閱讀 206,839評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件电谣,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡抹蚀,警方通過(guò)查閱死者的電腦和手機(jī)剿牺,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)环壤,“玉大人晒来,你說(shuō)我怎么就攤上這事≈O郑” “怎么了湃崩?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,116評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)接箫。 經(jīng)常有香客問(wèn)我攒读,道長(zhǎng),這世上最難降的妖魔是什么辛友? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,371評(píng)論 1 279
  • 正文 為了忘掉前任薄扁,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘泌辫。我一直安慰自己随夸,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布震放。 她就那樣靜靜地躺著宾毒,像睡著了一般。 火紅的嫁衣襯著肌膚如雪殿遂。 梳的紋絲不亂的頭發(fā)上诈铛,一...
    開(kāi)封第一講書(shū)人閱讀 49,111評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音墨礁,去河邊找鬼幢竹。 笑死,一個(gè)胖子當(dāng)著我的面吹牛恩静,可吹牛的內(nèi)容都是我干的焕毫。 我是一名探鬼主播,決...
    沈念sama閱讀 38,416評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼驶乾,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼邑飒!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起级乐,我...
    開(kāi)封第一講書(shū)人閱讀 37,053評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤疙咸,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后风科,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體撒轮,經(jīng)...
    沈念sama閱讀 43,558評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評(píng)論 2 325
  • 正文 我和宋清朗相戀三年贼穆,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了题山。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,117評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡扮惦,死狀恐怖臀蛛,靈堂內(nèi)的尸體忽然破棺而出亲桦,到底是詐尸還是另有隱情崖蜜,我是刑警寧澤,帶...
    沈念sama閱讀 33,756評(píng)論 4 324
  • 正文 年R本政府宣布客峭,位于F島的核電站豫领,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏舔琅。R本人自食惡果不足惜等恐,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧课蔬,春花似錦囱稽、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,315評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至扎即,卻和暖如春吞获,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背谚鄙。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,539評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工各拷, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人闷营。 一個(gè)月前我還...
    沈念sama閱讀 45,578評(píng)論 2 355
  • 正文 我出身青樓烤黍,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親傻盟。 傳聞我的和親對(duì)象是個(gè)殘疾皇子蚊荣,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容