深入理解原型
无论什么时候,只要创建了一个新函数,就会根据一组特定的规则为该函数创建一个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