JS中的原型链详解

js虽然不是面向对象类型的语言,但这不并不意味着js就不能够实现oop的特性。 我相信大家在使用js的时候,一定用过object的原型方法,比如call,apply,hasownproperty等等方法,可是这些方法是从哪里来的呢?如果js无法实现继承的话,这些方法的使用就无从谈起了。这里我们就来谈谈在js中实现继承的方法,原型链。

_proto_和prototype

首先我们要了解什么是普通对象,什么是函数对象。

普通对象

var a = {}

var a = new Object();

var a = new f1();//与上一个创建对象的方式相同

函数对象

var a = function(){};

var a = new Function(){};

f1()

_proto_是每个普通对象都拥有的属性,用来指向构造函数的prototype,也就是构造函数的原型对象。而构造函数的原型对象一般来说也是一个普通对象(在构造函数为Function的时候,它就变成了一个函数对象),所以它也有_proto_属性。而它的_proto_则指向它的构造函数的原型对象,也就是Object.prototype。最后的Object.prototype._proto_指向null,到了原型链的顶端。
prototype是函数对象都拥有的属性,它在对象创建的时候被指定给新的对象实例。当然也可以动态修改。

   function Person(){};   var p = new Person();//创建一个普通对象   //创建过程实际为   var p={};   p._proto_=Person.prototype;   Person.apply(p,arguments);//或者是call...   //执行构造函数,并返回创建的对象。

登录后复制

对上面代码的补充说明

正常来讲构造函数中是不用写return语句的,因为它会默认返回新创建的对象。但是,如果在构造函数中写了return语句,如果return的是一个对象,那么函数就会覆盖掉新创建的对象,而返回此对象;如果return的是基本类型如字符串、数字、布尔值等,那么函数会忽略掉return语句,还是返回新创建的对象。

