1 javascript inheritance object prototypal-inheritance prototype-chain
使用 Object.create() 继承 JavaScript?
或者
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain
建议 Object.create() 是在 ES5 中设计的,旨在提供一种简单的方式来继承 JavaScript 对象。
这按预期工作,如下所示:
const A = function() {};
A.prototype.x = 10;
A.prototype.say = function() {
console.log(this.x);
};
const a = new A();
a.say(); //10
const b = Object.create(a);
b.say(); //10Run Code Online (Sandbox Code Playgroud)
但是,现在我想继承一个对象,例如
Object(3).
出于某种原因,人们(在大多数情况下,用某个问题很难解决问题的人)倾向于问“你为什么需要这个?” 这对规范来说真的无关紧要,因此,可能最好指定。
我尝试创建一种根据需要为任何 JavaScript 对象提供类型的方法。
幸运的是,每个原始值3都可以通过Object(3).
现在,我尝试了Object.create在这种情况下如何工作,但它不起作用。
const a = Object(3);
console.log(
a
);//[Number: 3]
console.log(
a.toString()
);// 3
const b = Object.create(a);
console.log(
b
);//{}
console.log(
Object.getPrototypeOf(b)
);
console.log(
b.toString()
);
//TypeError: Number.prototype.toString requires that
// 'this' be a NumberRun Code Online (Sandbox Code Playgroud)
我想念什么?有什么解决方法吗?还是因为某种原因不可能?
谢谢。
编辑:我真的不想在这里扩展特定的主题或规范问题,但不幸的是,我无法避免人们问我“你为什么需要这个?” 我相信完全脱离主题的事情。
那些在 JavaScript 中被称为“盒装原语”的对象绝对看起来很奇怪。让我们看看您发现了什么,以及如何通过原型使用派生来做您想做的事情。
首先,记住它做了什么y = Object.create(x):它创建了一个原型为 x 的新对象 y。
x = {name: "Rex"};
x.constructor; // [Function: Object]
typeof x; // "object"
y = Object.create(x);
Object.getPrototypeOf(y) === x; // true
x.isPrototypeOf(y); // true
y.name; // "Rex"
Run Code Online (Sandbox Code Playgroud)
Nice:x指一个对象,y是一个原型为 的新对象x。x 引用的对象有一个可枚举的、可配置的、可写的、名为 的值属性name,该属性由 y 继承。在 x 中,name是自己的财产;in y,它是一个继承的属性。但在这两种情况下,该属性都非常“正常”。
现在让我们使用一个Number对象:
x = Object(3); // [Number: 3]
x.constructor; // [Function: Number]
typeof x; // "object"
x.valueOf(); // 3
x + 0 // 3
y = Object.create(x);
Object.getPrototypeOf(y) === x; // true
x.isPrototypeOf(y); // true
// So far so good, but now
y.valueOf()
// TypeError: Number.prototype.valueOf requires that
// 'this' be a Number
y + 0
// TypeError: Number.prototype.valueOf requires that
// 'this' be a Number
Run Code Online (Sandbox Code Playgroud)
哇刚刚发生了什么?这y是不是一个数字?让我们检查一下:
y.constructor // [Function: Number]
Run Code Online (Sandbox Code Playgroud)
好吧,它确实看起来像一个数字。由于原型的y是x,和的原型y就是Number.prototype,y肯定可以访问所有的功能Number.prototype。但似乎无论我们调用其中的哪一个,例如:
y.toFixed(2)
y.toLocaleString()
Run Code Online (Sandbox Code Playgroud)
等等,我们得到那个错误!这里发生的事情是,所有这些函数都在Number.prototype检查对象的内部属性,他们希望在那里看到一个原语。数字对象的这个内部槽不是继承的,所以当你做y = Object.create(x) x 的那个包含 3 的y槽没有被继承,所以在 中,那个槽不包含原始数字!所有的方法都Number.prototype期望内部槽(它被称为[[NumberData]]......请参阅关于数字对象的官方ECMAScript 规范部分以获得原始值。
现在稍微向下滚动到第 20.1.3 节,您可以看到数字操作如何通过抽象操作尝试提取槽中thisNumberValue的值,如果没有检出[[NumberData]],将抛出 a TypeError。这就是你所看到的!
所以这对于你来说意味着什么?
如果你想使用原型继承来创建一个新的数字对象,其原型是一个现有的数字对象,并以新对象的数值与原始对象相同的方式来做,你不能直接在 JavaScript 中这样做。这不是Number对象的工作方式!但是,您可以创建自己的数字类型,其中原始值存储在可继承的属性中。
您可以尝试的另一件事是:为每个原语创建您自己的函数。例如:
function createNewNumber(original) {
// n is expected to be a Number object
const derived = new Number(original.valueOf());
Object.setPrototypeOf(derived, original);
return derived;
}
Run Code Online (Sandbox Code Playgroud)
现在
x = Object(5) // [Number: 5]
y = createNewNumber(x) // [Number: 5]
x.isPrototypeOf(y) // true
Run Code Online (Sandbox Code Playgroud)
这可能会满足您的要求,但请记住,您不能直接使用Object.create! 对数字使用 Object.create 并不会继承[[NumberData]]我们亲眼所见的属性。需要自己实现推导函数,自己设置原型。这是一个黑客,但我希望它有所帮助!
附录
至于为什么该[[NumberData]]插槽没有继承,这里是从ES9规格报价:
内部槽对应于与对象相关联并被各种 ECMAScript 规范算法使用的内部状态。内部槽不是对象属性,它们不是继承的。根据特定的内部插槽规范,这种状态可能由任何 ECMAScript 语言类型的值或特定 ECMAScript 规范类型的值组成。除非另有明确规定,内部插槽是作为创建对象过程的一部分分配的,不能动态添加到对象中。除非另有说明,内部插槽的初始值是未定义的值。本规范中的各种算法创建具有内部插槽的对象。但是,ECMAScript 语言没有提供将内部插槽与对象关联的直接方法。
虽然这种语言明确表示无法在对象上创建或设置插槽,但似乎我们甚至无法检查。因此,从物体抓取数值将需要使用编程器可访问的valueOf物业Object.prototype。除非一个人做了一些疯狂的事情,比如Object.create(null)。:)
| 归档时间: |
|
| 查看次数: |
197 次 |
| 最近记录: |