原型 原型链 继承

发布于 2023-10-26 03:55:26 字数 5806 浏览 28 评论 0

原型 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 。

获取原型的方法

  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__原型,指向构造函数的原型对象。

类:

  1. class 本质还是 function
  2. 类的所有方法都定义在类的 prototype 属性上
  3. 类创建的实例,里面也有__proto__指向类的 prototype 原型对象
  4. 新的 class 写法,只是让对象原型的写法更加清晰,更像面向对象编程的语法而已。
  5. ES6 的类其实就是语法糖。
  6. 类必须使用 new 调用,否则会报错。这是它跟普通构造函数的一个主要区别,后者不用 new 也可以执行。
  7. 类的所有实例共享一个原型对象。
  8. 类的内部,默认就是严格模式,所以不需要使用 use strict 指定运行模式。
  9. 继承主要是使用 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: ƒ}

寄生组合继承

//构造继承
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. 类没有变量提升

参考链接
mqyqingfeng/Blog#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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

0 文章
0 评论
24 人气
更多

推荐作者

13886483628

文章 0 评论 0

流年已逝

文章 0 评论 0

℡寂寞咖啡

文章 0 评论 0

笑看君怀她人

文章 0 评论 0

wkeithbarry

文章 0 评论 0

素手挽清风

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文