// 创建父类
function Animal(){
this.name = 'Animal'
}
// 添加共享方法eat
Animal.prototype.eat = function(){
console.log(`${this.name} eat food!`)
}
// 创建子实例
function Cat(){
this.size = 'big'
}
// 实现继承
Cat.prototype = new Animal()
// 添加子类的方法
Cat.prototype.sleep = function(){
console.log(`${this.size} ${this.name} sleep 3 hours!`)
}
// 创建实例
let myCat = new Cat()
// 调用构造函数的方法
myCat.eat()
// 调用父类方法
myCat.sleep()
缺点: 引用类型的属性被所有实例共享, 修改堆内存数据时候会将所有实例的数据都修改,但是直接创建新的存储对象就不会产生此错误
// 创建父类
function Animal(){
this.name = ['Animal']
}
// 创建子实例
function Cat(){
this.size = 'big'
}
// 实现继承
Cat.prototype = new Animal()
// 创建实例
let myCat = new Cat()
let youCat = new Cat()
// 修改对象存储类型的对内存数值
youCat.name.push('cat')
console.log(youCat.name ) // ["Animal", "cat"]
console.log(myCat.name ) // ["Animal", "cat"]
// 修改对象存储类型的引用地址
youCat.name = ['cat']
console.log(youCat.name ) // ["cat"]
console.log(myCat.name ) // ["Animal", "cat"]
function Animal(){
this.sleep = [1,2,3,4]
}
function cat (){
}
cat.prototype.run = '20km'
// 原型链继承
cat.prototype = new Animal()
let mao1 = new cat()
let mao2 = new cat()
console.log(mao1.sleep) // [1,2,3,4]
mao1.sleep.push(...[7,8,9])
// 构造函数的引用类型被修改后其余对象实例都受到影响
console.log(mao1.sleep) // [1,2,3,4,7,8,9]
console.log(mao2.sleep) // [1,2,3,4,7,8,9]
// 子类的prototype的constructor指向了构造函数,所以子类的构造方法不会被子类实例对象继承
console.log(mao1.run) //undefined
// 解决办法,将子类的prototype的constructor指向子类
cat.prototype.constructor = cat
cat.prototype.jump = '10km'
// 子类的原型上绑定的方法必须要在修改原型的constructor之后
console.log(mao1.run) // unfined
console.log(mao1.jump) // 10km
如果子对象的方法和构造函数的方法相同,子对象的对象实例,会调用子对象的方法,构造函数中的属性将被隐蔽,可以使用__prorto__调用
function Animal(){
this.sleep = [1,2,3,4]
this.eat = function(){
console.log('Animal eat food')
}
}
function cat (){
this.eat = function(){
console.log('cat eat finsh')
}
}
// 原型链继承
cat.prototype = new Animal()
let mao1 = new cat()
console.log(mao1.eat()) // cat eat finsh
function Animal(){
this.sleep = [1,2,3,4]
this.eat = function(){
console.log('Animal eat food')
}
}
function cat (){
// 盗用构造函数
Animal.call(this)
}
let mao = new cat()
console.log(mao)
function Animal(){
this.sleep = [1,2,3,4]
this.eat = function(){
console.log('Animal eat food')
}
}
Animal.prototype.jump = function (){ console.log('Animal jump 20km')}
function cat (){
// 盗用构造函数
Animal.call(this)
}
cat.prototype.run = function (){ console.log('cat run 10km')}
let mao = new cat()
console.dir(mao.run())
console.dir(mao.jump())
function Animal(){
this.coler = 'red'
this.age = 2
this.sleep = [1,2,3,4]
}
Animal.prototype.run = function (){ console.log('Animal run 10km')}
function Cat(){
// 盗用构造函数
Animal.call(this)
this.name = {first:'big',last:'mao'}
}
// 原型链继承
Cat.prototype = new Animal()
Cat.prototype.constructor = cat
Cat.prototype.eat = function (){console.log('cat eat fish')}
// 创建实例
let mao = new Cat()
let mao1 = new Cat()
mao.run() // 构造函数的原型 ,被继承
mao.sleep.push(...[8,9])// 修改构造函数的对象类型属性,没有相互影响
console.log(mao.sleep)
console.log(mao1.sleep)
mao.eat() // 调用对象的原型方法,也被继承了
function getObj(obj){
function F(){}
F.prototype = obj
return new F()
}
let obj = {name:'zhangsan', age:['20',5],game:function(){}}
let f1 = getObj(obj)
let f2 = getObj(obj)
f1.age.push(78)
console.log(f1.age) //["20", 5, 78]
console.log(f1.age) //["20", 5, 78]
缺点是多个实例对象之间会将传入的对象的引用属性篡改,并且无法传参function getObj(obj){
function F(){}
F.prototype = obj
return new F()
}
function getOther(obj){
let p = getObj(obj)
p.say= function(){console.log('say hello ')}
return p
}
let obj = {name:'zhangsan', age:['20',5],game:function(){}}
let other = getOther(obj)
let other1 = getOther(obj)
other.age.push(92)
console.log(other.age)
console.log(other1.age)
other1.say()
原型式继承有的缺点寄生式继承也存在// 构造函数的构成
function inheritPrototype(subType, superType){
// 复制一个父类原型
copySuperPrototype = Object.create(superType.prototype)
// 将父类原型的构造函数执行子类,弥补因重写原型而失去的默认的constructor 属性
copySuperPrototype.constructor = subType
// 将子类的原型指向父类复制出来的原型上
subType.prototype = copySuperPrototype
}
// 父类
function superType(name){
this.name = name
this.color = ['red']
}
// 子类
function subType(name, age){
superType.call(this,name)
this.age = age
}
inheritPrototype(subType, superType)
let o1 = new subType('zhangsan',12)
let o2 = new subType('lisi',78)
o1.color.push(1)
console.dir(o1)
console.dir(o2)
这是现在库实现的方法,也是目前最成熟的方法Object.assign
会把 OtherSuperClass
原型上的函数拷贝到 MyClass
原型上,使 MyClass 的所有实例都可用 OtherSuperClass 的方法 function MyClass() {
SuperClass.call(this);
OtherSuperClass.call(this);
}
// 继承一个类
MyClass.prototype = Object.create(SuperClass.prototype);
// 混合其它
Object.assign(MyClass.prototype, OtherSuperClass.prototype);
// 重新指定constructor
MyClass.prototype.constructor = MyClass;
MyClass.prototype.myMethod = function() {
// do something
};
extends
关键字主要用于类声明或者类表达式中,以创建一个类,该类是另一个类的子类。其中constructor
表示构造函数,一个类中只能有一个构造函数,有多个会报出SyntaxError
错误,如果没有显式指定构造方法,则会添加默认的 constructor
方法,使用例子如下。 class Rectangle {
// constructor
constructor(height, width) {
this.height = height;
this.width = width;
}
// Getter
get area() {
return this.calcArea()
}
// Method
calcArea() {
return this.height * this.width;
}
}
const rectangle = new Rectangle(10, 20);
console.log(rectangle.area);
// 输出 200
-----------------------------------------------------------------
// 继承
class Square extends Rectangle {
constructor(length) {
super(length, length);
// 如果子类中存在构造函数,则需要在使用“this”之前首先调用 super()。
this.name = 'Square';
}
get area() {
return this.height * this.width;
}
}
const square = new Square(10);
console.log(square.area);
// 输出 100
extends继承的核心代码如下,其实现和上述的寄生组合式继承方式一样
function _inherits(subType, superType) {
// 创建对象,创建父类原型的一个副本
// 增强对象,弥补因重写原型而失去的默认的constructor 属性
// 指定对象,将新创建的对象赋值给子类的原型
subType.prototype = Object.create(superType && superType.prototype, {
constructor: {
value: subType,
enumerable: false,
writable: true,
configurable: true
}
});
if (superType) {
Object.setPrototypeOf
? Object.setPrototypeOf(subType, superType)
: subType.__proto__ = superType;
}
}