4

谈谈 javaScript 原型链

 3 years ago
source link: https://blog.dteam.top/posts/2021-03/js-prototype.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

谈谈 javaScript 原型链

小纪同学 Posted at — Mar 23, 2021 阅读 21

原型链是为了实现继承,也就是说js的继承是基于原型链的。原型-prototype,是一个对象,用于存放共享的属性和方法的。

原型主要有这么几个概念: __proto__、prototype、constructor

什么是__proto__? js会为每个对象添加一个属性,这个属性指向另外一个对象的prototype,js可以通过 Object.getPrototypeOf(obj)获取,chrom浏览器实现为__proto__

什么是prototype? js会为每个函数添加一个prototype属性,表示自己的原型对象。 prototype是个对象。

什么是constructor? 是js创建和初始化对象的方法,如果没有自己指定constructor,则会默认有个空的constructor。 原型对象的constructor指向自己的创造者,每个原型对象都有constructor。所有对象都会从它的原型上继承 constructor 属性。

Tips: 1.函数也是对象,所以函数也有 __proto__ 属性。 2.规定 Object.prototype.__proto__ === null。 3.默认情况下,除 Object 函数的 prototype.__proto__ 都是 Object.prototype。 4.除Object函数的__proto__永远指向prototype。

⚠️注意:这里有个特殊的函数: Function,任何函数都是 Function 的实例,包括 Object。所以 Function 可以说是根构造函数。 所以 Object.__proto__ 就是Function.prototype 所以 Function.__proto__ 也是Function.prototype

image.png

以上就是主要知识点,为了理解咱们举个🌰:

创建一个普普通通的函数A

function A(){}

此时 A 里面有prototype,__proto__两个属性。 A同时继承了A.prototype.constructor

A.prototype

A.prototype 就是它的原型对象,里面有什么? 有constructor__proto__,为什么会有__proto__?因为prototype也是个对象。 A.prototype.constructor 指向了谁?当然是A,prototype里面的constructor指向它的函数。 A.prototype.__proto__指向了谁?当然是Object.prototype,因为 默认情况下,任何函数的原型属性__proto__ 都是Object.prototype

image.png

image.png

A.__proto__

A.__proto__是什么?应该知道它指向一个prototype,那么是谁的prototype? 当然是Function的。因为它也是由Function创建的。__proto__是由浏览器实现的,不是标准写法,Object 提供了获取原型的方法:getPrototypeOf Object.getPrototypeOf(A)

image.png

image.png

image.png

A.constructor

A.constructor,实际是 A.prototype.constructor,指向自己的创造者:Function

image.png

创建一个A的实例:

a = new A();

根据上面讲述,a会有 __proto__constructor两个属性,并且a.__proto__=== A.prototype: a.constructor为a.__proto__.constructor。

image.png

image.png

如果这个时候A.prototype中如果有属性,或者方法,a都是可以调用的。 image.png

image.png

两个对象通过__proto__连接,就组成了原型链。 可以给对象指定原型(不建议这么做),这里举例仅是为了理解原型链。将A的实例赋值给B的原型,这样可以理解为B继承了A,B创建的实例b也可以调用A原型中的方法了: image.png

整体结构图如下: image.png

从上面例子可以看出js创建一个对象(使用new操作符)大致过程:

  1. 创建一个对象
  2. 给它一个原型
  3. 把对象放进constructor加工

创建一个对象: image.png

<!-- new 一个 A 对象  -->
function newA(...args) {
  var self = Object.create(A.prototype)
  var res = A.prototype.constructor.call(self, ...args)
  if (typeof res === 'object' && res !== null) {
    return res
  }
  return self
}

应用与总结

像Array中的forEach,find,filter等都是在Array.prototype上,这样的内置对象还有很多。 es6实现了class语法糖,实际还是应用原型链。

// function A(name) {
//   this.name = name;
// }

// A.prototype.run = function() {
//   console.log(`${this.name} running...`);
// };

class A {
  constructor(name) {
    this.name = name;
  }

  run() {
    console.log(`${this.name} running...`);
  }
}

但是不建议修改内置对象的原型,会产生一些副作用,比如: image.png

image.png


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK