JavaScript学习系列之原型、原型链

简介: JavaScript学习系列之原型、原型链

原型是Javascript中的继承的基础,JavaScript的继承主要依靠原型链来实现的。

1.原型

在JavaScript中,我们创建一个函数A(就是声明一个函数), 就会为该函数创建一个prototype属性。而且也会在内存中创建一个对象B,A函数的属性 prototype 指向这个对象B( 即:prototype的属性的值是这个对象 )。这个对象B就是函数A的原型对象,简称函数的原型。这个原型对象B 默认会有一个属性 constructor, constructor属性指向函数A ( 意思就是说:constructor属性的值是函数A )。

       /*
            声明一个函数,则这个函数默认会有一个属性叫 prototype 。而且浏览器会自动按照一定的规则
            创建一个对象,这个对象就是这个函数的原型对象,prototype属性指向这个原型对象。这个原型对象
            有一个属性叫constructor 执行了这个函数
    
          注意:原型对象默认只有属性:constructor。其他都是从Object继承而来,暂且不用考虑。
       */
        function Person () {
            
        }    

下面的图描述了声明一个函数之后发生的事情:

当把一个函数作为构造函数 (理论上任何函数都可以作为构造函数) 使用new创建对象的时候,那么这个对象就会存在一个默认的不可见的属性,来指向了构造函数的原型对象。 这个不可见的属性我们一般用 [[prototype]] 来表示,只是这个属性没有办法直接访问到。

 function Person () {  }    
        /*
            利用构造函数创建一个对象,则这个对象会自动添加一个不可见的属性 [[prototype]], 而且这个属性
            指向了构造函数的原型对象。
        */
          var p1 = new Person();

观察下面的示意图:

1.1 小结

__proto__ 是对象实例才有的属性,指向对象的原型。
prototype 是构造函数才有的属性,该属性指向了一个对象,这个对象正是调用该构造函数而创建的实例的原型
实例的__proto__属性 和 构造函数的 prototype 都指向该对象原型

这几句话能解释一切关于原型方面的问题:

当 new 一个函数的时候会创建一个对象,『函数.prototype』 等于 『被创建对象.__proto__』
一切函数都是由 Function 这个函数创建的,所以『Function.prototype === 被创建的函数.__proto__』
一切函数的原型对象都是由 Object 这个函数创建的,所以『Object.prototype === 一切函数.prototype.__proto__』

2.原型链

原型链基本思路:利用原型让一个引用类型继承另一个引用类型的属性和方法。

每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数想指针(constructor),而实例对象都包含一个指向原型对象的内部指针(__proto__)。
如果让原型对象等于另一个类型的实例,此时的原型对象将包含一个指向另一个原型的指针(__proto__),另一个原型也包含着一个指向另一个构造函数的指针(constructor)。
假如另一个原型又是另一个类型的实例……这就构成了实例与原型的链条。

原型链基本思路(图解):

'__proto__'是对象的属性、'prototype'是函数的属性
null是对象原型链的终点,其值既有(是一个对象)又无(不引用任何对象),
代表着对象本源的一种混沌、虚无的状态,正与老子《道德经》中的“道”,有着同等的意义
(心中一万只艹尼玛奔腾而过,还是写java爽啊)。

在JS中,undefined是全局对象的一个属性,它的初始值就是原始数据类型undefined,并且无法被配置,也无法被改变。
undefined从字面意思上理解为“未定义”,即表示一个变量没有定义其值。

而null是一个JS字面量,表示空值,即没有对象。
与undefined相比,null被认为是“期望一个对象,但是不引用任何对象的值”,而undefined是纯粹的“没有值”。

从一张图看懂原型对象、构造函数、实例对象之间的关系

prototype:构造函数中的属性,指向该构造函数的原型对象。

constructor:原型对象中的属性,指向该原型对象的构造函数

_proto_:实例中的属性,指向new这个实例的构造函数的原型对象

3.利用原型实现继承

3.1 利用 call 借用构造函数继承

优点:实现了继承属性,但值都不相同

缺点: 无法继承父级类别中原型上的方法

function Person(name,age,sex,weight){
    this.name=name;
    this.age=age;
    this.sex=sex;
    this.weight=weight;
}
Person.prototype.sayHi=function(){
    console.log("您好")
}
 
function Student(name,age,sex,weight,score){
    //将当前实例对象传入Person 借过来使用一次来达到继承效果
    Person.call(this,name,age,sex,weight);
    this.score=score;
}
 
var stu1=new Student("小明",10,"男","10kg","100")

3.2 prototype 实现继承

利用prototype,将Student 的prototype 指向 Person 来达到继承效果,

优点:继承了父级原型上的方法

缺点: 实例化多个Student 都必须共用相同的name 和 age

// 此处
Student.prototype.constructor=Student
function Person(name,age){
        this.name=name;
        this.age=age;
     }
 
     Person.prototype.eat=function(){
        console.log("Person 吃饭")
     }
 
     function Student(num,score){
        this.num=num
        this.score=score
     }
     //继承
    Student.prototype=new Person("小红",10)
    Student.prototype.constructor=Student
 
    var stu =new Student(2016002288,80)
 
    stu.eat()//Person 吃饭

3.3 组合继承

组合继承其实就是结合了上述的两种方法来实现继承,拥有两种方法的优点

