对象创建
1. 字面量(复用性差)
const student = {
name: 'name'
school: 'school',
teacher: 'teacher'
}
2. Object 创建(复用性差)
const student = new Object()
student.name = 'name'
student.school = 'school'
student.teacher = 'teacher'
3. 工厂模式(对象身份识别不了,都是由Object创建)
function Student(name, school, teacher){
const obj = new Object()
obj.name = name
obj.school = school
obj.techer = teacher
}
4. 构造函数(方法创建重复)
function Student(name, school, teacher){
this.name = name
this.school = school
this.teacher = teacher
this.say = function(){
console.log(this.name)
}
}
5. 构造函数+原型
较好的解决了以上问题,使用最为广泛,美中不足,定义的属性方法分离,封装性不强。
function Student(name, school, teacher){
this.name = name
this.school = school
this.teacher = teacher
}
Student.prototype.say = function(){
console.log(this.name)
}
6. 动态原型
动态原型方式创建实例方法就是在第一次使用时创建,之后再实例化时不会重复创建
function Student(name, school, teacher){
this.name = name
this.school = school
this.teacher = teacher
if(typeof this.say !== 'function'){
Student.prototype.say = function(){
console.log(this.name)
}
}
}
对象继承
对象继承的方法核心是原型链。
1. 原型链继承
function Teacher(){
this.name = 'teacher'
}
Teacher.prototype.say = function(){
console.log('i am a teacher')
}
function Student(){}
Student.prototype = new Teacher()
let stu = new Student()
stu.say() // i am a teacher
让Student的原型指向Teacher的实例对象,基于原型链的特性,可进一步继承到Teacher.prototype上的方法。
问题:引用类型的数据会被子类共享,无法向父类传递参数。
2. 盗用构造函数继承
function Teacher(){
this.hobby = {
sport: 'basketball',
subject: 'subject'
}
}
function Student(){
Teacher.call(this)
}
let s1 = new Student(),
s2 = new Studnet()
s1.hobby.book = 'book'
console.log(s1,s2) // 只有s1发生了变化
这种构造方式的目的是让每子类个实例之间屏蔽引用类型数据共享。
原理:父类的this指向子类,子类中也就能继承父类实例的属性和方法,call方法也解决了向父类传递参数的不足。
问题:无法得到父类原型上的方法。
3. 组合继承
function Teacher(){
this.name = 'name'
}
Teacher.prototype.say = function(){
console.log(this.name)
}
function Student(){
Teacher.call(this)
}
Student.prototype = new Teacher()
let s1 = new Student(),
s2 = new Student()
console.log(s1,s2)
将前两种继承方式组合,延续了它们的优势。
问题:重复调用父类,new和call。由于直接改写子类的原型为父类的实例,所以父类实例上的属性和方法会重复出现。
4. 原型式继承
function createObj(obj){
function F(){}
F.prototype = obj
return new F()
}
类似于创建对象原型,简单方便使用。
问题:还是会出现引用类型数据共享的问题,类似于一。
5. 寄生式继承
function extendObj(obj){
let newObj = createObj(obj)
newObj.say = function(){
console.log('this is a new Obj')
}
return newObj
}
在原型式继承的基础增强对象,提供了可用的方法。
问题:引用类型的数据共享,不能向父类传参。
6. 寄生式组合继承
function Teacher(){
this.name = 'name'
}
function Student(){
Teacher.call(this)
}
function inheritProto(target, origin){
let prototype = createObj(origin.prototype)
prototype.constructor = target
target.prototype = prototype
}
inheritProto(Student, Teacher)
// 或者用 Object.create()
原理:直接将子类的原型继承父类的原型。
避免了父类的重复调用,属性方法重复创建。
注意:若在继承前在子类的原型上添加方法会被覆盖,使用时最好在继承后增加方法。
ES6中官方也引入新的继承方法 extends