對象理解原型鏈

概述

對象中包含一系列的屬性,這些屬性無序。每個屬性都有一個key和對應的value。

var obj = {x:1,y:2};
obj.x;//1
obj.y;//2

對象的數據類型有:Function、Array、Date ···

對象結構

這裏寫圖片描述

var obj = {};
obj.y = 2;
obj.x = 1;

function foo(){}
foo.prototype.z = 3;
var obj =new foo();

一、對象的創建

第一種方式:字面量

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

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

第二種方式:new/原型鏈

這裏寫圖片描述

function foo(){};   //這樣就默認帶有一個foo.prototype對象屬性
foo.prototype.z = 3;

var obj =new foo();
obj.y = 2;
obj.x = 1;

obj.x; // 1
obj.y; // 2
obj.z; // 3
typeof obj.toString; // 'function'

'z' in obj; // true
obj.hasOwnProperty('z'); // false

obj.z = 5;

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

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

delete obj.z; // true
obj.z; // 3

delete obj.z; // true
obj.z; // still 3!!!

第三種方式:Object.create

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

這裏寫圖片描述

var obj = Object.create(null);
obj.toString // undefined

二、屬性的操作

屬性讀寫

var obj = {x : 1, y : 2};
obj.x; // 1
obj["y"]; // 2
var obj = {x1 : 1, x2 : 2};
var i = 1, n = 2;

for (; i <= n; i++) {
    console.log(obj['x' + i]);
}
// 輸出: 1, 2
var p;
for (p in obj) {
    console.log(obj[p]);
}
//for-in有可能將原型鏈上面的屬性遍歷下來

屬性異常

var obj = {x : 1};
obj.y; // undefined
var yz = obj.y.z; // TypeError: Cannot read property 'z' of undefined
obj.y.z = 2; // TypeError: Cannot set property 'z' of undefined

var yz;
if (obj && obj.y && obj.y.z) {
    yz = obj.y.z;
}
//或者如下巧用操作符
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,

var descriptor = Object.getOwnPropertyDescriptor(Object, 'prototype');
descriptor.configurable; // false   是否可配置,false表示不可配置
var globalVal = 1;
delete globalVal; // false

function fd() {}
delete fd; // false

//隱式創建的變量可以刪除
ohNo = 1;
window.ohNo; // 1
delete ohNo; // true

屬性檢測

var cat = new Object;
cat.legs = 4;
cat.name = "Kitty";

'legs' in cat; // true
'abc' in cat; // false
"toString" in cat; // true, inherited property!!!

cat.hasOwnProperty('legs'); // true
cat.hasOwnProperty('toString'); // false

//查看屬性是不是可枚舉的呢?
cat.propertyIsEnumerable('legs'); // true
cat.propertyIsEnumerable('toString'); // false
//cat對象的price屬性自己定義是否可枚舉,以下方式不寫默認爲false
Object.defineProperty(cat, 'price', {enumerable : false, value : 1000});
cat.propertyIsEnumerable('price'); // false
cat.hasOwnProperty('price'); // true

if (cat.legs != undefined) {
    //不等於表示 !== undefined, or, !== null
}

屬性枚舉

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
    console.log(o.key);//1,2,3
    console.log(0[key]);//1,2,3
}
var obj = Object.create(o);
obj.a = 4;
var key;
for (key in obj) {
    console.log(key); // a, x, y, z
}

var obj = Object.create(o);
obj.a = 4;
var key;
for (key in obj) {
    //過濾掉原型鏈上的屬性
    if (obj.hasOwnProperty(key)) {
        console.log(key); // a
    }
}

getter/setter方法

var man = {
    name : 'Bosn',
    weibo : '@Bosn',
    get age() {
        return new Date().getFullYear() - 1988;
    },
    set age(val) {
        console.log('Age can\'t be set to ' + val);
    }
}
console.log(man.age); // 27
man.age = 100; // Age can't be set to 100
console.log(man.age); // still 27

接下來將上面的代碼再複雜點:

