对象创建
工厂模式
函数封装创建对象的细节
function Person(nam, age) {
var o = new Object();
o.name = name;
o.age = age;
o.getName = function () {
alert(this.name)
};
return o;
}
var p1 = o('cfz', 20);
缺点:对象识别无法解决(不知道是怎样的对象类型,都为Object)
构造函数模式
初版:
function Person(name, age) {
this.name = name;
this.age = age;
this.getName = function () {
alert(this.name)
}
} var p2 = new Person('cfz', 20);
【new运行机制】!!!
相比于工厂模式:
- 无显示创建对象
- 直接将方法和属性赋给this
- 无return语句
- 可以将他的实例标示为一种特定类型(优点)
创建的所有对象都是Object实例,同时也是Person的实例
缺点:方法不复用,每个方法在每个实例上重新创建。
改进版:
函数定义移到构造函数外,复用方法。
function Person(name, age) {
this.name = name;
this.age = age;
this.getName = getName;
}
function getName() {
alert(this.name)
}
var p2 = new Person('cfz', 20);
缺点:在全局上定义对象方法,若对象方法很多,导致全局上方法很多,没有封装性。
原型模式
function Person() { }
Person.prototype = {
constructor: Person,
name: 'cfz',
age: 20,
sayName: function () {
alert(this.name);
}
};
var p2 = new Person();
缺点:所有实例共享属性,如果有引用类型的属性,则某一个实例修改,这个属性就会被修改。
组合使用构造函数和原型模式(改进上一种)
结合两者特点,取长补短。
数据用构造函数模式,每个实例有自己的数据副本。
方法用原型模式,实例共享。
function Person(name, age) {
this.name = name;
thia.age = age;
}
Person.prototype = {
constructor: Person,
sayName: function () {
alert(this.name);
}
};
var p2 = new Person('cfz', 20);
动态原型模式(改进上一种)
function Person(name, age) {
this.name = name;
thia.age = age;
if (typeof this.sayName != 'function') {
Person.prototype.sayName = function () {
alert(this.name);
}
};
}
var p2 = new Person('cfz', 20);
信息都封装到函数里,其中方法在使用时如果没有就创建。
对象继承
原型链继承
- 改写函数的prototype属性指向要继承的原型。
- 所有函数默认原型都是Object的实例,所以默认原型都继承了toString,valueOf方法。
- 问题:
- 原型对象中所有引用类型的值都会被子类共享。
- 无法在构造子类的时候向父类的构造函数动态传值。
借用构造函数
-
在子类型的构造函数内调用超类型构造函数。
-
如果该函数没有被任何对象显式地调用,那么在浏览器中,它就被认为是被全局对象window调用的。
Parent("cfz", 20); window.age === 20; //true
function Father(name) {
this.name = name;
this.getName = function () {
return this.name;
}
}
function Son() {
Father.call(this);
}
var s = new Son();
- 问题:同样方法无法复用
组合继承!!!
- 结合原型链继承和构造函数继承,数据用构造函数,方法用原型。
function Father(name) {
this.name = name;
}
Father.prototype.getName = function () {
console.log(this.name);
}
function Son(name) {
Father.call(this, name);//第二次调用Father构造函数
}
Son.prototype = new Father();//第一次调用Father构造函数
Son.prototype.constructor = Son;
var s = new Son('cfz');
- 问题:
Son.prototype = new Father();
这里Son.prototype为一个Father的实例,所以他有Father的所有属性,但是当我们访问时,从原型链查找,访问的都是子类的属性,即Father属性被屏蔽,所以这里new Father()所产生的属性是没必要的,还浪费内存和时间。
原型式继承
-
解决new Father()创建额外的属性。
-
内部创建一个新的空函数F,函数的prototype指向Father.prototype,所以可以认为F就是一个没有了属性的Father,那么当new F()产生子类原型时,就不会额外创建无用的属性。
-
ES5中,
Object.create()
,方法创建一个新对象,使用现有的对象来提供新创建的对象的__proto__,然后就可以像下面第一个代码这样,生成一个继承Father的实例child,然后给实例添加属性。var child = Object.create( Father.prototype ); child.name = "cfz"; child.age = 20;
function createObject( prototype ){
function F(){};
F.prototype = prototype;
return new F();
}
var child = createObject( Father.prototype );
寄生式继承
- 封装原型式继承
function createChild( Father ){
var child = Object.create( Father.prototype );
child.name = "cfz";
child.age = 20;
}
var child = createChild( Parent );
寄生组合式继承!!!
- 对于组合式继承改进。
- 根据上文知道,组合式继承的问题是产生了不必要的属性。所以可以采用原型式继承,解决这个问题,再将两者结合成一个理想的方案。
function Father(name, age){
this.name = name;
this.age = age;
}
Father.prototype.getName = function(){};
function Child(name, age){
Parent.call(this, name, age);
}
Child.prototype = Object.create( Parent.prototype );
Child.constructor = Child;
var child = new Child("cfz", 20);
https://blog.csdn.net/qq_41694291/article/details/97488644