1、 函数的构造函数
    内置函数 Object. proto === Function.prototype => true
    内置函数和普通函数都是有Function构造出来的。

    1. console.log(Object.constructor)
    2. // Object函数自身没有constructor属性,
    3. //会沿着原型链去找原型Functiono.protorype.constructor => Function

    一切函数都是Function的实例,包括Function本身。
    Function是实例对象,也是构造函数。

    1. console.log(Function.__proto__ === Function.prototype) // true 函数都是Function的实例

    2、对象的getter、setter方法
    将对象属性绑定到查询该属性时将被调用的函数。

    1. let obj = {
    2. a:1;
    3. get b(){
    4. return 'b'
    5. },
    6. set b(val){
    7. this.a = val
    8. }
    9. }

    setter和getter尝尝用来创建伪属性,不能在具有真实值属性上同时拥有setter器
    可在对象初始化时添加、使用delete删除、使用Object.defineProperty随时添加setter和getter

    3、继承方式
    (1)原型链继承
    将祖辈实例对象作为父类的原型对象进行原型链继承。
    缺点:
    (1)原型链上引用值共享
    (2)子类实例化的时候无法给父类传参。

    1. function Super(){
    2. this.name = 'SuperInstance'
    3. this.arr = [1, 2, 3]
    4. }
    5. let superInstance = new Super()
    6. function Father(){
    7. this.name = 'FatherInstance'
    8. }
    9. //将祖辈原型实例作为父类原型对象
    10. Father.prototype = superInstance
    11. let son1 = new Father(),
    12. son2 = new Father();
    13. son1.arr.push(6);
    14. console.log(son2.arr) // => [1,2,3,6]
    15. // son的原型链 son.__proto__ => Father.prototype(superInstance) => Super.prototype

    (2)盗用构造函数(constructor stealing)也被叫作经典继承
    避免原型链引用值共享的方法:借用构造函数,子类实例可以给父类构造函数传参,原理是给每个实例对象添加自己的属性值。缺点:无法是子类实例继承父类构造函数的原型对象。

    1. function Super(){
    2. this.name = 'SuperInstance'
    3. }
    4. function Father(){
    5. this.name = 'FatherInstance'
    6. Super.call(this)
    7. }
    8. let son = new Father()

    但是借用父类构造函数,没有让子类实例继承父类的原型对象。
    所以还需造出父类实例,指为子类构造函数的原型对象
    (3)组合继承(伪经典继承):

    1. function Super(name){
    2. this.name = name
    3. }
    4. let superInstance = new Super()
    5. Father.prototyper = superInstance
    6. function Father (opt){
    7. Super.call(this)
    8. this.habbit = opt.habbit
    9. }
    10. //这样解决了引用值共享的问题,也让子类实例继承了父类原型对象。
    11. //但是,这样调用了两次父类构造函数

    (4)寄生组合继承
    组合继承解决了原型引用值共享的问题,并且让子类实例继承父类原型上的属性与方法。但是有效率问题,父类在创建子类构造函数原型对象时,和子类构造函数时一共调用了两次。可以用 Object.create()来优化

    Father.prototype = Object.create(Super.prototype) // =>创造一个实例,并指定继承的对象。

    1. function Super(c){
    2. this.name = opt.name
    3. }
    4. function Son function(){
    5. Super.call(this)
    6. }
    7. Son.prototype = Object.create(Super.prototype)
    8. let son = new Son()
    9. //Object.create的es6兼用方式
    10. function correctProto(proto){
    11. if(Object.create){
    12. return Object.create(proto)
    13. }else{
    14. function Buffer(){}
    15. Buffer.prototype = proto
    16. return new Buffer()
    17. }
    18. }
    19. Fater.prototype = correctProto(Super.prototype)

    (5)圣杯模式

    1. function Buffer(){}
    2. Buffer.prototype = proto
    3. let buffer = new Buffer()
    4. Son.prototype = buffer
    5. Son.prototype.constructor = Son
    6. Son.superClass = Super
    7. //创建一个继承自父类的干净对象,指定为子类构造函数的prototype。
    8. //然后把子类构造函数的constructor矫正,并记录继承的超类。

    (6)es6 class继承
    同是解决了引用值共享问题,实现了子类实例对父类方法的继承

    1. class Super{
    2. constructor(){
    3. this.a = [1,2,3]
    4. }
    5. superSay(){
    6. console.log(this.a)
    7. }
    8. }
    9. class Sub extends Super{
    10. constructor(name){
    11. super()
    12. this.name = name
    13. }
    14. subSay(){
    15. console.log(this.name)
    16. }
    17. }
    18. let sub1 = new Sub('sub1'),
    19. sub2 = new Sub('sub2');
    20. sub1.a.push('sub1')
    21. sub1.subSay()
    22. sub2.subSay()
    23. console.log(sub1,sub2)

    (7)其他继承方式:拷贝继承,用的很少
    (8)class的一些用法
    1、可以直接在class内部添加实例自身属性

    1. class Super{
    2. a = [1,2,3,4,5]
    3. }
    4. let sub = new Super()

    2、子类构造函数继承父类构造函数时,constructor中使用this之前,需要调用super方法
    3、static静态方法,构造函数自身的方法(Object.create、Array.from、Array.of)。如果不加static关键字的话,就变成了构造函数原型对象上的方法了。

    1. class Super{
    2. static say(){
    3. console.log('SuperSay')
    4. }
    5. }
    6. 相当于
    7. Super.say = function(){console.log('SuperSay')}