Lawguancong / Daily-Charging-Learning

0 stars 0 forks source link

原型 原型链 继承 #34

Open Lawguancong opened 3 years ago

Lawguancong commented 3 years ago

image

原型 prototype

显式原型 只有函数才拥有该属性,除了bind函数创建的函数

把所有的对象共用的属性全部放在堆内存的一个对象中(共用属性组成的对象),然后让每一个对象的 proto存储这个(共用属性组成的对象)的地址。而这个共用属性就是原型。原型出现的目的就是 为了减少不必要的内存消耗。

原型的好处

  1. 通过原型链继承的方式,原先存在父类型的实例中的所有属性和方法,现在也能存在于子类型的原型中了;
  2. 在通过原型链实现继承时,原型实际上会成为另一个类型的实例。所以父类的实例属性实际上会成为子类的原型属性。
  3. JavaScript 采用原型编程,所有的对象都能共享原型上的方法,通过构造函数生成的实例所拥有的方法都指向一个函数的索引,这样可以节省内存,如果不使用原型法就会造成每创建一个对象就会产生一个内存地址

原型链 proto

隐式原型 而原型链就是对象通过proto向当前实例所属类的原型上查找属性或方法的机制,如果找到Object 的原型上还是没有找到想要的属性或者是方法则查找结束,最终会返回null。

constructor 构造函数

类组件的 constructor干了些啥

类组件执行构造函数过程中会在实例上绑定 props 和 context ,初始化置空 refs 属性,原型链上绑定setState、forceUpdate 方法。对于 updater,React 在实例化类组件之后会单独绑定 update 对象。

如果没有在 constructor 的 super 函数中传递 props,那么接下来 constructor 执行上下文中就获取不到 props ,这是为什么呢? 答案很简单,刚才的 Component 源码已经说得明明白白了,绑定 props 是在父类 Component 构造函数中,执行 super 等于执行 Component 函数,此时 props 没有作为第一个参数传给 super() ,在 Component 中就会找不到 props 参数,从而变成 undefined ,在接下来 constructor 代码中打印 props 为 undefined 。

image

获取原型的方法

  1. p.proto
  2. P.constructor.prototype
  3. P.getPrototypeOf(p)

注意:hasOwnProperty 执行直接对象查找时,它始终不会查找原型

Javascript如何实现继承?

• 构造继承 • 原型继承 • 实例继承 • 拷贝继承 • 原型 prototype 机制或 apply 和 call 方法去实现较简单,建议使用构造函数与原型混合方式

构造函数原则

• 公共属性定义到构造函数里面 • 公共方法我们放到原型对象身上。P.prototype.method

new 操作符

构造函数 和 类 区别

构造函数特点:

  1. 构造函数有原型对象prototype。
  2. 构造函数原型对象prototype里面有constructor,指向构造函数本身。
  3. 构造函数可以通过原型对象添加方法。
  4. 构造函数创建的实例对象有proto原型,指向构造函数的原型对象。

    类:

  5. class本质还是function
  6. 类的所有方法都定义在类的prototype属性上
  7. 类创建的实例,里面也有proto指向类的prototype原型对象
  8. 新的class写法,只是让对象原型的写法更加清晰,更像面向对象编程的语法而已。
  9. ES6的类其实就是语法糖。
  10. 类必须使用new调用,否则会报错。这是它跟普通构造函数的一个主要区别,后者不用new也可以执行。
  11. 类的所有实例共享一个原型对象。
  12. 类的内部,默认就是严格模式,所以不需要使用use strict指定运行模式。
  13. 继承主要是使用extends和super关键字,本质类似于ES5的寄生组合继承:

继承

https://juejin.cn/post/6844904098941108232

ES5的继承,实质是先创造子类的实例对象this,然后再将父类的方法添加到this上面( Parent.apply(this) )。

ES6的继承机制完全不同,实质是先将父类实例对象的属性和方法,加到this上面(所以必须先调用super方法),然后再用子类的构造函数修改this。

ES5继承

    function Father(name) {
        this.name = name;
    }
    Father.prototype.dance = function () {
        console.log('I am dancing');
    };
    function Son(name, age) {
        Father.call(this, name);
        this.age = age;
    }
    Son.prototype = new Father(); // Object.create(Father.prototype) -> 比较好
    Son.prototype.sing = function () {
        console.log('I am singing');
    };
    let son = new Son('小红', 100);
    console.log(Father.prototype) //{dance: ƒ, constructor: ƒ}

image

寄生组合继承

//构造继承
function Child () {
    Parent.call(this, ...arguments)
}
//原型式继承
Child. prototype = object. create(Parent. prototype)
//修正constructor
Child. prototype. constructor = Child

ES6继承

class Father {
        constructor(name){
            this.name = name;
        }
        dance(){
            return '我在跳舞';
        }
    }
    class Son extends Father{
        constructor(name,score){
            super(name);
            this.score = score;
        }
        sing(){
            return this.name +','+this.dance();
        }
    }
    let obj = new Son('小红',100);

ES5的继承和ES6继承的区别

https://blog.csdn.net/jyr28733669lq/article/details/107940365

总结

  1. Object 是所有对象的爸爸,所有对象都可以通过 proto 找到它
  2. Function 是所有函数的爸爸,所有函数都可以通过 proto 找到它
  3. Function.prototype 和 Object.prototype 是两个特殊的对象,他们由引擎来创建
  4. 除了以上两个特殊对象,其他对象都是通过构造器 new 出来的
  5. 函数的 prototype 是一个对象,也就是原型
  6. 对象的 proto 指向原型, proto 将对象和原型连接起来组成了原型链
  7. 类没有变量提升

参考链接 https://github.com/mqyqingfeng/Blog/issues/2 https://juejin.cn/post/6844903575974313992 https://juejin.cn/post/6844904093828251662 https://www.cnblogs.com/lijinwen/p/5740706.html https://www.jianshu.com/p/db7c4e9a80a3