• 什么是js的原型以及原型链


    1.为什么要有原型和原型链

    JavaScript中其实并没有类的概念。从es6通过class关键字才引入了Class这个概念,但是ES6的class可以看作是一个语法糖,它的绝大部分功能,ES5都可以做到。。

    es6之前,实现生成实例对象的传统方法是通过构造函数。将实例对象与构造函数连接起来的就是原型原型链

    2.什么是原型?

    JavaScript中有两个原型:

    • __proto__:隐式原型
    • prototype:显式原型

    但是,这两种原型并不存在于JavaScript的所有对象中。那么在哪里可以体现出这两个原型呢?先看代码:

    	var a = []
    	var o = {}
    	function fn(){}
    
    	console.log(a.__proto__); // 非undefined
    	console.log(a.prototype); // undefined
    
    	console.log(o.__proto__); // 非undefined
    	console.log(o.prototype); // undefined
    	
    	console.log(fn.__proto__); // 非undefined
    	console.log(fn.prototype); // {constructor: f}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    结果如下:

    image

    可以看到:

    • 数组、对象、函数三个引用类型都有__proto__属性(隐式原型)

    • 只有函数除了__proto__之外还有一个prototype属性(显式原型)

    所有的函数默认都会拥有一个名为prototype的公有且不可枚举(enumerable)的属性,它会指向另一个空的对象。

    下面用构造函数来说明:

    image

    可以看到,a是通过构造函数创建的一个新对象,通过a.__proto__可以看到foo.prototype的内容。其实a.__proto__就是foo.prototype的引用,它俩指向的都是同一个地址(a.__proto__ === foo.prototype // true)。

    小结:

    1. 实例对象a只有隐式原型(__proto__);构造函数既有隐式原型(__proto__)也有显式原型(prototype)。

    2. __proto__prototype都是对象,是对象说明它们也都有.__proto__属性:

      a.__proto__.__proto__
      foo.prototype.__proto__
      
      • 1
      • 2
    3. 实例对象的隐式原型指向了构造函数的显式原型:a.__proto__ === foo.prototype

    4. 访问实例对象的某个属性,如果实例对象上没有,就通过实例对象.__proto__找到构造函数的prototype继续找。

      function foo() { }
      
      foo.prototype.name = "张三"
      
      var a = new foo()
      
      a.name // 张三
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7

    3. 原型链

    什么是原型弄懂了,原型链是什么大致也就明了了。先看如下代码的输出:

    	function foo() { }
    
    	foo.prototype.name = "张三"
    
    	var a = new foo()
    
    	console.log('1------', a.__proto__);
    	console.log('2------', a.__proto__.__proto__);
    	console.log('3------', a.__proto__.__proto__.__proto__);
    
    	console.log(a.name); // 张三
    	console.log(a.toString()); // [object Object]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    结果如下:

    可以看到:

    • a.__proto__:实例对象a的__proto__,指向的是构造函数foo的prototype

    • a.__proto__.__proto__:实例对象a的__proto____proto__指向的是Object()构造函数对象。

    • a.__proto__.__proto__.__proto__Object对象的__proto__最终指向了null。

    这样一级一级的__proto__相连接起来的链式结构就是**原型链*。*

    而在最后两行的console中:

    • a.name输出的是"张三",但是实例对象a并没有name这个属性,它是js引擎通过原型链查找到a.__proto__(即foo.prototype)找到的。

    • a.toString()这个方法在foo构造函数以及a实例对象中均没有,它存在于原型链中的a.__proto__.__proto__找到了Object()构造函数对象的prototype(显式原型)上。

    因此,在查找一个对象的属性时,JS引擎就是在这样的原型链上一级一级的向上查找的,如果找到顶层的Object对象的__proto__还是没有找到某个属性,就会抛出错误。

    4.关于constructor

    可以看到,不管是实例对象a还是构造函数foo,又或者是Object()构造函数。它们的__proto__(隐式原型)上都有一个constructor属性。

    这个constructor属性是所有函数的prototype属性自带的一个属性,它不可枚举(enumerable = false)且通过new foo()创建的对象也有一个constructor属性,指向了这个对象的构造函数。所以,实例对象、构造函数的原型、构造函数三者的关系是这样的:

    a.constructor === foo.prototype === foo
    
    • 1

    其实,构造函数的原型上的constructor就是当前这个构造函数的引用:

    	function foo() { }
    
    	console.log(foo.prototype.constructor === foo); // true
    
    • 1
    • 2
    • 3
  • 相关阅读:
    java计算机毕业设计微服务毕业论文管理系统源码+系统+数据库+lw文档
    ASPICE标准快速掌握「2.2. 过程参考模型(Process Reference Model,PRM)」
    前端uniapp块样式写法
    浏览量5.54亿,“平替大军”击退“钱包刺客”?丨小红书消费趋势分析
    Linux: signal:需要注意的一个问题:SIGRTMIN 32 vs 34
    体验昇腾Ascend C 编程语言极简易用的算子开发
    JavaScript闭包
    java八股文(mysql篇)
    [附源码]计算机毕业设计JAVA科院垃圾分类系统
    吃透Chisel语言.34.Chisel进阶之硬件生成器(三)——利用面向对象编程特性:以Ticker为例
  • 原文地址:https://blog.csdn.net/vet_then_what/article/details/125515325