目录
一、创建对象
1. 工厂模式
<script>
// 定义Person类
var Person = function(name, hobby) {
var o = new Object();
o.name = name;
o.hobby = hobby;
o.talk = function() {
console.log("my name is " + this.name);
}
return o;
}
var xiaoming = Person("xiaoming", "swimming");
console.log(xiaoming); //{name: "xiaoming", hobby: "swimming", talk: ƒ}
xiaoming.talk(); //my name is xiaoming
var xiaohong = Person("xiaohong", "run");
console.log(xiaohong); //{name: "xiaohong", hobby: "run", talk: ƒ}
xiaohong.talk(); //my name is xiaohong
// 缺点: 1.无法识别对象的类型;
// 2. xiaoming和xiaohong的talk方法 虽然同名但是不相等
console.log(xiaoming.talk == xiaohong.talk); //false
</script>
2. 构造函数模式
<script>
//申明构造函数
function Person(name, hobby) {
this.name = name;
this.hobby = hobby;
this.talk = function() {
console.log("my name is " + name);
}
}
// 实例化对象
var xiaoming = new Person("xiaoming", "swimming");
console.log(xiaoming); //Person {name: "xiaoming", hobby: "swimming", talk: ƒ}
xiaoming.talk(); //my name is xiaoming
var xiaohong = new Person("xiaohong", "run");
console.log(xiaohong); //Person {name: "xiaohong", hobby: "run", talk: ƒ}
xiaohong.talk(); //my name is xiaohong
//可以使用 instanceof 方法检测是否为该对象类型
console.log(xiaoming instanceof Person); //true
console.log(xiaoming instanceof Object); //true
console.log(xiaohong instanceof Person); //true
console.log(xiaohong instanceof Object); //true
console.log("缺点: xiaoming和xiaohong的talk方法 虽然同名但是不相等");
console.log(xiaoming.talk == xiaohong.talk);
</script>
3. 原型模式
<script>
//申明Person函数
var Person = function() {};
Person.prototype.name = "default name";
Person.prototype.hobby = ["swimming", "run"];
Person.prototype.talk = function() {
console.log("my name is " + this.name);
}
var xiaoming = new Person();
console.log(xiaoming); //Person {}
xiaoming.talk(); //my name is default name
var xiaohong = new Person();
console.log(xiaohong); //Person {}
xiaohong.talk(); //my name is default name
// 优点: 可以使用 instanceof 方法检测是否为该对象类型
console.log(xiaoming instanceof Person); //true
console.log(xiaoming instanceof Object); //true
console.log(xiaohong instanceof Person); //true
console.log(xiaohong instanceof Object); //true
// 优点: xiaoming和xiaohong的talk方法 同名且相等
console.log(xiaoming.talk == xiaohong.talk);
// 缺点: 当数据为引用类型时, 所有实例会公用一个数据,如下
xiaoming.hobby.push("code");
console.log(xiaoming.hobby); // ["swimming", "run", "code"]
//似乎没什么问题
//我们再来看看小红的
console.log(xiaohong.hobby); // ["swimming", "run", "code"]
//小红的hobby也被加上了数据
// js的数据分为两种类型,基础类型和引用类型
// 基础类型为String, Number, Boolean, null, underfined, Symbol
// 引用类型为Object, Array, Date, RegExp, Function
</script>
4. 混合模式
<script>
//申明构造函数
var Person = function(name, hobby) {
this.name = name;
this.hobby = hobby;
}
Person.prototype.talk = function() {
console.log("my name is " + this.name);
}
// 实例化对象
var xiaoming = new Person("xiaoming", ["swimming"]);
console.log(xiaoming); //Person {name: "xiaoming", hobby: Array(1)}
xiaoming.talk(); //my name is xiaoming
var xiaohong = new Person("xiaohong", ["run"]);
console.log(xiaohong); //Person {name: "xiaohong", hobby: Array(1)}
xiaohong.talk(); //my name is xiaohong
// 判断对象类型
console.log("可以使用 instanceof 方法检测是否为该对象类型");
console.log(xiaoming instanceof Person); //true
console.log(xiaoming instanceof Object); //true
console.log(xiaohong instanceof Person); //true
console.log(xiaohong instanceof Object); //true
console.log("优点: xiaoming和xiaohong的talk方法 同名且相等");
console.log(xiaoming.talk == xiaohong.talk);
console.log("优点: 当数据为引用类型时, 所有实例 不会 公用一个数据,如下")
xiaoming.hobby.push("code");
console.log(xiaoming.hobby); //["swimming", "code"]
//似乎没什么问题
console.log(xiaohong.hobby); //["run"]
//小红的hobby也正确
</script>
这种构造函数与原型混成的模式,是目前在ECMAScript中使用最广泛、认同度最高的一种创建自定义类型的方法。可以说,这是用来定义引用类型的一种默认模式。
——《JavaScript高级程序设计(第3版)》
二、继承
1. 原型链继承
<script>
// 子构造函数.prototype = new 父构造函数();
function Person() {
this.name = "default name";
this.hobby = ["swim"];
this.talk = function() {
console.log("my name is " + this.name);
}
}
function Student(name) {
this.name = name;
this.grade = "high"
}
Student.prototype = new Person();
var xiaoming = new Student("xiaoming");
console.log(xiaoming); //Student {name: "xiaoming", grade: "high"}
xiaoming.talk(); //my name is xiaoming
var xiaohong = new Student("xiaohong");
console.log(xiaohong); //Student {name: "xiaohong", grade: "high"}
xiaohong.talk(); //my name is xiaohong
// 缺点: Parent的引用属性会被所有Child实例共享
xiaoming.hobby.push("run");
console.log(xiaoming.hobby); //["swim", "run"]
console.log(xiaohong.hobby); //["swim", "run"]
// 缺点: 无法向父级传递参数
</script>
2. 构造函数继承
<script>
// 父构造函数().call(this);
function Person(name) {
this.name = name;
this.hobby = ["swim"];
this.talk = function() {
console.log("my name is " + this.name);
}
}
Person.prototype.age = 18;
function Student(name) {
Person.call(this, name);
this.grade = "high";
}
var xiaoming = new Student("xiaoming");
console.log(xiaoming); //Student {name: "xiaoming", hobby: Array(1), grade: "high", talk: ƒ}
xiaoming.talk(); //my name is xiaoming
var xiaohong = new Student("xiaohong");
console.log(xiaohong); //Student {name: "xiaohong", hobby: Array(1), grade: "high", talk: ƒ}
xiaohong.talk(); //my name is xiaohong
// 优点: Parent的引用属性不会被所有Child实例共享
xiaoming.hobby.push("run");
console.log(xiaoming.hobby); //["swim", "run"]
console.log(xiaohong.hobby); //["swim"]
// 缺点: 没有实现函数复用,Parent构造函数中的方法会在每个Child中复制一份,浪费内存
console.log(xiaoming.talk == xiaohong.talk); //false
// 缺点: Person原型对象上的方法不会被Child继承
console.log(xiaoming.age); //undefined
console.log(xiaohong.age); //undefined
</script>
3. 组合继承
<script>
// 属性使用构造函数继承,方法使用原型继承
function Person(name) {
this.name = name;
this.hobby = ["swim"];
}
Person.prototype.talk = function() {
console.log("my name is " + this.name);
}
function Student(name) {
Person.call(this, name);
this.school = "high"
}
Student.prototype = new Person();
var xiaoming = new Student("xiaoming");
console.log(xiaoming); // Student {name: "xiaoming", hobby: Array(1), school: "high"}
xiaoming.talk(); //my name is xiaoming
var xiaohong = new Student("xiaohong");
console.log(xiaohong); //Student {name: "xiaohong", hobby: Array(1), school: "high"}
xiaohong.talk(); //my name is xiaohong
// 优点: 实现函数复用
console.log(xiaoming.talk == xiaohong.talk); //true
// 优点: Parent的引用属性不会被所有Child实例共享
xiaoming.hobby.push("run");
console.log(xiaoming.hobby); //["swim", "run"]
console.log(xiaohong.hobby); //["swim"]
//PS: 此时Child的constructor指向Parent,需要自己重新指向
console.log(Student.prototype.constructor); //ƒ Person(name) {this.name = name;this.hobby = ["swim"];}
Student.prototype.constructor = Student;
console.log(Student.prototype.constructor); //ƒ Student(name) {Person.call(this, name);this.school = "high"}
</script>