關於JavaScript原型屬性若干特色的分析

1. delete關鍵字

對象屬性會屏蔽原型屬性,經過delete刪除對象的屬性,能夠繼續訪問原型屬性,達到解除屏蔽的目的,看以下代碼:javascript

function Person(name, age, job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.friends = ['小明', '小剛'];
}

Person.prototype = {
    constructor: Person,
    sayName: function(){
        console.log(this.name);
    }
};

var p1 = new Person('張三', 18, 'JavaScript');

p1.sayName = function(){
    console.log('沒有名字');
}
p1.sayName();//沒有名字

//刪除對象屬性,能夠繼續訪問到原型上的屬性
delete p1.sayName;
p1.sayName();//張三

如代碼所示,給p1添加了sayName方法,屏蔽掉了原型上的sayName,經過delete關鍵字刪除對象上的屬性,又能夠訪問到原型上的屬性了。java

2. hasOwnProperty()

當給定屬性存在於實例中時,返回true,不然返回false,看下面代碼:函數

function Person(name, age, job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.friends = ['小明', '小剛'];
}

Person.prototype = {
    constructor: Person,
    sayName: function(){
        console.log(this.name);
    }
};

var p1 = new Person('張三', 18, 'JavaScript');
var p2 = new Person('李四', 18, 'Java');

p1.sayName = function(){
    console.log('沒有名字');
}

console.log(p1.hasOwnProperty('sayName'));//true
console.log(p2.hasOwnProperty('sayName'));//false

如代碼所示,給p1添加了sayName方法,經過hasOwnProperty檢測的結果爲true,沒有給p2添加,檢測結果爲falsehasOwnProperty只關心實例對象有沒有這個屬性,有就返回true,沒有就返回false,無論原型有沒有。學習

3. in關鍵字

只要經過實例對象可以訪問到的屬性,in關鍵字就返回true,怎麼理解呢?看下面代碼:this

function Person(name, age, job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.friends = ['小明', '小剛'];
}

Person.prototype = {
    constructor: Person,
    sayName: function(){
        console.log(this.name);
    }
};

var p = new Person('張三', 18, 'JavaScript');

console.log(p.hasOwnProperty('name'));//true
console.log(p.hasOwnProperty('sayName'));//false

console.log('name' in p);//true
console.log('sayName' in p);//true

delete p.name;

console.log(p.hasOwnProperty('name'));//false
console.log('name' in p);//false

如代碼所示,hasOwnProperty只有屬性在實例中存在時纔會返回truenamesayName經過實例都是可訪問的,因此使用in檢測時結果爲truein關鍵字,只要經過實例能訪問到屬性就返回true,也就是說,無論屬性存在實例仍是原型中,in關鍵字都會返回true,而hasOwnProperty只有當屬性存在實例中才會返回trueprototype

這樣結合兩者咱們也能夠自定義一個判斷屬性只存在原型中的方法了,以下代碼:設計

function Person(name, age, job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.friends = ['小明', '小剛'];
}

Person.prototype = {
    constructor: Person,
    sayName: function(){
        console.log(this.name);
    },
    /*
    * param: property, 類型:String, 描述:屬性
    * return: 類型:Boolean,描述:返回true,屬性只存在原型中
    * */
    hasPrototypeProperty: function(property){
        return (property in this) && !this.hasOwnProperty(property);
    }
};

var p = new Person('張三', 18, 'JavaScript');

console.log(p.hasPrototypeProperty('name'));//false, name不存在原型中
console.log(p.hasPrototypeProperty('sayName'));//true, sayName只存在原型中

p.sayName = function(){
    console.log('沒有名字');
}

console.log(p.hasPrototypeProperty('sayName'));//false, sayName不是隻在原型中存在

如代碼所示,重寫原型時添加了一個方法,用於判斷屬性是否只在原型中存在。首先使用in關鍵字判斷屬性在實例或原型中存在,再使用hasOwnProperty()排除掉在實例中存在的狀況,這樣結果返回true時就表示該屬性只在原型中存在了。code

4. 枚舉屬性

4.1 for-in枚舉

能夠枚舉出全部可以經過對象訪問的、可枚舉的屬性。可以經過對象訪問的屬性好理解,那什麼樣的屬性算可枚舉的屬性呢?目前讀者只要記住全部開發人員定義的屬性都是可枚舉的就行了,以下代碼所示:對象

function Person(name, age, job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.friends = ['小明', '小剛'];
}

Person.prototype = {
    constructor: Person,
    sayName: function(){
        console.log(this.name);
    }
};

var p = new Person('張三', 18, 'JavaScript');

for(var pro in p){
    console.log(pro);//name age job friends constructor sayName
}

4.2 Object.keys()方法

ES5新增的方法,這個方法接收一個對象做爲參數,可枚舉該對象自己全部可枚舉的屬性,不包括原型,見以下代碼:ip

function Person(name, age, job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.friends = ['小明', '小剛'];
}

Person.prototype = {
    constructor: Person,
    sayName: function(){
        console.log(this.name);
    }
};

var p = new Person('張三', 18, 'JavaScript');

console.log(Object.keys(p));//["name", "age", "job", "friends"]
console.log(Object.keys(Person));//[]
console.log(Object.keys(Person.prototype));//["constructor", "sayName"]

如代碼所示,枚舉的只是對象自己的屬性,不是能經過對象訪問的屬性均可枚舉,這點要注意和for-in進行比較。

4.3 Object.getOwnPropertyNames()

這個方法能夠枚舉全部屬性,不管是否是可枚舉的,只有一個例外——__proto__,見以下代碼:

function Person(name, age, job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.friends = ['小明', '小剛'];
}

Person.prototype = {
    constructor: Person,
    sayName: function(){
        console.log(this.name);
    }
};

var p = new Person('張三', 18, 'JavaScript');

console.log(Object.getOwnPropertyNames(p));//["name", "age", "job", "friends"]
console.log(Object.getOwnPropertyNames(Person));//["length", "name", "arguments", "caller", "prototype"]
console.log(Object.getOwnPropertyNames(Person.prototype));//["constructor", "sayName"]

5. 原生對象的原型

全部原生引用類型(ArrayStringDate等)都在其構造函數的原型上定義了方法。學習了原型的知識,咱們也能夠在原型上擴展方法,以下代碼所示:

Date.prototype.addDay = function (count) {
    return new Date(this.getFullYear(), this.getMonth(), this.getDate() + count);
}

var _date = new Date();
console.log(_date.addDay(2));//Mon Oct 29 2018 00:00:00 GMT+0800 (中國標準時間),後天
console.log(_date.addDay(-1));//Fri Oct 26 2018 00:00:00 GMT+0800 (中國標準時間),昨天

如代碼所示,給Date添加了一個加幾天的方法,這樣作很方便,可是原書中有這樣一段話,「儘管能夠這樣作,但咱們不推薦在產品化的程序中修改原生對象的原型。若是因某個實現中缺乏某個方法,就在原生對象的原型中添加這個方法,那麼當在另外一個支持該方法的實現中運行代碼時,就可能會致使命名衝突。並且,這樣作也可能會意外地重寫原生方法」。

雖然做者這樣說,可是工做中依然會有人這麼寫,也確實方便,我就遇到過不少次,這個仍是在工做中具體狀況具體分析吧。

本文參考《JavaScript高級程序設計(第3版)》

相關文章
相關標籤/搜索