构造函数模式
构造函数中的实例属性在各个实例化对象间是独立的
function Box(name, age) { //构造函数模式
this.name = name; //实例属性
this.age = age;
this.run = function () {
return this.name + this.age + '运行中...';
};
}
var box1 = new Box('Lee', 100); //new Box()即可
var box2 = new Box('Jack', 200);
构造函数方式
构造函数中的实例属性在各个实例化对象间是独立的
构造函数的方法有一些规范:
1.函数名和实例化构造名相同且大写,(PS:非强制,但这么写有助于区分构造函数和
普通函数);
2.通过构造函数创建对象,必须使用new 运算符。
既然通过构造函数可以创建对象,那么这个对象是哪里来的,new Object()在什么地方
执行了?执行的过程如下:
1.当使用了构造函数,并且new 构造函数(),那么就后台执行了new Object();
2.将构造函数的作用域给新对象,(即new Object()创建出的对象),而函数体内的this 就
代表new Object()出来的对象。
3.执行构造函数内的代码;
4.返回新对象(后台直接返回)。
原型模式
原型属性可以被所有的实例对象共享
我们创建的每个函数都有一个prototype(原型)属性,这个属性是一个对象,它的用途是
包含可以由特定类型的所有实例共享的属性和方法。逻辑上可以这么理解:prototype 通过
调用构造函数而创建的那个对象的原型对象。使用原型的好处可以让所有对象实例共享它所
包含的属性和方法。也就是说,不必在构造函数中定义对象信息,而是可以直接将这些信息
添加到原型中。
function Box() {} //声明一个构造函数
Box.prototype.name = 'Lee'; //在原型里添加属性
Box.prototype.age = 100;
Box.prototype.run = function () { //在原型里添加方法
return this.name + this.age + '运行中...';
};
原型模式方式
原型属性可以被所有的实例对象共享
在原型模式声明中,多了两个属性,这两个属性都是创建对象时自动生成的。__proto__
属性是实例指向原型对象的一个指针,它的作用就是指向构造函数的原型属性constructor。
通过这两个属性,就可以访问到原型里的属性和方法了。
原型模式的执行流程:
1.先查找构造函数实例里的属性或方法,如果有,立刻返回;
2.如果构造函数实例里没有,则去它的原型对象里找,如果有,就返回;
为了让属性和方法更好的体现封装的效果,并且减少不必要的输入,原型的创建可以使
用字面量的方式:
function Box() {};
Box.prototype = { //使用字面量的方式
name : 'Lee',
age : 100,
run : function () {
return this.name + this.age + '运行中...';
}
};
使用构造函数创建原型对象和使用字面量创建对象在使用上基本相同,但还是有一些区
别,字面量创建的方式使用constructor 属性不会指向实例,而会指向Object,构造函数创建
的方式则相反。
如果想让字面量方式的constructor 指向实例对象,那么可以这么做:
Box.prototype = {
constructor : Box, //直接强制指向即可
};
PS:字面量方式为什么constructor 会指向Object?因为Box.prototype={};这种写法其实
就是创建了一个新对象。而每创建一个函数,就会同时创建它prototype,这个对象也会自
动获取constructor 属性。所以,新对象的constructor 重写了Box 原来的constructor,因此会
指向新对象,那个新对象没有指定构造函数,那么就默认为Object。
原型的声明是有先后顺序的,所以,重写的原型会切断之前的原型,之前的原型全部被新原型覆盖。
构造函数模式+原型模式
function Box(name, age) { //不共享的使用构造函数
this.name = name; //实例属性独立
this.age = age;
this. family = ['父亲', '母亲', '妹妹'];
};
Box.prototype = { //共享的使用原型模式
constructor : Box,//原型属性共享
run : function () {
return this.name + this.age + this.family;
}
};
原型模式,不管你是否调用了原型中的共享方法,它都会初始化原型中的方法,并且在
声明一个对象时,构造函数+原型部分让人感觉又很怪异,最好就是把构造函数和原型封装
到一起。为了解决这个问题,我们可以使用动态原型模式。
function Box(name ,age) { //将所有信息封装到函数体内
this.name = name;
this.age = age;
if (typeof this.run != 'function') { //仅在第一次调用的初始化
Box.prototype.run = function () {
return this.name + this.age + '运行中...';
};
}
}
var box = new Box('Lee', 100);
alert(box.run());
当第一次调用构造函数时,run()方法发现不存在,然后初始化原型。当第二次调用,就
不会初始化,并且第二次创建新对象,原型也不会再初始化了。这样及得到了封装,又实现
了原型方法共享,并且属性都保持独立。