1、 函数的构造函数
内置函数 Object. proto === Function.prototype => true
内置函数和普通函数都是有Function构造出来的。
console.log(Object.constructor)// Object函数自身没有constructor属性,//会沿着原型链去找原型Functiono.protorype.constructor => Function
一切函数都是Function的实例,包括Function本身。
Function是实例对象,也是构造函数。
console.log(Function.__proto__ === Function.prototype) // true 函数都是Function的实例
2、对象的getter、setter方法
将对象属性绑定到查询该属性时将被调用的函数。
let obj = {a:1;get b(){return 'b'},set b(val){this.a = val}}
setter和getter尝尝用来创建伪属性,不能在具有真实值属性上同时拥有setter器
可在对象初始化时添加、使用delete删除、使用Object.defineProperty随时添加setter和getter
3、继承方式
(1)原型链继承
将祖辈实例对象作为父类的原型对象进行原型链继承。
缺点:
(1)原型链上引用值共享
(2)子类实例化的时候无法给父类传参。
function Super(){this.name = 'SuperInstance'this.arr = [1, 2, 3]}let superInstance = new Super()function Father(){this.name = 'FatherInstance'}//将祖辈原型实例作为父类原型对象Father.prototype = superInstancelet son1 = new Father(),son2 = new Father();son1.arr.push(6);console.log(son2.arr) // => [1,2,3,6]// son的原型链 son.__proto__ => Father.prototype(superInstance) => Super.prototype
(2)盗用构造函数(constructor stealing)也被叫作经典继承
避免原型链引用值共享的方法:借用构造函数,子类实例可以给父类构造函数传参,原理是给每个实例对象添加自己的属性值。缺点:无法是子类实例继承父类构造函数的原型对象。
function Super(){this.name = 'SuperInstance'}function Father(){this.name = 'FatherInstance'Super.call(this)}let son = new Father()
但是借用父类构造函数,没有让子类实例继承父类的原型对象。
所以还需造出父类实例,指为子类构造函数的原型对象
(3)组合继承(伪经典继承):
function Super(name){this.name = name}let superInstance = new Super()Father.prototyper = superInstancefunction Father (opt){Super.call(this)this.habbit = opt.habbit}//这样解决了引用值共享的问题,也让子类实例继承了父类原型对象。//但是,这样调用了两次父类构造函数
(4)寄生组合继承
组合继承解决了原型引用值共享的问题,并且让子类实例继承父类原型上的属性与方法。但是有效率问题,父类在创建子类构造函数原型对象时,和子类构造函数时一共调用了两次。可以用 Object.create()来优化
Father.prototype = Object.create(Super.prototype) // =>创造一个实例,并指定继承的对象。
function Super(c){this.name = opt.name}function Son function(){Super.call(this)}Son.prototype = Object.create(Super.prototype)let son = new Son()//Object.create的es6兼用方式function correctProto(proto){if(Object.create){return Object.create(proto)}else{function Buffer(){}Buffer.prototype = protoreturn new Buffer()}}Fater.prototype = correctProto(Super.prototype)
(5)圣杯模式
function Buffer(){}Buffer.prototype = protolet buffer = new Buffer()Son.prototype = bufferSon.prototype.constructor = SonSon.superClass = Super//创建一个继承自父类的干净对象,指定为子类构造函数的prototype。//然后把子类构造函数的constructor矫正,并记录继承的超类。
(6)es6 class继承
同是解决了引用值共享问题,实现了子类实例对父类方法的继承
class Super{constructor(){this.a = [1,2,3]}superSay(){console.log(this.a)}}class Sub extends Super{constructor(name){super()this.name = name}subSay(){console.log(this.name)}}let sub1 = new Sub('sub1'),sub2 = new Sub('sub2');sub1.a.push('sub1')sub1.subSay()sub2.subSay()console.log(sub1,sub2)
(7)其他继承方式:拷贝继承,用的很少
(8)class的一些用法
1、可以直接在class内部添加实例自身属性
class Super{a = [1,2,3,4,5]}let sub = new Super()
2、子类构造函数继承父类构造函数时,constructor中使用this之前,需要调用super方法
3、static静态方法,构造函数自身的方法(Object.create、Array.from、Array.of)。如果不加static关键字的话,就变成了构造函数原型对象上的方法了。
class Super{static say(){console.log('SuperSay')}}相当于Super.say = function(){console.log('SuperSay')}
