当前位置: 首页 > news >正文

JS原型和原型链的理解

原型链图,图中Parent是构造函数,p1是通过Parent实例化出来的一个对象

在这里插入图片描述

前置知识

  1. js中对象和函数的关系,函数其实是对象的一种

  2. 函数、构造函数的区别,任何函数都可以作为构造函数,但是并不能将任意函数叫做构造函数,只有当一个函数通过new关键字调用的时候才可以成为构造函数

    var Parent = function(){}
    var p1 = new Parent();
    
  3. 三个属性__proto__、prototype、 constructor

    • proto、 constructor属性是对象所独有的
    • prototype属性是函数独有的
    • js中函数也是对象的一种,那么函数同样也有属性__proto__、 constructor

prototype属性

在这里插入图片描述

  • prototype 它是函数独有的属性,从图中可以看到它从一个函数指向另一个对象,代表这个对象是这个函数的原型对象,这个对象也是当前函数所创建的实例的原型对象。

  • prototype设计之初就是为了实现继承,让由特定函数创建的所有实例共享属性和方法,也可以说是让某一个构造函数实例化的所有对象可以找到公共的方法和属性。有了prototype我们不需要为每一个实例创建重复的属性方法,而是将属性方法创建在构造函数的原型对象上(prototype)。那些不需要共享的才创建在构造函数中。

  • 当我们想为通过Parent实例化的所有实例添加一个共享的属性时,
    Parent.prototype.name = "我是原型属性,所有实例都可以读取到我";

  • 这就是原型属性,当然你也可以添加原型方法。那问题来了,p1怎么知道他的原型对象上有这个方法呢,往下看

proto属性

在这里插入图片描述

  • __proto__属性是对象(包括函数)独有的。从图中可以看到__proto__属性是从一个对象指向另一个对象,即从一个对象指向该对象的原型对象(也可以理解为父对象)。显然它的含义就是告诉我们一个对象的原型对象是谁。

  • 上面说到,Parent.prototype上添加的属性和方法叫做原型属性和原型方法,该构造函数的实例都可以访问调用。那这个构造函数的原型对象上的属性和方法,怎么能和构造函数的实例联系在一起呢,就是通过__proto__属性。每个对象都有__proto__属性,该属性指向的就是该对象的原型对象
    p1.__proto__ === Parent.prototype; // true

  • __proto__通常称为隐式原型,prototype通常称为显式原型,那我们可以说一个对象的隐式原型指向了该对象的构造函数的显式原型。那么我们在显式原型上定义的属性方法,通过隐式原型传递给了构造函数的实例。这样一来实例就能很容易的访问到构造函数原型上的方法和属性了。
    我们之前也说过__proto__属性是对象(包括函数)独有的,那么Parent.prototype也是对象,那它有隐式原型么?又指向谁?
    Parent.prototype.__proto__ === Object.prototype; //true

  • 可以看到,构造函数的原型对象上的隐式原型对象指向了Object的原型对象。那么Parent的原型对象就继承了Object的原型对象。由此我们可以验证一个结论,万物继承自Object.prototype。这也就是为什么我们可以实例化一个对象,并且可以调用该对象上没有的属性和方法了。如:
    //我们并没有在Parent中定义任何方法属性,但是我们可以调用 p1.toString();//hasOwnProperty 等等的一些方法

  • 我们可以调用很多我们没有定义的方法,这些方法是哪来的呢?现在引出原型链的概念,当我们调用p1.toString()的时候,先在p1对象本身寻找,没有找到则通过p1.__proto__找到了原型对象Parent.prototype,也没有找到,又通过Parent.prototype.__proto__找到了上一层原型对象Object.prototype。在这一层找到了toString方法。返回该方法供p1使用

  • 当然如果找到Object.prototype上也没找到,就在Object.prototype.__proto__中寻找,但是Object.prototype.proto === null所以就返回undefined。这就是为什么当访问对象中一个不存在的属性时,返回undefined了

constructor属性

