原型
创建对象的方法
let obj = {}
let obj1 = Object.create(obj)
let obj2 = new Object(obj1)
function M(){} let obj3 = new M()
原型详解
Javascript中每一个对象都有自己的特殊内置属性**[[prototype]]**,这个特殊属性可以指向另一个对象
获取方式
可以通过实例对象的__proto__属性可以获取到。
let obj = {}
obj.__proto__ === Object.getPrototypeOf(obj) //true
该图为构造函数和原型对象,实例对象的关系
constructor
该属性在对象创建时就在prototype中存在
该属性不可遍历,但是可以通过属性描述符改变属性,使其可以遍历
Object.defineProperty(Super.prototype,'constructor',{
enumerable:true,
configurable:true,
writable:true,
value:Super
})
console.log(Object.keys(sub))
原型链
总结:所有函数都是function的实例,所有原型对象都是Object()的实例。原型链又叫隐式原型链,由__proto__串联而成
ES5中实现继承
原型链继承
这里可看到,sub继承了Super上的属性
弊端:引用值共享问题,引用值sub1改变后sub上也改变了。
构造函数继承
引用值共享问题解决
**弊端:**无法继承到父亲原型上的方法
组合式继承(伪经典继承)
弊端 : new Super() 和 Super.call执行了两次 ,性能损失
寄生组合式继承
性能损失解决
弊端:重写了Sub.prototype,使得实例化对象无法调用方法
圣杯模式继承
function inherit(Target,Origin){
function F(){}
F.prototype = new F();
Target.prototype = F.prototype
Target.prototype.constructor = Target
Target.prototype.uber = Origin.prototype
}
圣杯模式在子类和父类中定义了一个中间类,这样改变子类上的prototype上的变量就不会影响到父类的prototype,因为他们不共享原型。
雅虎高级写法,使用闭包私有化变量
const inheritYaHU = (function (){
var F = function (){}
return function (Target,Origin){
F.prototype = Origin.prototype
Target.prototype = new F();
Target.prototype.constructor = Target
Target.prototype.uber = Origin.prototype
}
}())
ES6中实现继承
class
内部操作
当我们通过new关键字操作类的时候,会调用这个constructor函数,并且执行如下操作:
◻ 1.在内存中创建一个新的对象(空对象);
◻ 2.这个对象内部的[[prototype]]属性会被赋值为该类的prototype属性;
◻ 3.构造函数内部的this,会指向创建出来的新对象;
◻ 4.执行构造函数的内部代码(函数体代码);
◻ 5.如果构造函数没有返回非空对象,则返回创建出来的新对象;
类似于java,可以使用extends继承
class Father {
constructor(){
this.name = 'jth'
}
static say(name){
console.log(name)
}
sayName(){
console.log('wolf')
}
}
class Son extends Father{
constructor(){
//调用父类方法
super().sayName();
}
}
let son = new Son()
console.log(son.name)
也可以继承内置类。
js不支持多继承,可以使用mixin进行继承,使用父类方法
// JavaScript只支持单继承(不支持多继承)
function mixinAnimal(BaseClass) {
return class extends BaseClass {
running() {
console.log("running~")
}
}
}
function mixinRunner(BaseClass) {
return class extends BaseClass {
flying() {
console.log("flying~")
}
}
}
class Bird {
eating() {
console.log("eating~")
}
}
// var NewBird = mixinRunner(mixinAnimal(Bird))
class NewBird extends mixinRunner(mixinAnimal(Bird)) {
}
var bird = new NewBird()
bird.flying()
bird.running()
bird.eating()