创建对象的多种方式
1)工厂模式
function createPerson(name) {
var _obj = new Object();
_obj .name = name;
_obj .getName = function () {
console.log(this.name);
};
return _obj ;
}
var person1 = createPerson('anissa');
优点:简单;
缺点:对象⽆法识别,因为所有的实例都指向⼀个原型;
2)构造函数模式
function createPerson(name) {
this.name = name;
this.getName = function () {
console.log(this.name);
};
}
var person1 = createPerson('anissa');
优点:实例可以识别为⼀个特定的类型;
缺点:每次创建实例时,每个⽅法都要被创建⼀次;
优化
function Person(name) {
this.name = name;
this.getName = getName;
}
function getName() {
console.log(this.name);
}
var person1 = new Person('anissa');
3)原型模式
function Person(name) {
}
Person.prototype.name = 'anissa';
Person.prototype.getName = function () {
console.log(this.name);
};
var person1 = new Person();
优点:⽅法不会重新创建;
缺点:
- 所有的属性和⽅法都共享;
- 不能初始化参数;
优化
function Person(name) {
}
Person.prototype = {
name: 'anissa',
getName: function () {
console.log(this.name);
}
};
var person1 = new Person();
优点:封装清晰点;
缺点:重写了原型,丢失了constructor属性;
再次优化
function Person(name) {
}
Person.prototype = {
constructor: Person,
name: 'anissa',
getName: function () {
console.log(this.name);
}
};
var person1 = new Person();
优点:实例可以通过constructor属性找到所属构造函数;
缺点:
- 所有的属性和⽅法都共享;
- 不能初始化参数;
4)组合模式
function Person(name) {
this.name = name;
}
Person.prototype = {
constructor: Person,
getName: function () {
console.log(this.name);
}
};
var person1 = new Person();
优点:属性共享,方法私有,使⽤最⼴泛的⽅式;
缺点:希望写在⼀个地⽅,即更好的封装性;
优化:动态原型模式
function Person(name) {
this.name = name;
if (typeof this.getName != "function") {
Person.prototype.getName = function () {
console.log(this.name);
}
}
}
var person1 = new Person();
继承的多种方式
1)原型链继承
function Parent () {
this.name = 'anissa';
}
Parent.prototype.getName = function () {
console.log(this.name);
}
function Child () {
}
Child.prototype = new Parent();
var child1 = new Child();
console.log(child1.getName()) // anissa
在这种情况下,引用类型的属性会被多个实例更改共享
2)构造函数继承
function Parent () {
this.names = ['anissa', 'delyn'];
this.sex=arguments[0];
console.log(this.sex);//female
}
function Child () {
console.log(...arguments);//female
Parent.call(this,...arguments);
}
var child1 = new Child("female");
child1.names.push('test');
console.log(child1.names); // ["anissa", "delyn", "test"]
var child2 = new Child();
console.log(child2.names); // ["anissa", "delyn"]
优点:
- 避免了引⽤类型的属性被所有实例共享;
- 可以在 Child 中向 Parent 传参;
3)组合继承
function Parent (name) {
this.name = name;
this.colors = ['red', 'blue', 'green'];
}
function Child (name, age) {
Parent.call(this, name);
this.age = age;
}
Child.prototype = new Parent();
Child.prototype.constructor = Child;
var child1 = new Child('anissa', '18');
child1.colors.push('black');
console.log(child1.name); // anissa
console.log(child1.age); // 18
console.log(child1.colors); // ["red", "blue", "green", "black"]
var child2 = new Child('delyn', '20');
console.log(child2.name); // delyn
console.log(child2.age); // 20
console.log(child2.colors); // ["red", "blue", "green"]
优点:融合原型链继承和构造函数的优点,是 JavaScript 中最常⽤的继承模式
4)原型继承
function createObj(o) {
function F(){}
F.prototype = o;
return new F();
}
缺点:
包含引⽤类型的属性值始终都会共享相应的值,这点跟原型链继承⼀样。
var person = {
name: 'anissa',
friends: ['delyn', 'krystal']
}
var person1 = createObj(person);
var person2 = createObj(person);
person1.name = 'person1';
console.log(person2.name); // anissa
person1.friends.push('kitty');
console.log(person2.friends); // ["delyn", "krystal", "kitty"]
5)寄生式继承
创建⼀个仅⽤于封装继承过程的函数,该函数在内部以某种形式来做增强对象,最后返回对象
function createObj (o) {
var clone = Object.create(o);
clone.sayName = function () {
console.log('hi');
}
return clone;
}