原型、原型链、继承
对象:
创建对象的方式:
-
工厂模式(无法解决对象识别问题)
function gongchang(name,age,sex){ var o = new Object(); o.name = name; o.age = age; o.sex = sex; o.sayname = function(){ alert(this.name); }; return o; } var person1 = gongchang("nihao",18,"man");
-
构造函数模式:
function gouzao(name,age,sex){ var o = new Object(); o.name = name; o.age = age; o.sex = sex; o.sayname = function(){ alert(this.name); }; //return o; 构造函数没有return语句 } var person1 = new gouzao("nihao",18,"man");
构造函数模式和工厂模式的区别:
-
没有显式的创造对象
-
没有直接将属性和方法赋值给this
-
没有return语句
-
原型模式:创建的每个函数都有一个prototype的属性,这个属性是一个指针,指向一个对象。这个对像它包含了所有实例共享的属性和方法
function yuanxing(){ } yuanxing.prototype.name = "nihao"; yuanxing.prototype.sayname = function(){ alert(this.name); } var person1 = new yuanxing(); person1.sayname(); //"nihao" person2.sayname(); //"nihao"
Person构造函数、Person的原型属性和Person实例的关系,如图:
当我们创建一个构造函数,会根据规则为该函数创建一个名为prototype的指针,该指针指向Person的原型对象(Person.prototype),而原型对象的constructor(即Person.prototype.constructor)又指回Person。person1和person2分别为Person的实例对象,它们的内部属性[[Prototype]],都指向Person的原型对象,可知与Person没有直接的关系。
另外:可以使用hasOwnProperty()方法检测一个属性是存在与实例中还是原型中
继承
js中的继承主要是依靠原型链来实现。基本思想:让一个引用类型继承另一个引用类型的属性和方法。
原型链
回顾构造函数、原型和实例的关系:每一个构造函数都有一个指向原型对象的指针prototype,该原型对象有一个constructor属性,该属性会指回构造函数,而实例包含一个指向原型对象的内部指针。(>…<)\
一种基本继承模式:
function Father(){
this.property = true;
}
Father.prototype.FgetValue = function(){
return this.property;
}
function Son(){
this.Sproperty = false;
}
//继承
Son.prototype = new Father();
Son.prototype.SgetValue = function(){
return this.prototype;
}
var test = new Son();
console.log(test.FgetValue(); //undefined
console.log(test.SgetValue(); //true
以上代码创建了两个构造函数,分别是Father、Son;它们分别有一个属性和一个方法;其中Son.prototype = new Father();该写了Son的原型对象,即变成了Father的实例。实现的本质就是改写了原型对象
结果:test指向了Son的原型,Son的原型又指向了Father的原型。(变成链了好像 ?_?)
借用构造函数继承
感觉有点类似java的super()
实现:在子类调用父类构造函数,需配合call或apply使用,如Father.call(this);
组合继承
思想:子类的构造函数内通过Father.call(this)继承父类的属性,然后通过改变子类的原型为父类的实例,来继承父类的函数。
function Father(){
this.val = Value;
}
Father.prototype.getValue = function(){
console.log(this.val);
};
function Son(value){
Father.call(this,value);
}
Son.prototype = new Father();
var son1 = new Son(2);
child1.getValue(); //2
优点:可以传参,不会与父类的引用属性共享,可以复用父类的函数
缺点:在继承的时候调用的父类的构造函数,导致原型上多了一个不需要的父类属性,存在内存浪费。会调用两次超类构造函数
原型式继承
es5新增了Object.create()方法规范了原型式继承,Object.create()接受两个参数,一是用做新对象原型的对象,二是一个为新对象定义额外属性的对象。在传入一个参数下,Object和Object.create一样。
寄生组合式继承
解决了组合继承中原型上多的一个父类属性
function Father(value) {
this.val = value
}
Father.prototype.getValue = function() {
console.log(this.val)
}
function Son(value) {
Father.call(this, value)
}
Son.prototype = Object.create(Father.prototype, {
constructor: {
value: Child,
enumerable: false,
writable: true,
configurable: true
}
})
const Son = new Son(2)
Son.getValue() // 1
//finally