我们可以手动断开JS中预定义的数字、字符串、布尔值、数组的原型链,或者重新赋值吗
__proto__
指向Number Object
。它的__proto__
将再次指向Object Core
,其__proto__
指向null
,从而结束原型链。
我尝试做的是通过尝试将__proto__
链接从Number Object
更改为某个字符串来覆盖中间的这个链。我无法中断链,因为在我的赋值之后,它仍然指向Object Core
结构。
断开此原型链是我做错了什么,还是无法在浏览器中断开预定义的原型链!
Number.__proto__ = "abc";
let num4 = 8;
console.log(num4.__proto__);//returns Number Object
console.log(num4.__proto__.__proto__)//should return string "abc"
输出:
不过,我知道我可以通过以下代码在链的中间添加某些项目(如Number-Object):
Number.prototype.alpha = "def";
let num5 = 99;
console.log(num5.__proto__);
输出:
解决方案
修改基本对象的内置原型或内置原型链通常是非常糟糕的想法。我强烈建议您不要这么做。
Number.__proto__
是Number
函数的原型,不是Number
对象(即Number.prototype
)的原型。
此外,JavaScript同时具有Number基元和Number对象。大多数情况下,您要处理的是一个原始的数字。当您在Number基元(n = 42
)(如LIKEtoString
)上使用属性(包括方法)时,即使n
是基元,JavaScript引擎也会从Number.prototype
获取这些属性。
您可以更改Number.prototype
的原型。例如,您可以将其设置为null
,以便Number
对象不再继承Number.prototype
以外的任何对象(用Object.prototype
断开链接),这意味着对数字原语的属性查找不再从Object.prototype
中找到属性和方法:
const n = 8;
console.log(typeof n.hasOwnProperty); // function
console.log(Object(n) instanceof Number); // true
console.log(Object(n) instanceof Object); // true
Object.setPrototypeOf(Number.prototype, null);
console.log(typeof n.hasOwnProperty); // undefined
console.log(Object(n) instanceof Number); // true
console.log(Object(n) instanceof Object); // false
(Object(n)
返回数字原语n
的Number
对象。我在那里使用它是因为instanceof
对于原语总是false
[例如n instanceof Number
isfalse
]。若要检查继承,我们临时需要一个对象。)
如您所见,Number
对象和Object
之间的链接已断开。
不过,我知道我可以通过以下代码在链的中间添加某些项目(如Number-Object):
Number.prototype.alpha = "def"; let num5 = 99; console.log(num5.__proto__);
这只是向Number.prototype
添加属性,而不是向原型链中插入某些内容。但是也可以插入到原型链中,因为我们可以更改Number.prototype
:
function Custom() {
}
// Change `Custom.prototype` to an object whose prototype
// is the prototype of `Number.prototype` (which will be
// `Object.prototype` in an unsullied environment).
// (`Object.create` creates an object setting its prototype
// to the given object.)
Object.defineProperty(Custom, "prototype", {
value: Object.create(Object.getPrototypeOf(Number.prototype)),
writable: true,
});
Object.defineProperty(Custom.prototype, "constructor", {
value: Custom,
writable: true,
configurable: true,
});
Object.defineProperty(Custom.prototype, "example", {
value() {
return "hi there";
},
writable: true,
configurable: true,
});
Object.setPrototypeOf(Number.prototype, Custom.prototype);
const n = 8;
console.log(n.example()); // "hi there"
console.log(Object(n) instanceof Custom); // true
我在那里使用了构造函数,这样我们就可以方便地使用instanceof
检查继承,但是您可以在没有构造函数的情况下插入原型。下面是不带一个相同代码:
const custom = Object.create(Object.getPrototypeOf(Number.prototype));
Object.defineProperty(custom, "example", {
value() {
return "hi there";
},
writable: true,
configurable: true,
});
Object.setPrototypeOf(Number.prototype, custom);
const n = 8;
console.log(n.example()); // "hi there"
注意1:最好避免更改现有对象的原型(例如,使用Object.setPrototypeOf
)。JavaScript引擎基于这样的假设进行优化(通常是正确的),即对象的原型在创建之后不会更改。更改它会打破这一假设,从而从对象中删除这些优化。
注意2:您会注意到我没有在上面的任何地方使用__proto__
accessor property。它已弃用,不应在新代码中使用,请改用Object.getPrototypeOf
和(如果绝对必要)Object.setPrototypeOf
。对于不是从Object.prototype
继承任何对象,它也会失败,因为__proto__
访问器属性就是在这里定义的。
相关文章