原型和原型链
2019-01-20 本文已影响46人
simon_李玉兵
函数也是对象。每个函数都有一个属性
prototype
,指向函数的原型对象。所有原型对象都会自动获得一个constructor
属性,这个属性是一个 指向prototype
属性所在函数的指针。
构造函数模式
function Person (name, age, job) { // 构造函数
this.name = name
this.age = age
this.job = job
this.sayName = function () {
console.log(this.name)
}
}
var person1 = new Person('jose', 18, 'Doctor') // 实例
var person2 = new Person('jack', 20, 'programer') // 实例
创建Person实例,必须使用new操作符。以上方式调用构造函数将经历一下4步
1)创建一个新对象;
2)将构造函数的作用域给新对象(因此this就指向这个新对象)
3)执行构造函数中的代码(为这个新对象添加属性)
4)返回新对象
构造函数的问题
就是每个方法都要在每个实例上重新创建一遍。就像上述的person1和person2的sayName函数。这样子就会非常消耗内存。因为每次执行
function () {}
,都要在heap(堆内存)中开辟一个新的空间来存储。但是上述的两个实例,sayName方法都是一样的。
原型模式
利用构造函数的
prototype
(原型)。prototype
属性指向一个对象。这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。使用原型对象的好处是可以让所有对象实例共享它所包含的属性和方法。
function Person () {} // 构造函数
Person.prototype.name = 'jose'
Person.prototype.age = 12
Person.prototype.job = doctor
Person.sayName = function () {
console.log(this.name)
}
var person1 = new Person () // 实例 有一个属性__proto__指向构造函数的原型对象
person1.name // "jose"
var person2 = new Person() // 实例 有一个属性__proto__指向构造函数的原型对象
person2.name // "jose"
console.log(person1.sayName === person2.sayName) // true
关系当调用构造函数创建函数后,该实例的内部将包含一个指针(内部属性),指向构造函数的原型对象。这个属性叫
[[prototype]]
或__proto__
。
实例如何读取属性
执行
person.sayName
时,首先会搜索实例中是否含有该属性,如果在实例中找到了,就返回该返回该属性的值,如果没有找到则继续搜索原型对象。
实例中的属性会屏蔽原型对象中的同名属性 。
更简单的原型语法
function Person () {}
Person.prototype = {
constructor: Person,
name: "jose",
age: 12,
job: 'doctor',
sayName: function () {
console.log(this.name)
}
}
此时将prototype属性指向另一个对象了。constructor将显式赋值。
原型模式的问题
function Person () {}
Person.prototype = {
constructor: Person,
name: 'jose',
age: 12,
job: 'doctor',
friends: ['jack', 'tom', 'ming'],
sayName: function () {
console.log(this.name)
}
}
var person1 = new Person ()
var person2 = new Person ()
person1.friends.push('van')
console.log(person2.friends) // "jack, tom, ming, van"
console.log(person1.friends === person2.friends) //true
组合使用构造函数和原型模式
function Person (name, age, job) {
this.name = name
this.age = age
this.job = job
this.friends = ['jack', 'tom']
}
Person.prototype = {
constructor: Person,
sayName: function () {
console.log(this.name)
}
}
var person1 = new Person('jose', 12, 'doctor')
var person1 = new Person('van', 22, 'teacher')
person1.friends.push('count')
console.log(person1.friends) // "jack, tom, count"
console.log(person2.friends) // "jack, tom"
console.log(person1.friends === person2.friends) // false
console.log(person1.sayName === person2.sayName) // true
继承
让原型对象等于另一个类型的实例
function SuperType(){
this.property = true;
}
SuperType.prototype.getSuperValue = function(){
return this.property;
};
--------------------
function SubType(){
this.subproperty = false;
}
//继承了 SuperType
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function (){
return this.subproperty;
};
-----------------------
var instance = new SubType();
console.log(instance.getSuperValue()); //true
image.png
还有默认的原型
image.png原型链的问题
function SuperType(){
this.colors = ["red", "blue", "green"];
}
function SubType(){
}
//继承了 SuperType
SubType.prototype = new SuperType(); // 此时colors数组被放进了prototype中实现了共享
var instance1 = new SubType();
instance1.colors.push("black");
console.log(instance1.colors); //"red,blue,green,black"
var instance2 = new SubType();
console.log(instance2.colors); //"red,blue,green,black"
组合继承
function SuperType(name){
this.name = name;
this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function(){
alert(this.name);
}
function SubType(name, age){
//继承属性
SuperType.call(this, name);
this.age = age;
}
//继承方法
SubType.prototype = new SuperType(); // 此时SubType.prototype中也含有colors:["red", "blue", "green"]和name: undefined。但是将被实例中的同名属性覆盖
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function(){
alert(this.age);
};
var instance1 = new SubType("Nicholas", 29);
instance1.colors.push("black");
alert(instance1.colors); //"red,blue,green,black"
instance1.sayName(); //"Nicholas";
instance1.sayAge(); //29
var instance2 = new SubType("Greg", 27);
alert(instance2.colors); //"red,blue,green"
instance2.sayName(); //"Greg";
instance2.sayAge(); //27
201.png
当没有代码时,原始的构造函数将被初始化。
image.png