什么是变异的[[原型]]
在 JavaScript 中,每个对象都有一个 [[原型]] 属性,它指向另一个对象。这个被指向的对象就是该对象的原型,也可以称之为父对象或者超类。
当我们访问一个对象的属性时,如果该对象本身没有这个属性,JavaScript 就会沿着原型链往上查找,直到找到该属性或者到达原型链的顶端(即 Object.prototype)。
所谓“变异的[[原型]]”,指的是在运行时改变某个对象的原型链,即将该对象的 [[原型]] 属性指向另一个对象。
例如,我们可以通过以下代码将一个空对象 {}
的原型指向 Array.prototype
:
const obj = {}; obj.__proto__ = Array.prototype;
变异的[[原型]]的糟糕表现
虽然变异的[[原型]]看起来似乎很有用,但实际上却会带来一些严重的问题。下面我们来看看这些问题是什么。
问题一:性能问题
每次访问一个对象的属性时,JavaScript 都需要沿着原型链往上查找,直到找到该属性或者到达原型链的顶端。这个过程是比较耗费时间的,因为要递归地遍历所有的原型链。
如果我们使用变异的[[原型]],那么每次访问该对象的属性时,JavaScript 都需要遍历新的原型链。这个过程比起之前要长得多,因为它需要先查找新的原型对象,才能继续查找原来的原型对象。这对性能会有很大的影响。
问题二:不可靠的行为
由于 JavaScript 引擎不支持变异的[[原型]],因此这种行为是不被标准所支持的。不同的引擎可能会有不同的实现方式,这样一来就会导致代码的行为不可靠。
例如,在某些浏览器中,将一个对象的原型指向 null
后再将其恢复成原来的原型对象时,该对象上的方法可能会出现错误或者失效。
const obj = {}; obj.__proto__ = null; // 将 obj 的原型指向 null console.log(obj.toString()); // TypeError: obj.toString is not a function obj.__proto__ = Object.prototype; // 恢复 obj 的原型为 Object.prototype console.log(obj.toString()); // "[object Object]"
问题三:安全问题
变异的[[原型]]也可能会带来安全问题。如果某个对象的原型被修改成了一个恶意的对象,那么在查询该对象的属性时,就可能会调用到这个对象的恶意方法,从而导致安全问题。
例如,以下代码将一个普通的对象的原型修改成了 Function.prototype
,并调用了该对象的 constructor
方法,可以看到这个方法输出了一个函数对象:
const obj = { name: 'Alice' }; obj.__proto__ = Function.prototype; console.log(obj.constructor); // "function Function() { [native code] }"
这个函数对象不仅可以访问全局变量,还可以执行任意 JavaScript 代码,因此可能会对系统造成严重的安全威胁。
如何避免使用变异的[[原型]]
鉴于变异的[[原型]]会带来许多问题,我们应该尽量避免使用它。下面是一些替代方案:
- 使用 Object.create() 来创建一个新的对象,并将其原型指
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/14698