JavaScript的原型与原型链是如何构成一个完整的长尾词的?

2026-04-02 21:501阅读0评论SEO问题
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计2936个文字,预计阅读时间需要12分钟。

JavaScript的原型与原型链是如何构成一个完整的长尾词的?

目录- 解释原型与原型链- 构造函数- 原型对象- 访问原型- 设置原型- 测试原型- prototype、__proto__、constructor之间的关系- 原型链- 原型链的作用- 普通对象与函数对象- 经典原型链图- 总结- 原型详解

目录
  • 详解原型与原型链
    • 构造函数
    • 原型对象
      • 访问原型
      • 设置原型
      • 检测原型
    • prototype、__proto__、constructor之间的关系
      • 原型链
        • 原型链的作用
      • 普通对象与函数对象
        • 经典原型链图
        • 总结

          详解原型与原型链

          其实,刚开始学JavaScript时,就有学过原型与原型链的相关知识了,只是当时还没有养成写笔记的习惯,导致现在已经忘的七七八八了。

          这边文章真是花了很多心思,写了两天,看了很多篇篇博文,其中有小参考的,有解决一点疑惑的,但是最后只标注了一篇帮助最大的。

          构造函数

          实例的构造函数属性(constructor)指向其构造函数

          function Person(name) { this.name = name } const person = new Person('clz') console.log(person.constructor === Person) // true

          实例的构造函数并不是自身属性,而是从原型对象上继承的属性

          function Person(name) { this.name = name } const person = new Person('clz') console.log(person.constructor === Person) // true console.log(Person.prototype.constructor === Person) // true console.log(person.hasOwnProperty('constructor')) // false:constructor属性并不是实例自身的属性,而是继承来的

          原型对象

          • __proto__(隐式原型):每个对象(除了null)都具有的属性,该属性指向该对象的原型
          • prototype(显式原型):只有函数对象才有的属性,该属性指向函数的原型对象

          来看来看

          const arr = [1, 2, 3] const obj = { name: 'clz' } function add(a, b) { return a + b } console.log(arr) console.log(obj) console.log(add)

          红框框中的[[prototype]]__proto__意义相同,都是指对象的内部属性

          而所有函数都拥有prototype属性,所以可以通过f.prototype得到,那么自然也不需要通过[[prototype]]显示出来(毕竟prototype是显式原型,而__proto__是隐式原型,好吧,这是我猜的)

          箭头函数没有prototype属性

          访问原型

          通过实例对象访问原型对象有 3 种方法

          • obj.__proto__
          • obj.constructor.prototype
          • Object.getPrototypeOf(obj)

          function Person(name) { this.name = name } const person = new Person('clz') const proto1 = person.__proto__ const proto2 = person.constructor.prototype const proto3 = Object.getPrototypeOf(person) const proto = Person.prototype // 原型 console.log(proto1 === proto) // true: 第一种方法 console.log(proto2 === proto) // true: 第二种方法 console.log(proto3 === proto) // true: 第三种方法

          比较安全的做法是Object.getPrototypeOf(obj)

          以下部分会涉及一丢丢原型链的知识(如果没看懂,可以看下原型链再来看)

          • __proto__属性是私有属性,存在浏览器兼容性问题,缺乏非浏览器环境的支持
          • 如果obj的constructor属性被覆盖,那么obj.constructor.prototype将会失效。(因为obj自身是没有constructor属性的,是通过原型链去它的原型上获取constructor属性,所以覆盖该属性时,将不会再去原型链上查找)

          function Person(name) { this.name = name } function Temp(name) { this.name = name } const person = new Person('clz') person.constructor = Temp const proto = Person.prototype // 原型 console.log(person.__proto__ === proto) // true: 第一种方法 console.log(person.constructor.prototype === proto) // false: 第二种方法 console.log(Object.getPrototypeOf(person) === proto) // true: 第三种方法

          设置原型

          设置原型对象有 3 种方法

          • obj.__proto__=prototypeObj
          • Object.setPrototypeOf(obj, prototypeObj)
          • Object.create(prototypeObj)

          const proto = { // 原型对象 name: 'prototype' } // 第一种方法 const obj1 = {} obj1.__proto__ = proto // 设置原型 console.log(obj1.name) // prototype console.log(obj1.__proto__ === proto) // true // 第二种方法 const obj2 = {} Object.setPrototypeOf(obj2, proto) // 设置原型 console.log(obj2.name) // prototype console.log(obj2.__proto__ === proto) // true // 第三种方法 const obj3 = Object.create(proto) // 创建对象并设置原型 console.log(obj3.name) // prototype console.log(obj3.__proto__ === proto) // true

          检测原型

          使用obj1.isPrototypeOf(obj2)方法判断obj1是否为·obj2的原型

          const proto = { // 原型对象 name: 'prototype' } const proto1 = { name: 'prototype' } const obj = {} obj.__proto__ = proto // 设置原型 console.log(proto.isPrototypeOf(obj)) // true console.log(Object.prototype.isPrototypeOf(obj)) // true console.log(proto1.isPrototypeOf(obj)) // false

          prototype、__proto__、constructor之间的关系

          function Person(name) { this.name = name } const person = new Person('clz') console.log(person.__proto__ === Person.prototype) // true:因为创建person对象的构造函数是Person,所以person对象的隐式原型(__proto__)指向Person函数的原型(prototype) console.log(Person.prototype.constructor === Person) // true

          同一个构造函数创建的多个实例的原型是同一个

          function Person(name) { this.name = name } const person1 = new Person('clz') const person2 = new Person('clz') console.log(person1 === person2) // false: 不是同一个对象 console.log(person1.__proto__ === person2.__proto__) // true:同一个构造函数创建的实例对象的原型是同一个

          原型链

          由上面的知识可以知道,实例对象具有属性__proto__,会指向原型对象。而原型对象也是对象,所以也会有属性__proto__,也会继续指向它的原型对象。

          实例对象在查找属性时,如果查找不到,就会沿着__proto__去它的原型上查找,还找不到,则继续去原型的原型上查找,直到找到或到最顶层为止。这就是原型链的概念。

          对象本身的方法(第一层:把方法当成属性)

          function Person(name) { this.name = name this.listenMusic = function () { console.log('听音乐') } } const person = new Person('clz') console.log(person) console.log('实例对象本身是否有listenMusic方法', person.hasOwnProperty('listenMusic')) person.listenMusic()

          对象的原型上添加方法(第二层)

          function Person(name) { this.name = name } Person.prototype.listenMusic = function () { console.log('听音乐') } const person = new Person('clz') console.log(person) console.log('实例对象本身是否有listenMusic方法', person.hasOwnProperty('listenMusic')) person.listenMusic()

          原型的原型上的方法(第三层)

          function Person(name) { this.name = name } Person.prototype.__proto__.listenMusic = function () { console.log('听音乐') } const person = new Person('clz') console.log(person) person.listenMusic()

          但是呢,没法玩第四层,因为已经到顶了(Object.prototype没有原型(原型为null))

          function Person(name) { this.name = name } Person.prototype.__proto__.__proto__.listenMusic = function () { console.log('听音乐') } const person = new Person('clz') console.log(person) person.listenMusic()

          person -> Person.prototype -> Object.prototype -> null

          那么,这里就来看看第三层是不是真的是Object.prototype

          function Person(name) { this.name = name } Person.prototype.__proto__.listenMusic = function () { console.log('听音乐') } const person = new Person('clz') console.log(person) console.log(Person.prototype.__proto__ === person.__proto__.__proto__) console.log(person.__proto__.__proto__ === Object.prototype) // 这里就是判断处 person.listenMusic()

          发现,确实如此。

          下面这张图就是原型链的简单图(找不到是在哪里截的图了,侵删)

          原型链的作用

          为对象设置默认值

          利用原型为对象设置默认值。当原型属性与私有属性同名时,删除私有属性之后,可以访问原型属性,即可以把原型属性值作为初始化默认值。

          function Person(name) { this.name = name } Person.prototype.name = '赤蓝紫' const person = new Person('clz') console.log(person.name) // clz delete person.name console.log(person.name) // 赤蓝紫

          继承

          继承内容部分之后单独写。

          扩展原型方法

          Array.prototype.test = function () { console.log('扩展原型方法: 有风险') } const arr = [1, 2, 3] arr.test() // 扩展原型方法: 有风险

          typeof

          JavaScript的原型与原型链是如何构成一个完整的长尾词的?

          typeof是判断类型时大多数人的选择(当然也包括我啦),但是,判断非基本数据类型(function除外)时,只能得到Object。(null也是,但是null这个属于是历史遗留bug了)。

          js 在底层存储变量的时候,会在变量的机器码的低位1-3位存储其类型信息

          • 000:对象
          • 010:浮点数
          • 100:字符串
          • 110:布尔
          • 1:整数

          null:所有机器码均为0

          undefined:用 −2^30 整数来表示

          symbolbigint是后来新增的数据类型

          const num = 123 const str = 'hello' const bool = true const n = null const u = undefined const sym = Symbol(1) const big = BigInt(123) const fun = () => console.log(1) console.log(typeof num) // number console.log(typeof str) // string console.log(typeof bool) // boolean console.log(typeof n) // object console.log(typeof u) // undefined console.log(typeof sym) // symbol console.log(typeof big) //bigint console.log(typeof fun) //function

          function除外的非基本数据类型

          let arr = [] let obj = { name: 'clz' } let set = new Set([1, 2, 4]) console.log(typeof arr) console.log(typeof obj) console.log(typeof set)

          清一色object

          通过Object.prototype.toString.call(obj)来识别对象类型。会返回"[object Type]"来告诉你所指对象的类型

          let arr = [] let obj = { name: 'clz' } let set = new Set([1, 2, 4]) console.log(Object.prototype.toString.call(arr)) // [object Array] console.log(Object.prototype.toString.call(obj)) // [object Object] console.log(Object.prototype.toString.call(set)) // [object Set]

          instanceof

          instanceof只要右边变量的 prototype 在左边变量的原型链上,就会返回true

          function Person(name) { this.name = name } function Test(name) { this.name = name } const person = new Person('clz') console.log(person instanceof Person) // true console.log(person instanceof Object) // true console.log(person instanceof Test) // false

          普通对象与函数对象

          • 所有的函数都是通过new Function()来创建的,即是函数对象
          • 其他的都是普通对象

          function fn1() { } const fn2 = function () { } const fn3 = () => { } const fn4 = new Function() console.log(typeof fn1) //function console.log(typeof fn2) //function console.log(typeof fn3) //function console.log(typeof fn4) //function const obj1 = {} const obj2 = new Object() const obj3 = new fn1() console.log(typeof obj1); //object console.log(typeof obj2); //object console.log(typeof obj3); //object

          上面的例子中,fn1fn2fn3fn4是函数对象,obj1obj2obj3是普通对象

          • Object是构造函数,即也是函数,所以Object也是函数对象,相当于Function的实例,即Object.__proto__ === Function.prototype
          • Object.prototypeObject构造函数的原型,处于原型链的顶端,Object.prototype.__proto__已经没有可以指向的上层原型,因此其值为null

          console.log(typeof Object) // function console.log(Object.__proto__ === Function.prototype) // true console.log(Object.prototype.__proto__) // null

          • Function.prototypeFunction的原型,是所有函数对象的原型
          • Function.prototype是一个普通对象,所以Function.prototype.__proto__ === Object.prototype
          • Function函数不通过任何东西创建,JS引擎启动时,添加到内存中,所以**Function.__proto__ === Function.prototype**

          console.log(typeof Function) // function console.log(Function.prototype.__proto__ === Object.prototype) // true console.log(Function.__proto__ === Function.prototype) // true

          经典原型链图

          总结

          本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注自由互联的更多内容!

          本文共计2936个文字,预计阅读时间需要12分钟。

          JavaScript的原型与原型链是如何构成一个完整的长尾词的?

          目录- 解释原型与原型链- 构造函数- 原型对象- 访问原型- 设置原型- 测试原型- prototype、__proto__、constructor之间的关系- 原型链- 原型链的作用- 普通对象与函数对象- 经典原型链图- 总结- 原型详解

          目录
          • 详解原型与原型链
            • 构造函数
            • 原型对象
              • 访问原型
              • 设置原型
              • 检测原型
            • prototype、__proto__、constructor之间的关系
              • 原型链
                • 原型链的作用
              • 普通对象与函数对象
                • 经典原型链图
                • 总结

                  详解原型与原型链

                  其实,刚开始学JavaScript时,就有学过原型与原型链的相关知识了,只是当时还没有养成写笔记的习惯,导致现在已经忘的七七八八了。

                  这边文章真是花了很多心思,写了两天,看了很多篇篇博文,其中有小参考的,有解决一点疑惑的,但是最后只标注了一篇帮助最大的。

                  构造函数

                  实例的构造函数属性(constructor)指向其构造函数

                  function Person(name) { this.name = name } const person = new Person('clz') console.log(person.constructor === Person) // true

                  实例的构造函数并不是自身属性,而是从原型对象上继承的属性

                  function Person(name) { this.name = name } const person = new Person('clz') console.log(person.constructor === Person) // true console.log(Person.prototype.constructor === Person) // true console.log(person.hasOwnProperty('constructor')) // false:constructor属性并不是实例自身的属性,而是继承来的

                  原型对象

                  • __proto__(隐式原型):每个对象(除了null)都具有的属性,该属性指向该对象的原型
                  • prototype(显式原型):只有函数对象才有的属性,该属性指向函数的原型对象

                  来看来看

                  const arr = [1, 2, 3] const obj = { name: 'clz' } function add(a, b) { return a + b } console.log(arr) console.log(obj) console.log(add)

                  红框框中的[[prototype]]__proto__意义相同,都是指对象的内部属性

                  而所有函数都拥有prototype属性,所以可以通过f.prototype得到,那么自然也不需要通过[[prototype]]显示出来(毕竟prototype是显式原型,而__proto__是隐式原型,好吧,这是我猜的)

                  箭头函数没有prototype属性

                  访问原型

                  通过实例对象访问原型对象有 3 种方法

                  • obj.__proto__
                  • obj.constructor.prototype
                  • Object.getPrototypeOf(obj)

                  function Person(name) { this.name = name } const person = new Person('clz') const proto1 = person.__proto__ const proto2 = person.constructor.prototype const proto3 = Object.getPrototypeOf(person) const proto = Person.prototype // 原型 console.log(proto1 === proto) // true: 第一种方法 console.log(proto2 === proto) // true: 第二种方法 console.log(proto3 === proto) // true: 第三种方法

                  比较安全的做法是Object.getPrototypeOf(obj)

                  以下部分会涉及一丢丢原型链的知识(如果没看懂,可以看下原型链再来看)

                  • __proto__属性是私有属性,存在浏览器兼容性问题,缺乏非浏览器环境的支持
                  • 如果obj的constructor属性被覆盖,那么obj.constructor.prototype将会失效。(因为obj自身是没有constructor属性的,是通过原型链去它的原型上获取constructor属性,所以覆盖该属性时,将不会再去原型链上查找)

                  function Person(name) { this.name = name } function Temp(name) { this.name = name } const person = new Person('clz') person.constructor = Temp const proto = Person.prototype // 原型 console.log(person.__proto__ === proto) // true: 第一种方法 console.log(person.constructor.prototype === proto) // false: 第二种方法 console.log(Object.getPrototypeOf(person) === proto) // true: 第三种方法

                  设置原型

                  设置原型对象有 3 种方法

                  • obj.__proto__=prototypeObj
                  • Object.setPrototypeOf(obj, prototypeObj)
                  • Object.create(prototypeObj)

                  const proto = { // 原型对象 name: 'prototype' } // 第一种方法 const obj1 = {} obj1.__proto__ = proto // 设置原型 console.log(obj1.name) // prototype console.log(obj1.__proto__ === proto) // true // 第二种方法 const obj2 = {} Object.setPrototypeOf(obj2, proto) // 设置原型 console.log(obj2.name) // prototype console.log(obj2.__proto__ === proto) // true // 第三种方法 const obj3 = Object.create(proto) // 创建对象并设置原型 console.log(obj3.name) // prototype console.log(obj3.__proto__ === proto) // true

                  检测原型

                  使用obj1.isPrototypeOf(obj2)方法判断obj1是否为·obj2的原型

                  const proto = { // 原型对象 name: 'prototype' } const proto1 = { name: 'prototype' } const obj = {} obj.__proto__ = proto // 设置原型 console.log(proto.isPrototypeOf(obj)) // true console.log(Object.prototype.isPrototypeOf(obj)) // true console.log(proto1.isPrototypeOf(obj)) // false

                  prototype、__proto__、constructor之间的关系

                  function Person(name) { this.name = name } const person = new Person('clz') console.log(person.__proto__ === Person.prototype) // true:因为创建person对象的构造函数是Person,所以person对象的隐式原型(__proto__)指向Person函数的原型(prototype) console.log(Person.prototype.constructor === Person) // true

                  同一个构造函数创建的多个实例的原型是同一个

                  function Person(name) { this.name = name } const person1 = new Person('clz') const person2 = new Person('clz') console.log(person1 === person2) // false: 不是同一个对象 console.log(person1.__proto__ === person2.__proto__) // true:同一个构造函数创建的实例对象的原型是同一个

                  原型链

                  由上面的知识可以知道,实例对象具有属性__proto__,会指向原型对象。而原型对象也是对象,所以也会有属性__proto__,也会继续指向它的原型对象。

                  实例对象在查找属性时,如果查找不到,就会沿着__proto__去它的原型上查找,还找不到,则继续去原型的原型上查找,直到找到或到最顶层为止。这就是原型链的概念。

                  对象本身的方法(第一层:把方法当成属性)

                  function Person(name) { this.name = name this.listenMusic = function () { console.log('听音乐') } } const person = new Person('clz') console.log(person) console.log('实例对象本身是否有listenMusic方法', person.hasOwnProperty('listenMusic')) person.listenMusic()

                  对象的原型上添加方法(第二层)

                  function Person(name) { this.name = name } Person.prototype.listenMusic = function () { console.log('听音乐') } const person = new Person('clz') console.log(person) console.log('实例对象本身是否有listenMusic方法', person.hasOwnProperty('listenMusic')) person.listenMusic()

                  原型的原型上的方法(第三层)

                  function Person(name) { this.name = name } Person.prototype.__proto__.listenMusic = function () { console.log('听音乐') } const person = new Person('clz') console.log(person) person.listenMusic()

                  但是呢,没法玩第四层,因为已经到顶了(Object.prototype没有原型(原型为null))

                  function Person(name) { this.name = name } Person.prototype.__proto__.__proto__.listenMusic = function () { console.log('听音乐') } const person = new Person('clz') console.log(person) person.listenMusic()

                  person -> Person.prototype -> Object.prototype -> null

                  那么,这里就来看看第三层是不是真的是Object.prototype

                  function Person(name) { this.name = name } Person.prototype.__proto__.listenMusic = function () { console.log('听音乐') } const person = new Person('clz') console.log(person) console.log(Person.prototype.__proto__ === person.__proto__.__proto__) console.log(person.__proto__.__proto__ === Object.prototype) // 这里就是判断处 person.listenMusic()

                  发现,确实如此。

                  下面这张图就是原型链的简单图(找不到是在哪里截的图了,侵删)

                  原型链的作用

                  为对象设置默认值

                  利用原型为对象设置默认值。当原型属性与私有属性同名时,删除私有属性之后,可以访问原型属性,即可以把原型属性值作为初始化默认值。

                  function Person(name) { this.name = name } Person.prototype.name = '赤蓝紫' const person = new Person('clz') console.log(person.name) // clz delete person.name console.log(person.name) // 赤蓝紫

                  继承

                  继承内容部分之后单独写。

                  扩展原型方法

                  Array.prototype.test = function () { console.log('扩展原型方法: 有风险') } const arr = [1, 2, 3] arr.test() // 扩展原型方法: 有风险

                  typeof

                  JavaScript的原型与原型链是如何构成一个完整的长尾词的?

                  typeof是判断类型时大多数人的选择(当然也包括我啦),但是,判断非基本数据类型(function除外)时,只能得到Object。(null也是,但是null这个属于是历史遗留bug了)。

                  js 在底层存储变量的时候,会在变量的机器码的低位1-3位存储其类型信息

                  • 000:对象
                  • 010:浮点数
                  • 100:字符串
                  • 110:布尔
                  • 1:整数

                  null:所有机器码均为0

                  undefined:用 −2^30 整数来表示

                  symbolbigint是后来新增的数据类型

                  const num = 123 const str = 'hello' const bool = true const n = null const u = undefined const sym = Symbol(1) const big = BigInt(123) const fun = () => console.log(1) console.log(typeof num) // number console.log(typeof str) // string console.log(typeof bool) // boolean console.log(typeof n) // object console.log(typeof u) // undefined console.log(typeof sym) // symbol console.log(typeof big) //bigint console.log(typeof fun) //function

                  function除外的非基本数据类型

                  let arr = [] let obj = { name: 'clz' } let set = new Set([1, 2, 4]) console.log(typeof arr) console.log(typeof obj) console.log(typeof set)

                  清一色object

                  通过Object.prototype.toString.call(obj)来识别对象类型。会返回"[object Type]"来告诉你所指对象的类型

                  let arr = [] let obj = { name: 'clz' } let set = new Set([1, 2, 4]) console.log(Object.prototype.toString.call(arr)) // [object Array] console.log(Object.prototype.toString.call(obj)) // [object Object] console.log(Object.prototype.toString.call(set)) // [object Set]

                  instanceof

                  instanceof只要右边变量的 prototype 在左边变量的原型链上,就会返回true

                  function Person(name) { this.name = name } function Test(name) { this.name = name } const person = new Person('clz') console.log(person instanceof Person) // true console.log(person instanceof Object) // true console.log(person instanceof Test) // false

                  普通对象与函数对象

                  • 所有的函数都是通过new Function()来创建的,即是函数对象
                  • 其他的都是普通对象

                  function fn1() { } const fn2 = function () { } const fn3 = () => { } const fn4 = new Function() console.log(typeof fn1) //function console.log(typeof fn2) //function console.log(typeof fn3) //function console.log(typeof fn4) //function const obj1 = {} const obj2 = new Object() const obj3 = new fn1() console.log(typeof obj1); //object console.log(typeof obj2); //object console.log(typeof obj3); //object

                  上面的例子中,fn1fn2fn3fn4是函数对象,obj1obj2obj3是普通对象

                  • Object是构造函数,即也是函数,所以Object也是函数对象,相当于Function的实例,即Object.__proto__ === Function.prototype
                  • Object.prototypeObject构造函数的原型,处于原型链的顶端,Object.prototype.__proto__已经没有可以指向的上层原型,因此其值为null

                  console.log(typeof Object) // function console.log(Object.__proto__ === Function.prototype) // true console.log(Object.prototype.__proto__) // null

                  • Function.prototypeFunction的原型,是所有函数对象的原型
                  • Function.prototype是一个普通对象,所以Function.prototype.__proto__ === Object.prototype
                  • Function函数不通过任何东西创建,JS引擎启动时,添加到内存中,所以**Function.__proto__ === Function.prototype**

                  console.log(typeof Function) // function console.log(Function.prototype.__proto__ === Object.prototype) // true console.log(Function.__proto__ === Function.prototype) // true

                  经典原型链图

                  总结

                  本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注自由互联的更多内容!