对象的创建
字面量
- 语法
var person = {
name:"Cookie",
age:20
}
- 适用场景
- 对象内部数据是已知的
- 优点
- 简单清楚
- 缺点
- 创建多个对象时代码重复度高
工厂函数
- 语法
- 优点
- 解决了创建多个相似对象的问题
- 缺点
- 存在对象识别的问题
- 存在对象识别的问题
构造函数
- 语法
- 优点
- 自定义的构造函数可以将它的实例标识为一种特定的类型
- 自定义的构造函数可以将它的实例标识为一种特定的类型
- 缺点
- 构造函数中的每个方法都会在实例中重新创建一遍
- 构造函数中的每个方法都会在实例中重新创建一遍
原型模式
我们创建的每一个函数都有一个prototype属性指向一个对象,这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法
- 语法
- 缺点
- 省略了为构造函数初始化参数的环节,使所有的实例默认情况下都取得相同的值
- 属性的共享
组合模式(常用)
继承
原型链
- 基本使用
function Person(){
this.type= "person";
}
Person.prototype.getType = function(){
return this.type;
}
function Student(name){
this.name = name;
this.type = "student";
}
Student.prototype = new Person(); //实现继承
var student = new Student("Cookie");
console.log(student.getType())
- 注意:
Student.prototype = new Person()
本质是重写了原型对象,所以给原型添加方法的代码一定要放在替换原型语句之后,不然就不起作用了。 - 存在的问题
-
在通过原型链实现继承时,在超类构造函数中定义的引用类型的属性会成为子类原型对象中的属性,那么就又会出现共享的问题了
-
在创建子类型的实例时,不能向超类的构造函数传递参数
-
借用构造函数(伪造对象|经典继承)
- 思想
- 在子类的构造函数中调用超类的构造函数
function Person(type){
this.type= type;
}
function Student(name){
this.name = name;
Person.call(this,"student");
}
var student = new Student("Cookie");
console.log(student.type) //studnet
- 优点
- 可以传递参数
- 存在的问题
- 没有函数的复用,想解决函数的复用就要将共享的方法定义到原型对象中,但是在超类原型中定义的方法对子类是不可见的
- 没有函数的复用,想解决函数的复用就要将共享的方法定义到原型对象中,但是在超类原型中定义的方法对子类是不可见的
组合继承
使用原型链实现对原型属性和方法的继承,通过借用构造函数来实现对实例属性的继承
function Person(name,age){
this.name = name;
this.age = age;
this.friends = ["Max"];
}
Person.prototype.sayName = function(){
console.log(this.name)
}
function Student(type,name,age){
Person.call(this,name,age)
this.type = type;
}
Student.prototype = new Person(); //实现继承
Student.prototype.constructor = Student;
Student.prototype.sayAge= function(){
console.log(this.age)
};
var student1 = new Student("Cookie",20);
student1.friends.push("Maria")
console.log(student1);
var student2 = new Student("Yang",18);
console.log(student2);
student1.sayName == student2.sayName