函数的属性直接写在函数里面,函数的方法则写在函数的原型里面,具体看下面这段代码。
function Person (name, age) {
this.type = 'human'
this.name = name
this.age = age
}
Person.prototype.sayName = function () {
console.log('hello ' + this.name)
}
用class
写下面这段代码可以得到上面一样的效果,可以看成一个语法糖,只是把属性写在constructor
里面。
class Person {
constructor(name, age) {
this.type = 'human'
this.name = name
this.age = age
}
sayName() {
console.log('hello ' + this.name)
}
}
用class写的话可以用extends
实现继承,让子类继承父类的属性和方法,但是子类必须在constructor()
方法中调用super()
,如果不调用super()
,子类就找不到自己的this,会发生报错。
class sun extends Person {
constructor(name, age) {
//继承父亲的属性
super()
//继承父亲的方法
sayName() {
super.sayName()
}}
}
除开class
用extends
实现继承,下面还有三种方法实现继承。
原型继承
function Student (name, age) {
Person.call(this, name, age)
}
// 子类的原型指向了父类的实例,这样会调用两次父类构造函数
Student.prototype = new Person()
// 下面这个直接指向了父类的原型,会导致子类的constructor是父类的constructor
// Student.prototype = Person.prototype
var s1 = new Student('张三', 18)
// 这里可以访问到父类实例上的type属性,这是错误的
console.log(s1.type) // human
s1.sayName() // hello 张三
Person.call()
实现让Student调用Person函数,然后把Student的原型指向Person的实例,这样会调用两次父类构造函数,不能直接把Student的原型指向Person的原型,这样会导致Student的constructor
是Person的constructor
.
拷贝继承
function Student (name, age) {
Person.call(this, name, age)
}
// 这里拷贝父类原型上的属性和方法
for (var key in Person.prototype) {
Student.prototype[key] = Person.prototype[key]
}
var s1 = new Student('张三', 18)
s1.sayName() // hello 张三
直接通过for in
遍历Person的原型,然后直接把遍历到的属性和方法赋给Student,这样就可以直接实现继承。
寄生组合继承
function Student (name, age) {
Person.call(this, name, age)
}
Student.prototype = Object.create(Person.prototype)
// 让子类的构造器还是指向自己的构造函数
Student.prototype.constructor = Student
var s1 = new Student('张三', 18)
console.log(s1.type) // human
s1.sayName() // hello 张三
寄生组合继承可以算是引用类型继承的最佳方式了,父类方法可以复用,父类的引用属性不会被共享。