var man = {
    weibo : '@Bosn',
    $age : null,
    get age() {
        if (this.$age == undefined) {
            return new Date().getFullYear() - 1988;
        } else {
            return this.$age;
        }
    },
    set age(val) {
        val = +val;//將傳入的字符串轉化爲Number類型(val-0也可以實現)
        if (!isNaN(val) && val > 0 && val < 150) {
            this.$age = +val;
        } else {
            throw new Error('Incorrect val = ' + val);
        }
    }
}

get/set遇到原型鏈

function foo() {}

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

var obj = new foo();

obj.z; // 1
obj.z = 100;//先前可以在obj中創建屬性爲z值爲100
obj.z; // still 1

Object.defineProperty(obj, 'z', 
{value : 100, configurable: true});
obj.z; // 100;
delete obj.z;
obj.z; // back to 1
var o = {};
Object.defineProperty(o, 'x', {value : 1}); // writable=false, configurable=false
var obj = Object.create(o);//obj類似於理解爲一個o的指向
obj.x; // 1
obj.x = 200;//writable=false爲不可寫所以賦值無效
obj.x; // still 1, can't change it

//用Object.definProperty();方式來定義屬性,並賦值
Object.defineProperty(obj, 'x', {writable:true, configurable:true, value : 100});
obj.x; // 100
obj.x = 500;
obj.x; // 500

三、屬性的權限

Object.getOwnPropertyDescriptor({pro : true}, 'pro');
//{pro : true}是對象,'pro'爲屬性
// Object {value: true, writable: true, enumerable: true, configurable: true}
Object.getOwnPropertyDescriptor({pro : true}, 'a'); // undefined

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

person.name; // Bosn Ma
person.name = 1;
person.name; // still Bosn Ma
delete person.name; // false
Object.defineProperties(person, {
    title : {value : 'fe', enumerable : true},
    corp : {value : 'BABA', 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;
        }
    }
});

Object.getOwnPropertyDescriptor(person, 'salary');
// Object {value: 50000, writable: true, enumerable: true, configurable: false}
Object.getOwnPropertyDescriptor(person, 'corp');
// Object {value: "BABA", writable: false, enumerable: true, configurable: false}
person.salary; // 50000
person.promote = 2;
person.salary; // 60000

五、對象標籤

proto

class標籤

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

toString.call(null); // "[object Null]"
getType(null); // "Null"
getType(undefined); // "Undefined"
getType(1); // "Number"
getType(new Number(1)); // "Number"
typeof new Number(1); // "object"
getType(true); // "Boolean"
getType(new Boolean(true)); // "Boolean"

extensible標籤

var obj = {x : 1, y : 2};
Object.isExtensible(obj); // true
Object.preventExtensions(obj);
Object.isExtensible(obj); // false
obj.z = 1;
obj.z; // undefined, add new property failed
Object.getOwnPropertyDescriptor(obj, 'x');
// Object {value: 1, writable: true, enumerable: true, configurable: true}

Object.seal(obj);//隱藏
Object.getOwnPropertyDescriptor(obj, 'x');
// Object {value: 1, writable: true, enumerable: true, configurable: false}
Object.isSealed(obj); // true

Object.freeze(obj);//凍結
Object.getOwnPropertyDescriptor(obj, 'x');
// Object {value: 1, writable: false, enumerable: true, configurable: false}
Object.isFrozen(obj); // true

// [caution] not affects prototype chain!!!

序列化

var obj = {x : 1, y : true, z : [1, 2, 3], nullVal : null};
JSON.stringify(obj); // "{"x":1,"y":true,"z":[1,2,3],"nullVal":null}"

obj = {val : undefined, a : NaN, b : Infinity, c : new Date()};
JSON.stringify(obj); // "{"a":null,"b":null,"c":"2015-01-20T14:15:43.910Z"}"

obj = JSON.parse('{"x" : 1}');
obj.x; // 1

自定義序列化

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

其他方法

var obj = {x : 1, y : 2};
obj.toString(); // "[object Object]"
obj.toString = function() {return this.x + this.y};
"Result " + obj; // "Result 3", by toString

+obj; // 3, from toString

obj.valueOf = function() {return this.x + this.y + 100;};
+obj; // 103, from valueOf

"Result " + obj; // still "Result 3"
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章