function Person(name,age,sex){
        this.name=name;
        this.age=age;
        this.sex=sex;
     }
     Person.prototype.sayHi=function(){
        console.log("你好")
     }
 
     function  Student(name,age,sex,score){
        //借用构造函数
        Person.call(this,name,age,sex)
        this.score=score
     }
 
     // 改变了原型指向
     Student.prototype=new Person();//不传值
     Student.prototype.eat=function(){
        console.log("吃东西");
     }
 
     var stu=new Student("小黑",20,"男","100分")
     console.log(stu.name,stu.age,stu.sex,stu.score);
     stu.sayHi()//你好
     stu.eat()//吃东西

3.4 拷贝继承

类似于复制,把一个对象中的属性和方法直接复制到另一个对象中

function Person(){
    }
 
    Person.prototype.name="小红"
    Person.prototype.age=18
 
    function Student(){
    }
    
    var p=Person.prototype;
    var s=Student.prototype;
 
    for(key in p){
        s[key]=p[key]
    }
 
    console.dir(Student)

每次都要for in 好累 , 可以进行优化封装一下

function extend(Child,Parent) {
 
    var p = Parent.prototype;
    var c = Child.prototype;
 
    for (var i in p) {
      c[i] = p[i];
      }
        
        //这个属性直接指向父对象的prototype属性,可以直接调用父对象的方法,为了实现继承的完备性,纯属备用性质
    c.par = p;
 
  }

3.5 直接继承prototype

优点 : 效率比较高

缺点 : 因为相当于是个传址过程 所以修改Student的属性 Person 的也会被更改

    function Person(){};
 
    Person.prototype.name="小红";
    Person.prototype.age=18;
 
    function Student(){};
 
    Student.prototype=Person.prototype;
 
    console.dir(Student);
    console.dir(Person);
    Student.prototype.age=25;

3.6 利用空对象作中介实现继承

用这种方式修改 Student 的prototype 不会影响到 Person的prototype

function Person(){};
    Person.prototype.name="小红";
    Person.prototype.age=11;
 
    function Student(){};
    var F=function(){};
    F.prototype=Person.prototype;
 
    Student.prototype=new F();
    Student.prototype.constructor=Student;
 
    Student.prototype.age=25;
 
    console.dir(Person)
    console.dir(Student)

参考文献

https://www.cnblogs.com/wangfupeng1988/p/3977924.html

相关文章
|
4月前
|
前端开发 JavaScript
个人征信电子版无痕修改, 个人信用报告pdf修改,js+html+css即可实现【仅供学习用途】
本代码展示了一个信用知识学习系统的前端实现,包含评分计算、因素分析和建议生成功能。所有数据均为模拟生成
|
4月前
|
前端开发
个人征信PDF无痕修改软件,个人征信模板可编辑,个人征信报告p图神器【js+html+css仅供学习用途】
这是一款信用知识学习系统,旨在帮助用户了解征信基本概念、信用评分计算原理及信用行为影响。系统通过模拟数据生成信用报告,涵盖还款记录
|
5月前
|
JavaScript 数据可视化 前端开发
three.js简单实现一个3D三角函数学习理解
1.Three.js简介 Three.js是一个基于JavaScript编写的开源3D图形库,利用WebGL技术在网页上渲染3D图形。它提供了许多高级功能,如几何体、纹理、光照、阴影等,以便开发者能够快速地创建复杂且逼真的3D场景。同时,Three.js还具有很好的跨平台和跨浏览器兼容性,让用户无需安装任何插件就可以在现代浏览器上观看3D内容。
179 0
|
12月前
|
JavaScript 前端开发 开发者
理解JavaScript中的原型链:基础与实践
【10月更文挑战第8天】理解JavaScript中的原型链:基础与实践
|
7月前
|
数据采集 JavaScript 前端开发
一站搞定原型链:深入理解JavaScript的继承机制
综上所述,可以得出: 1. 原型链是对象通过原型实现属性和方法继承的一种机制。 2. 每个对象都有一个 __proto__ 属性,指向它的原型对象。 3. 每个函数(包括构造函数)都有一个 prototype 属性,指向一个对象,这个对象的属性和方法可以被实例共享。 4. 构造函数创建对象时,新对象的 __proto__ 属性指向构造函数的 prototype 对象。 5. 继承可以通过设置原型对象实现,也可以使用 ES6 的 class 语法糖。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一
|
11月前
|
JavaScript 前端开发
JavaScript 原型链的实现原理是什么?
JavaScript 原型链的实现原理是通过构造函数的`prototype`属性、对象的`__proto__`属性以及属性查找机制等相互配合,构建了一个从对象到`Object.prototype`的链式结构,实现了对象之间的继承、属性共享和动态扩展等功能,为 JavaScript 的面向对象编程提供了强大的支持。
|
11月前
|
JavaScript 前端开发
原型链在 JavaScript 中的作用是什么?
原型链是 JavaScript 中实现面向对象编程的重要机制之一,它为代码的组织、复用、扩展和多态性提供了强大的支持,使得 JavaScript 能够以简洁而灵活的方式构建复杂的应用程序。深入理解和熟练运用原型链,对于提升 JavaScript 编程能力和开发高质量的应用具有重要意义。
|
11月前
|
JavaScript 前端开发
JavaScript中的原型 保姆级文章一文搞懂
本文详细解析了JavaScript中的原型概念,从构造函数、原型对象、`__proto__`属性、`constructor`属性到原型链,层层递进地解释了JavaScript如何通过原型实现继承机制。适合初学者深入理解JS面向对象编程的核心原理。
168 1
JavaScript中的原型 保姆级文章一文搞懂
|
11月前
|
Web App开发 JavaScript 前端开发
如何学习JavaScript?
如何学习JavaScript?
201 5