工厂函数模式
function createPerson(name, age, job) { var o = new Object(); o.name = name; o.age = age; o.job = job; o.sayName = function() { alert(this.name); } return 0; } var person1 = createPerson('Nicholas', 29, 'software engineer'); var person2 = createPerson('greg', 27, 'doctor')
构造函数模式
function Person(name, age, job) { this.name = name; this.age = age; this.job = job; this.sayName = function () { alert(this.name); } return 0; } var person1 = new Person('Nicholas', 29, 'software engineer'); var person2 = new Person('greg', 27, 'doctor'); alert(person1.constructor == Person) // true
- 构造函数始终都应该以一个大写之母开头,而非构造函数则应该以小写之母开头。
- 创建Person的新实例,必须使用new操作符。
- 使用new这种方式调用构造函数会经历4个步骤 1.创建一个新对象 2.将构造函数的作用域赋给新对象(因此 this就指向了这个新对象) 3.执行构造函数中的代码 为这个新对象添加属性 4.返回新对象
- 构造函数与普通函数的区别
- 任何函数通过new操作符来调用,那它就是构造函数
- 构造函数的缺点
- 就是每个方法都要在每个实例上重新创建一遍。
- person1和person2都有一个名为sayName()的方法,但那两个方法不是同一个Function的实例。
- 每定义一个函数,也就是实例化了一个对象。
- 从逻辑上讲,可以这样
function Person(name, age, job) { this.name = name; this.age = age; this.job = job; this.sayName = new Function('alert(this.name)'); //与声明函数在逻辑上是等价的 } alert(person1.sayName == person2.sayName) // false
- 把函数定义转移到构造函数外部
function Person(name, age, job) { this.name = name; this.age = age; this.job = job; this.sayName = sayName; } function sayName() { alert(this.name); } var person1 = new Person('Nicholas', 29, 'software engineer'); var person2 = new Person('greg', 27, 'doctor')// 我们把sayName()定义在外部,person1 和person2 共享了在全局作用域中定义的同一个sayname()函数。// 如果对象需要定义很多方法,那么就要定义很多个全局函数,于是这个自定义的引用类型没有分装性可言// 可以使用原型模式
原型模式
使用原型对象的好处是可以让所有对象实例共享它所包含的属性和方法
function Person() { } Person.prototype.name = 'nicholas'; Person.prototype.age = 29; Person.prototype.job = 'software engineer'; Person.prototype.sayName = function () { alert(this.name); } var person1 = new Person(); person1.sayName(); // nicholas var person2 = new Person(); person2.sayName(); // nicholas alert(person1.sayName == person2.sayName); // true // 什么是原型对象 // 只要创建了一个函数,就会根据一组特定的规则为该函数创建一个prototype属性,这个属性指向函数的原型对象。 // 在默认情况下,所有的原型对象都会自动获得一个constructor(构造函数)属性。这个属性包含一个指向prototype属性所在函数的指针。 // Person.prototype constructor指向Person. // 而通过这个构造函数,我们可以原型对象添加其他属相和方法。
简单的原型模式语法
function Person() { } Person.prototype = { name: 'nicholas', age: 29, job: 'software engineer', sayName: function() { alert(this.name); } } var friend = new Person();
- 原型对象的缺点
- 不能为构造函数传递初始化参数
- 最大的问题是 是由其共享本性所导致的。
- 原型中所有属性是被很多实例共享的。
原型链
原型链是作为实现继承的主要方法。
- 其基本思想就是利用原型让一个引用类型继承另一个引用类型的属性和方法、
- 构造函数。 原型和实例之间的关系。
- 每个构造函数都有一个原型对象,原型对象包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。
- 那么,假如我们让原型对象等于另一个类型的实例,此时的原型对象将包含一个指向另一个原型的指针,相应地,另一个原型中包含着一个指向另一个构造函数的指针、
- 假如另一个原型又是另一个类型的实例,那么上述关系依然成立,如此,就构成了实例与原型的链条。这就是所谓的原型链、
function SuperType() { this.property = true; } SuperType.prototype.getSuperValue = function() { return this.property; }; function SubType() { this.subproperty =false; } // 继承了supertype SubType.prototype = new SuperType(); SubType.prototype.getSubValue = function() { return this.subproperty; } var instance = new SubType(); alert(instance.getSuperValue()) //true
借用构造函数继承
使用apply() 和call() 方法也可以在将来新创建的对象上执行构造函数
function SuperType() { this.colors = ['red', 'blue', 'green']; } function SubType() { // 继承了 supertype SuperType.call(this); } var instance1 = new SubType(); instance1.colors.push('black'); alert(instance1.colors)// red blue green black var instance2 = new SubType(); alert(instance2.colors); // 'red', 'blue', 'green'
// 1.传递参数 function SuperType(name) { this.name = name; } function SubType() { // 继承了SuperType同时还传递了参数 SuperType.call(this, 'nicholas'); // 实例属性 this.age = 29; } var instance = new SubType(); alert(instance.name); alert(instance.age);
- 借用构造函数的问题
方法都在构造函数中定义,因此函数的复用就无从谈起。
组合继承
通过借用构造函数来实现对实例属性的继承。这样,即通过在原型上定义方法实现了函数复用,有能保证每个实例都有它自己的属性、
function SuperType(name) { this.name = name; this.colors = ['red', 'blue', 'green']; } SuperType.prototype.sayName = function() { alert(this.name); } function SubType(name, age) { // 继承属性 SuperType.call(this, name); this.age = age; } // 继承方法 SubType.prototype = new SuperType(); SubType.prototype.constructor = SubType; SubType.prototype.sayAge = function() { alert(this.age); } var instance1 = new SubType('nicholas', 29); instance1.colors.push('black'); alert(instance1.colors);//red,blue,green,black instance1.sayName()//nicholas instance1.sayAge()// 29 var instance2 = new SubType('greg', 27); alert(instance2.colors);//red,blue,green instance2.sayName()//greg instance2.sayAge()// 27