這樣理解原型,更加容易易懂
無論什麽時候,只要創建了一個新函數,就會根據一組特定的規則為該函數創建一個prototype屬性,這個屬性指向函數的原型對象。所有原型對象都會自動獲得一個consturctor屬性,這個屬性指向prototype屬性所在函數的指針。Person.prototype.constructor 指向Person。通過這個構造函數可以繼續為原型對象添加其他屬性和方法.
1.prototype:
只要我們定義一個函數,prototype
作為函數的屬性存在了,它的初始值是一個對象。
function Person () {
}
Person.prototype
2.給對象添加屬性和方法
給通過構造函數創建的對象添加屬性和方法:在函數內部通過this
function Person (name, age) {
this.name = name;
this.age = age;
}
var person1 = new Person();
通過構造函數的prototype
屬性給對象添加屬性和方法,這種方式添加的屬性和方法會被所有的對象實例共享。
function Person (name, age) { this.name = name; this.age = age; } Person.prototype.sayName = function() { return this.name; } Person.prototype.breathes = ‘空氣‘; var person1 = new Person(‘張三‘, 20); var person2 = new Person(‘李四‘, ‘21‘); person1.sayName();
註意:一定要前在原型中定義方法和屬性,然後再使用:
person2.eat();
Person.prototype.eat = function() {
console.log(‘吃飯啦‘);
}
註意:原型對象中屬性和對象自己的屬性是有區別的,對象自己屬性默認是可配置可枚舉的,而我們在原型中添加的屬性是不可配置的,但確是可枚舉。
function Person (name, age) { this.name = name; this.age = age; } Person.prototype.sayName = function() { return this.name; } Person.prototype.breathes = ‘空氣‘; var person1 = new Person(‘張三‘, 20); delete person1.sayName; console.log(person1.sayName()) // ‘張三‘ for(propName in person1){ console.log(propName) // name age sayName breathes }
3.覆蓋原型中屬性
如果對象出現了和原型對象中同名的屬性或方法,原型的屬性和方法會被覆蓋掉。這是因為,我們在訪問對象的屬性或方法時,優先在對象自己的屬性列表中查找,如果找到的話,就使用自己的屬性,如果找不到的,就去原型對象中查找。
在下面的示例中,原型對象中sayName
方法被對象自己的sayName
方法遮擋住了,所以最終調用的是對象自己的sayName
方法。
function Person (name, age) {
this.name = name;
this.age = age;
}
Person.prototype.sayName = function() {
return this.name;
}
var person1 = new Person(‘李四‘, 20);
person1.sayName = function() {
console.log(‘對象自己的sayName方法‘)
}
person1.sayName(); // ‘對象自己的sayName方法‘
4.hasOwnProperty()方法和in操作符的區別
判斷對象中是否存在某個屬性,除了使用in
操作符,還可以使用hasOwnProperty()
方法。hasOwnProperty()
方法只在對象自己的屬性列表中搜索;而in
操作符,先在對象自己的屬性列表中查找,如果找不到,接著去原型對象的屬性列表中查找。
function Person (myname, myage) {
this.name = myname;
this.age = myage;
}
Person.prototype.sayName = function() {
console.log(this.name)
}
var person1 = new Person(‘小明‘, 18, ‘女‘);
// 使用hasOwnProperty()方法
console.log(person1.hasOwnProperty(‘name‘)) // ture
console.log(person1.hasOwnProperty(‘sayName‘)) // false
// 使用in操作符
console.log(‘sayName‘ in person1) // true
5.isPrototypeOf()方法
該方法是用來判斷一個對象是否是另一個對象的原型。例如:
var monkey = {
feeds: ‘香蕉‘,
breathes: ‘空氣‘
}
function Human (name) {
this.name = name;
}
Human.prototype = monkey;
接下來我們來判斷monkey對象是否是Human原型:
var person1 = new Human(‘李四‘);
monkey.isPrototypeOf(person1)
驗證person1的原型是否是monkey
console.log(Object.getPrototypeOf(person1))
console.log(Object.getPrototypeOf(person1) === monkey)
6.proto
我們先前講過,當我們訪問一個當前對象中沒有的屬性時,會去prototype
對象中查找。
var developer = new Human(‘李四‘);
developer.feeds = ‘大米飯‘;
developer.hacks = ‘JavaScript‘;
developer.hacks // ‘JavaScript‘
當我們訪問developer
對象中不存在的breathes
屬性時,就會去原型對象中查找,仿佛有一個神秘的鏈接指向原型對象。
developer.breathes; // ‘air‘
在大多數瀏覽器中都是以__proto__
屬性作為這個神秘的鏈接
console.log(developer.__proto__ === monkey); // true
在學習的過程中,我們可以使用這個鏈接,但是在實際的項目開發中不要使用它,因為並不是所有的瀏覽器都有__proto__
屬性。
我們可以使用Object.getPrototypeOf()代替它。
7.擴展(增強)內置的構造函數創建的對象
內置的構造函數有Array
,String
,Object
,Function
等,我們可以通過改變原型對象的方式增強由這些構造函數創建的對象。
例如,給數組添加一個inArray()
方法,用於判斷數組中是否包含某個元素:
Array.prototype.inArray = function (ele) { for (var i = 0; i < this.length; i++) { if(this[i] === ele) { return true; } } return false; }; var colors = [‘red‘, ‘green‘, ‘blue‘]; console.log(colors.inArray(‘red‘)); // true console.log(colors.inArray(‘purple‘)); // false
這樣理解原型,更加容易易懂