而构造函数的原型对象的默认值为:

  Person.prototype={    constructor://指向构造函数本身    _proto_://指向构造函数Person的原型对象的构造函数的原型对象,这里是指Object.prototype  }  //这里有一个特殊情况——当构造函数为Function的时候  Function.prototype._proto_===Object.prototype   //我们知道Function.prototype是一个函数对象,它的_proto_应该指向它的构造函数的原型,也就是Function.prototype。  //可是这样下去就没完没了了,毕竟一条链总是有顶端的。这里约定Function.prototype._proto_===Object.prototype;  //这时,Object.prototype._proto_===null;完美结束原型链。

登录后复制

我们可以不断修改构造函数的原型对象的指向,这样最终就可以形成一条链。而上面提到的一条链就是JS中的默认原型链。

谈谈代码实现

下面我们看看代码:

  function Parent(name){        this.name=name||"parent";    }    function Son(name){        this.name=name||"son";        this.property="initial Son name";    }    function Grandson(name){        this.name=name||"grandson";        this.ggs="initial Grandson name";    }    Son.prototype = new Parent("原型中的Parent");    Grandson.prototype = new Son("原型中的Son");    let grandson = new Grandson("孙子");    console.log(grandson instanceof Son);//true    console.log(grandson instanceof Grandson);//true    console.log(grandson instanceof Parent);//true

登录后复制

这里写图片描述
很显然,最后都输出true。但是我们改动一点代码:

    Grandson.prototype = new Son("原型中的Son");    Son.prototype = new Parent("原型中的Parent");//其实上一步已经实例化了一个Son的对象给Grandson.prototype    //这个时候Son的实例的_proto_已经确定指向那个时候的构造函数.prototype了(默认原型对象)    let grandson = new Grandson("孙子");    console.log(grandson instanceof Son);//false    console.log(grandson instanceof Grandson);//true    console.log(grandson instanceof Parent);//false

登录后复制

这里写图片描述
为什么结果会变呢?原因也很简单。我们之前有提到对象的创建的创建过程:对象在实例化的时候就已经给对象的_proto_赋了构造函数的prototype了。也就是说上面代码中第一行已经确定了Grandson.prototype._proto_的值了,即使在第二行修改了Son.prototype也是无法修改Grandson.prototype._proto_的值。

Conclusion:JS中原型链的关系是由_proto_维持的,而不是prototype。

小测试

var animal = function(){}; var dog = function(){}; animal.price = 2000; dog.prototype = animal; var tidy = new dog(); console.log(dog.price)  console.log(tidy.price)

登录后复制

答案是输出什么呢?是undefined和2000,我们分析一下:
首先我们清楚animal和dog都是函数对象,在第四行修改了dog的原型对象为animal。那么我们接着往下看,console.log(dog.price) 这一句首先会寻找dog的price,没有。然后去原型链上寻找。怎么找的呢?我们之前提到是通过_proto_去到它构造函数的原型对象上,这里因为dog是函数对象,那么它的构造函数的原型对象就是Function.prototype,这是一个empty function。于是返回undefined,没有找到price这个属性。
那么console.log(tidy.price) 呢?
tidy是一个普通对象,首先也是寻找它本身的属性price,也没有。通过_proto_去到它构造函数的原型对象上,也就是dog.prototype。因为tidy实例化在dog.prototype = animal; 之后,所以tidy._proto_的指向已经指向了修改后的dog.prototype。也就是指向了animal,也就是能够找到price这个属性了,所以输出2000。

原型对象上的所有属性和方法都可以看成是Java中父类的public(protected)属性和方法,在这些方法内部使用this即可访问构造函数中的属性和方法。至于为什么,这又得提到JS中this的绑定问题了….总而言之,谁调用的函数,this就指向谁。箭头函数除外…

  相关推荐:

详解JS原型和原型链(一)

详解JS原型和原型链(二)

详解JS原型和原型链(三)

以上就是JS中的原型链详解的详细内容,更多请关注【创想鸟】其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2779926.html

(0)
上一篇 2025年3月8日 15:53:22
下一篇 2025年3月8日 15:53:31

AD推荐 黄金广告位招租... 更多推荐

相关推荐

  • js数据类型详解

    es5简单数据类型(也称为基本数据类型):undefined、null、boolean、number和string。还有1 种复杂数据类型—object,object 本质上是由一组无序的名值对组成的。ecmascript不支持任何创建自定…

    编程技术 2025年3月8日
    200
  • vue、js中的换行详解

    在页面中经常会遇到自定义文本,如果文本过长就需要换行,在HTML中可以通过标签换行,也可以通过转椅字符换行,以下是在javascript中和vue中的换行,希望能帮助到大家。 javascript中的换行 var reg=new RegEx…

    编程技术 2025年3月8日
    200
  • js的BOM简介

    BOM(Browser Object Model),浏览器对象模型,是将我们使用的浏览器抽象成对象模型,例如我们打开一个浏览器,会呈现出以下页面,通过js提供浏览器对象模型对象我们可以模拟浏览器功能。例如,在浏览器地址栏输入地址,敲击回车这…

    编程技术 2025年3月8日
    200
  • js和jquery知识点汇总

    本文主要和大家分享js和jquery知识点汇总,希望能帮助到大家。 return 语句:   一般三种用法: 1.return true======》返回当前函数的正确结果。                          2.retur…

    编程技术 2025年3月8日
    200
  • 原生js实现轮播图

    本文主要和大家分享原生js实现轮播图,主要以代码形式,希望能帮助到大家。 nbsp;html>     /*重置样式*/ *{margin: 0;padding: 0; list-style: none;} /*wrap的轮播图和切换…

    编程技术 2025年3月8日
    200
  • Node.js的非对称加密详解

    这次给大家带来Node.js的非对称加密详解,使用Node.js的非对称加密注意事项有哪些,下面就是实战案例,一起来看一下。 前言 刚回答了SegmentFault上一个兄弟提的问题《非对称解密出错》。这个属于Node.js在安全上的应用,…

    编程技术 2025年3月8日
    200
  • javascript的代码优化详解

    这次给大家带来javascript的代码优化详解,javascript代码优化的注意事项有哪些,下面就是实战案例,一起来看一下。 本文将详细介绍JS编程风格的几个要点 松耦合 当修改一个组件而不需要更改其他组件时,就做到了松耦合 1、将JS…

    编程技术 2025年3月8日
    200
  • vue.js实现单次弹框

    这次给大家带来vue.js实现单次弹框,vue.js实现单次弹框的注意事项有哪些,下面就是实战案例,一起来看一下。 核心代码是 getCookie()部分,控制弹框的显示隐藏则在 created()中。 Lorem ipsum dolor …

    编程技术 2025年3月8日
    200
  • JS中Object对象的原型的使用方法

    这次给大家带来JS中Object对象的原型的使用方法,使用JS中Object对象原型的注意事项有哪些,下面就是实战案例,一起来看一下。 对象概念 在 javascript 中, 一切引用类型均为对象。 如 function Foo () {…

    2025年3月8日
    200
  • js字符串如何实现截取函数slice()、substring()、substr()

    在js中字符截取函数有常用的三个slice()、substring()、substr()了,下面我来给大家介绍slice()、substring()、substr()函数在字符截取时的一些用法与区别吧。 取字符串的三个函数:slice(st…

    编程技术 2025年3月8日
    200

发表回复

登录后才能评论