在这里插入图片描述

  • constructor是对象才有的属性,从图中看到它是从一个对象指向一个函数的。指向的函数就是该对象的构造函数。每个对象都有构造函数,好比我们上面的代码p1就是一个对象,那p1的构造函数是谁呢?我们打印一下。
    console.log(p1.constructor); // ƒ Parent(){}
  • 通过输出结果看到,很显然是Parent函数。我们有说过函数也是对象,那Parent函数是不是也有构造函数呢?显然是有的。再次打印下
    console.log(Parent.constructor); // ƒ Function() { [native code] }
  • 通过输出看到Parent函数的构造函数是Function(),这点也不奇怪,因为我们每次定义函数其实都是调用了new Function(),下面两种效果是一样的
    var fn1 = new Function('msg','alert(msg)');
    function fn1(msg){alert(msg);
    }
    
  • 那么我们再回来看下,再次打印Function.constructor
    console.log(Function.constructor); // ƒ Function() { [native code] }
  • 可以看到Function函数的构造函数就是本身了,那我们也就可以说Function是所有函数的根构造函数。
  • 到这里我们已经对constructor属性有了一个初步的认识,它的作用是从一个对象指向一个函数,这个函数就是该对象的构造函数。通过栗子我们可以看到,p1的constructor属性指向了Parent,那么Parent就是p1的构造函数。同样Parent的constructor属性指向了Function,那么Function就是Parent的构造函数,然后又验证了Function就是根构造函数

参考:https://segmentfault.com/a/1190000021232132 # 巴斯光年

相关文章:

  • CSP - X - 2023 普及组初赛试题及解析
  • uniapp移动端 IOS系统下无法与webview通信
  • 鸿蒙Harmony应用开发—ArkTS声明式开发(基础手势:Span)
  • c语言文件操作(中)
  • Android 14.0 SystemUI设置系统导航栏默认为系统手势导航
  • Selenium库原代码WebDriver及WebElement方法属性总结
  • C语言入门学习 --- 7.结构体
  • 用pako.js压缩字符串,如何在后端用java解开?
  • Java项目:63 ssm网上花店设计+vue
  • 【Redis内存数据库】NoSQL的特点和应用场景
  • Java 构造方法
  • uniapp 兼容pc与手机的样式方法
  • 添可、希亦、追觅洗地机好不好用?实物终极PK测评分享!
  • 基于vue实现bilibili网页
  • 【Python多进程】的进阶讲解
  • exports和module.exports
  • jQuery(一)
  • MYSQL 的 IF 函数
  • MySQL常见的两种存储引擎:MyISAM与InnoDB的爱恨情仇
  • Python连接Oracle
  • Spring Cloud Feign的两种使用姿势
  • win10下安装mysql5.7
  • 阿里中间件开源组件:Sentinel 0.2.0正式发布
  • 关于Flux,Vuex,Redux的思考
  • 买一台 iPhone X,还是创建一家未来的独角兽?
  • 前端攻城师
  • 删除表内多余的重复数据
  • 算法之不定期更新(一)(2018-04-12)
  • zabbix3.2监控linux磁盘IO
  • 阿里云服务器如何修改远程端口?
  • # 计算机视觉入门
  • $.ajax,axios,fetch三种ajax请求的区别
  • (1)虚拟机的安装与使用,linux系统安装
  • (3)nginx 配置(nginx.conf)
  • (Redis使用系列) Springboot 实现Redis消息的订阅与分布 四
  • (二)Pytorch快速搭建神经网络模型实现气温预测回归(代码+详细注解)
  • (四)Linux Shell编程——输入输出重定向
  • (一)Spring Cloud 直击微服务作用、架构应用、hystrix降级
  • (转)visual stdio 书签功能介绍
  • .[hudsonL@cock.li].mkp勒索加密数据库完美恢复---惜分飞
  • .bat批处理(九):替换带有等号=的字符串的子串
  • .dat文件写入byte类型数组_用Python从Abaqus导出txt、dat数据
  • .NET Core使用NPOI导出复杂,美观的Excel详解
  • .net mvc部分视图
  • .NET Standard / dotnet-core / net472 —— .NET 究竟应该如何大小写?
  • .net web项目 调用webService
  • .NET 表达式计算:Expression Evaluator
  • .Net中wcf服务生成及调用
  • @vue/cli 3.x+引入jQuery
  • [ 攻防演练演示篇 ] 利用通达OA 文件上传漏洞上传webshell获取主机权限
  • [20171102]视图v$session中process字段含义
  • [8-27]正则表达式、扩展表达式以及相关实战
  • [BZOJ1060][ZJOI2007]时态同步 树形dp
  • [C++]运行时,如何确保一个对象是只读的
  • [CareerCup][Google Interview] 实现一个具有get_min的Queue