重新看红皮书,觉得很多知识多看几遍确实是能看的更明白些。今天重温了一下对象创建和继承,就稍微记下来,巩固一下。
js是面向对象的编程语言,ECMA-262吧对象定义为:“无序属性的集合,其属性可以包含基本值,对象或者函数”。每个对象都是基于一个引用类型创建的,这个引用类型可以是原生类型,也可以是自定义的。
一,讲讲创建对象的几个方法
1. var person = new Object();
2. var person = {};
3. 工厂模式
4. 构造函数模式
5. 原型模式
6. 组合使用构造函数模式和冤案型模式
7. 动态原型模式
8.等等......
这里着重记一下构造模式和原型模式,毕竟之后的模式和继承方法都是由于这两个的优缺点借鉴而来。
4.构造函数模式
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(‘niko‘,‘19‘,‘FE‘);
这种方式创建对象,可以将它的实例化标识为一中特定类型。及实例可以通过 instanceof 或者constructor 来检测对象的类型。缺点是无法完成方法的复用,即每个方法都需要在实例化上重新创建。
5.原型模式
我们自然是希望创建对象时可以共享某些属性和方法,搞这个原型模式挺拿手的~~~来露个脸。简单的说,我们创建的每个函数都有一个prototype属性,这个prototype属性是一个指针,指向一个对象,这个对象里面放着创建的这个对象实例的原型对象。原型对象,即是包含所有实例都共享的属性和方法。默认情况下,所有原型对象都自动获得一个constructor属性,这个属性包含一个指向prototype属性所在函数的指针。绕来绕去估计就晕了,来个图解释一下。
通过原型模式创建对象之后,是可以顺顺利利的完成属性和方法的共享,但是也是有弊端的如果包含引用类型的值,那么实例化的某一个对象对这个值进行操作,就会修改原型里的值,这样问题就比较麻烦了。所以组合模式就出现了,及用构造函数来创建属性,用原型模式来创建共享方法。
7.动态原型模式,就是把所有信息封装到函数里看着会简洁好多,也是组合了构造函数和原型模式的优点,在函数内部初始化原型(仅仅在第一次运行时初始化)。
function Person(name,age,job){
this.name = name;
this.age = age;
this.job = job;
if(typeof this.sayName!= "function"){
Person.prototype.sayName = function(){
console.log(this.name);
};
}
}
var person1 = new Person(‘niko‘,‘19‘,‘FE‘);
跟组合模式不同的是,初始化原型在函数内部,并且如果有多个共享函数时,只判断一个就好~~看着简洁那么一小丢~~对象创建就写到这,接下来写一下继承啦啦啦啦~
二,常见的继承方式
1.原型链
2.借用构造函数
3.组合继承
4.组合寄生式继承
5.原型式,寄生式..
挑几个重要的讲吧,重要的就是掌握原型链的原理,以及构造函数继承方式,组合是采取了这两个优缺点进行优化,组合寄生则是针对组合继承进行的优化。原型、寄生式是对一个相对的对象来创建另一个,没怎么碰到就不讲了。
1.原型链
原型链的主要思想就是让一个引用类型继承另一个引用类型的实例。原型对象将包含一个指向另一个原型的指针,另一个原型中也包含指向另一个构造函数的指针。层层递进之后,形成原型链。
function SuperType(){
this.property = true;
}
SuperType.prototype.getSuperValue = function(){
return this.property;
};
function Subtype(){
this.subproperty = false;
}
Subtype.prototype.getSubValue = function(){
return this.subproperty;
}
Subtype.prototype.getSubValue = function(){
return this.subproperty;
};
var instance = new Subtype();
啊,写到一半突然要闭馆了闭馆了闭馆了=.=泪奔一下 ,中间详细就不解释了,看懂这个图就没啥大问题了~原型链的问题就是,共享引用类型值的时候,修改一个实例就会修改原型。
2.借用构造函数
这个方法就是在子类构造函数中调用超类的构造函数。
function SuperType(name){
this.name = name;
}
function SubType(){
SuperType.call(this,‘niko‘); //在this的作用域中调用SuperType()
}
var instance = new SubType();
这种方式不像原型继承,相当于在子类的作用域中吧超类的属性完完全全复制了一份。因为不是引用的指针,所以,即使是引用类型的属性值,每个实例都会复制一份属性值,所以不会有什么问题哒~~~而且借用构造函数模式可以在子类中传参。
3.组合继承就是兼顾了原型模式和借用构造函数模式的优缺点。既可以共享方法,也可以让不同的实例分别有自己的属性。
function SuperType(name){
this.name = name;
this.colors = [‘red‘,‘blue‘,‘orange‘];
}
SuperType.prototype.sayName = function(){
console.log(this.name);
}
function SubType(name,age){
//继承属性
SuperType.call(this,name); //第二次调用SuperType()
this.age = age;
}
SubType.prototype.sayAge = function(){
console.log(this.age);
}
//继承方法
SubType.prototype = new SuprType(); //第一次调用SuperType();
var instance = new Subtype(‘niko‘,34);
如图所示,第一次调超类的时候,SubType.prototype得到两个属性:name,colors。调用Subtype构造函数时,第二次调用超类,在新对象上创建实例属性:name,colors。这两个实例属性屏蔽了原型中的属性。
这种方法可以达到既可以共享方法,也可以有自己的实例属性,但是调用两次超类的构造函数。
4.寄生组合式继承
为了解决组合式的缺点,寄生组合式这个超级大Boss上场了。
大体思路还是借用构造函数来继承属性,用原型链的混成方法机场方法。与组合 方式不同的是,没有在子类中调用超类,而是取得了一个超类的副本。
function inhertiPrototype(subType,superType){
var prototype = object(superType.prototype); //创建对象
prototype.constructor = subType; //增强对象
subType.prototype = prototype; //指定对象
}