原由.................
用Object或对象字面量建立对象会产生大量的重复代码,并且只能经过变量名来区分不一样的对象,没有记录对象的类型
例如:函数
//Object建立对象 var student = new Object(); student.name = 's'; student.age = "20"; var student1 = new Object(); student1.name = "s1"; student.age = "20"; //字面量建立对象 var student = { name: 's', age: '23' } var student1 = { name: 's', age: '23' }
工厂模式解决了类似代码重复书写的问题this
//好处:js中没法建立类,为了模仿类的建立方式,抽象具体对象的建立过程; //缺点:工厂模式建立的对象是经过普通函数调用实现的,没有解决标识对象类型的问题,没法区分对象的类型, function person(name) { var o = new Object(); o.name = name; o.sayName = function() { console.log(this.name) } return o; } var p1 = person('a'); var p2 = person('b');
function Person(name) { this.name = name; this.sayName = function() { console.log(this.name); } //function() { console.log(this.name);}至关于new Function(){console.log(this.name);}} var a = new Person('ww'); a.sayName(); console.log(a)
new 一个实例的过程:
(1)先建立一个对象
(2)将构造函数的做用域赋给新对象
(3),执行构造函数中的代码
(4)返回新对象spa
构造函数模式解决了标识构造函数类型的问题,可是构造函数内部每定义一个函数就会实例化一个对象,能够经过将公用的方法提到全局环境下,经过普通函数调用的方式实现调用函数,避免了重复实例化对象的问题prototype
function Person(name) { this.name = name; this.sayName = sayName; } function sayName() { console.log(this.name) } var a = new Person('p1'); var b = new Person('p2'); a.sayName(); b.sayName();
若是Person内部封装较多的函数,会致使定义大量的全局函数,这些函数散乱分布在全局环境中,失去了封装性.为了解决这个问题,能够用原型模式建立对象设计
原型模式建立对象,把属性和函数添加到对象的prototype上,实例化一个对象p1,p1能够经过原型链访问到原型链上的对象code
function Person() {} Person.prototype.name = "ww"; Person.prototype.sayName = function() { console.log(this.name); } var p1 = new Person(); p1.sayName();
(1)原型模式的另外一种方式:
这种方式会致使,Person.prototype上本来指向Person的constructor丢失,能够手动添加constructor属性,以下对象
(2)若是先建立实例,再定义Person.prototyp的值会报错,p1仍是经过[[prototype]]隐式属性指向Person没修改过的原型,致使找不到sayName方法继承
解释如js高级程序设计一书中的例子:ip
(3)原型链模式存在如下问题:(1),prototype上的属性和方法共享,一个对象对prototype属性的修改会影响另外一个对象的属性;(2)不能传递参数原型链
咱们能够把一些共享的属性和方法添加到prototype,再利用构造函数在实例对象上添加不一样属性
经过将一个构造函数的原型从新赋值(另外一个构造函数的实例)实现继承
例子:
function SuperType() { this.property = ['p1']; } SuperType.prototype.getValue = function() { console.log(this.property); } function SubType() { this.subproperty = ['1']; } SubType.prototype.getSubValue = function() { console.log("getSubVlue", this.subproperty); } SubType.prototype = new SuperType(); var a = new SubType(); console.log("a", a);
结果:
对于引用类型属性,原型链继承会将该属性做为公共属性,谁均可以对它的值进行修改;对于像name这样的非引用类型,每建立一个实例就会定义一个新额属性,不会和其余实例中的属性共享,以下所示
为了解决引用类型值共享的问题和原型链继承不能传递参数的缺陷,能够在子类型构造函数的内部调用超类型构造函数。以下:
function SuperType() { this.property = ['p1']; } function SubType() { this.subproperty = ['1']; SuperType.call(this); } SubType.prototype = new SuperType(); var a = new SubType(); var b = new SubType(); a.property.push('2'); console.log(a.property, b.property);
利用单纯的借用构造函数解决了引用类型值共享的问题,可是若是大量的函数写着超类中,函数没法复用,全部须要结合原型构造函数.
组合构造函数到的思路是将利用构造函数实例实现对属性的继承,利用原型链来实现对原型对象的属性和函数的继承.
因为给SubType.prototype直接赋值为SuperType的实例,致使constructor丢失,利用Object.defineProperty找回
思路:基于已有的对象建立新对象,继承一个现成的对象
原型式继承存在的问题就和原型模式同样,对于引用型属性有共享的特性
思路:建立一个仅用于封装继承过程的函数
该继承方式存在的问题是a对象内部的函数不能复用
组合构造函数也有缺陷,须要调用两次超类构造函数,下降效率
function SuperType(name) { this.name = name; this.books = ['b1'] } SuperType.prototype.getName = function() { console.log(this.name); } function SubType(name, age) { this.age = age; SuperType.call(this, name); //第二次调用构造函数 } SubType.prototype = new SuperType(); //第一次调用构造函数 SubType.prototype.constructor = SubType; SubType.prototype.getSubValue = function() { console.log("getSubVlue", this.age); }
利用寄生式继承来继承超类的原型,利用构造函数继承实例属性
有不对或者表达不许确的地方欢迎指出!