1.创建对象 (通过字面量或者Object构造函数)
var person = {}; or new Object();
person.age = 12;
person.say = function() {
alert(this.age)
}
缺点:使用同一个接口创建很多对象,会产生大量重复代码
2.工厂模式 (通过函数来封装特定接口创建对象)
function creatPerson(age) {
var o = new Object();
o.age = age;
o.say = function() {
alert(this.age);
}
return o;
}
var person1 = createPerson(23);
var person2 = createPerson(21);
缺点:虽然解决了创建多个相似对象问题,但却没有解决对象识别问题(即怎样知道一个对象的类型)
3.构造函数模式 (创建自定义构造函数,从而定义自定义对象类型属性和方法)
function Person(age) {
this.age = age;
this.say = function() {
alert(this.age);
}
}
var person1 = new Person(23);
var person2 = new Person(21);
function say() { alert(this.age); } // 全局函数
缺点:不同实例上的同名函数不相等。person1.say == person2.say // false
将this.say改成指针指向全局函数say()。这样就不用创建不同Function实例,但是say()是全局函数,没有封装性可言。
4.原型模式(通过原型对象共享属性和方法)
function Person() {
}
Person.prototype.age = 23;
Person.prototype.say = function() {
alert(this.age)
}
var person1 = new Person();
var person2 = new Person();
person1.say == person2.say // true
创建函数,自动拥有prototype属性,这个属性指向函数的原型对象。
实例与构造函数的原型对象是有关系的,与构造函数没关系。
person1.age = 1;
person1.age // 1
person2.age // 23
person1先访问实例属性,再访问原型属性。通过delete person1.age 删除实例属性, 随后即可访问原型属性。
判断实例是否拥有属性
“age” in person1
判断是否实例属性
person1 hasOwnProperty(“name”)
更简单的原型语法
function Person() {
}
Person.prototype = {
age: 23,
say: function() {
alert(this.age);
}
}
Person.prototype.name => person1.constructor = Person
Person.prototype = {} => 字面量赋值,改写了person1.constructor = Object
Person.prototype = {
constructor: Person,
age: 23
...
}
原生对象的原型:
Array.prototype.sort
Person.prototype.friend = [‘tony’]
person1.friends.push(‘van’) // tony, van
person2.friends // tony,van
缺点:省略了为构造函数传递初始化参数这一环节,所有实例在默认情况下将取得相同的属性值。
5.构造函数+原型模式
function Person(age) {
this.age = age;
this.friend = ['tony']
}
Person.prototype = {
constrostor: Person,
say: function() {
alert(this.name);
}
}
var person1 = new Person(1);
var Person2 = new Person(2);
person1.friends.push("van");
person1.friends // tony, van
person2.friends // tony
person1.say === person2.say // true
6.动态原型模式(由于开发人员看到独立的构造函数和原型时困惑,所以把所有信息都封装在构造函数中)
function Person(age) {
this.age = age;
if( typeof this.say != 'function') {
Person.prototype.say = function() {
alert(this.age);
}
}
}
使用动态原型模型时,不能使用对象字面量重写原型。
7.寄生构造函数模式
与工厂模式相似,只是通过new 构造函数不一样。
构造函数默认返回新对象实例,通过在构造函数末尾添加return语句,重写调用构造函数时返回的值。
8. 稳妥构造函数模式 (不使用this,new)
========================
继承
1.原型链继承
function SuperType() {
this.colors = ['red']
}
function SubType() {}
SubType.prototype = new SuperType() // 继承了SuperType
var instance1 = new SubType();
instance1.colors.push('blue');
instance1.colors // red, blue
var instance2 = new SubType();
instance2.colors // red, blue
问题: SuperType每个实例都有各自colors属性,SubType所有实例共享同一个colors属性。在创建子类型的实例时,不能向超类型的构造函数传递参数。
2.借用构造函数
function SuperType(name) {
this.colors = ['red'];
this.name = name;
}
function SubType() {
SuperType.call(this,'wu'); // 继承了SuperType
}
在子类型构造函数内部调用超类型构造函数。(call(), apply()执行构造函数)
问题: 方法都在构造函数中定义,因此无法函数复用。(在超类型的原型中定义的方法,对子类型而言不可见)
3.组合继承(原型链+借用构造函数)
function SuperType(name) {
this.colors = ['red'];
this.name = name;
}
SuperType.prototype.say = function() {
alert(this.name);
}
function SubType() {
SuperType.call(this,'wu'); // 继承属性
}
SubType.prototype = new SuperType(); // 继承方法
此处原型链也继承了属性
var instance1 = new SubType(‘wu’);
instance1.name = wu // 实例name
delete instance1.name
instance1.name = wu // 原型对象name
“name” in instance1 // true
instance1.hasOwnProperty(‘name’) // false
