我真的很努力创建一个可以继承数组所有属性的自定义对象,但其行为也与普通实例相同,也就是说,instanceof
和 构造函数
的行为就像您希望的那样。我读过类声明只是语法糖,所以我从未向它们寻求解决方案(我对它们知之甚少)。
在我取得重大突破之前,我创造了这个令人厌恶的东西:
function arrayLike() {
let al = [];
//make obj.constructor work
Object.defineProperty(al, 'constructor', {value: arrayLike});
//add methods
//make (obj instanceof arrayLike) == true
return new Proxy(al, {
getPrototypeOf() {
return arrayLike.prototype;
},
})
}
//make (obj instanceof Array) == true
Reflect.setPrototypeOf(arrayLike.prototype, Array.prototype);
碰巧我看到了一个非常接近我想做的事情的类示例,然后发现它非常适合这项工作:
class arrayLike extends Array {
//add methods
}
在 Chrome DevToos 中查看它,我可以看到我创建的内容与此完全不具有相同的结构。
如果类声明确实是语法糖,那么没有它你到底如何创建这个对象呢?
最佳答案
Javascript 是一种具有继承形式的语言,称为原型(prototype)继承。
其背后的想法是,给定一个对象,它有一个名为 prototype 的隐藏属性,它是对另一个对象的引用,该对象被称为原型(prototype)对象。
当您要求 javascript 引擎为您提供对象属性的值时,这种关系非常重要,我们将其称为 foo 只是为了解决这个问题。 JavaScript 引擎将首先检查您的对象以查看它是否具有名为 foo 的属性:如果在您的对象上定义了该属性,则返回其值并完成搜索。否则,如果您的对象没有名为 foo 的属性,则将搜索其原型(prototype)对象并再次重复相同的过程。
递归地重复此过程,直到探索完所有所谓的原型(prototype)链。原型(prototype)链的根是一个内置的 javascript 对象,您可以使用表达式 Object.prototype 引用它,并且是所有其他 javascript 对象派生的对象。请注意,如果构成整个原型(prototype)链的all对象中缺少foo属性,则返回值undefined。
这是内置于 javascript 中的继承的真正形式,它是真正位于 ES6 class 关键工作背后的业务,它是一种便利,可以隐藏这种困惑,并给您这样的印象,即 javascript 有一种形式类继承(类继承更广为人知,大多数程序员发现它比原型(prototype)继承更容易想到)。
为了获取一个对象并决定它应该像数组一样运行,您至少可以执行以下操作:
const myArray = [];
const myObject = { foo: "bar" }
Object.setPrototypeOf(myObject, myArray);
myObject.push("hello");
myObject.push("world");
console.log(myObject.length); // prints 2
This book是我所知道的关于 javascript 语言的最佳引用。 This is good too ,但现在有点过时了,而且不像以前那么容易遵循。
一个比前一个更复杂的示例可以通过使用函数作为构造函数来实现。这实际上是 ES5 实现类继承的老式方法,您在 ES5 时代为了模仿类而所做的事情:
function SpecialArray(name) {
this.name = name;
}
SpecialArray.prototype = [];
// fix the constructor property mess (see the book linked above)
Object.defineProperty(SpecialArray.prototype, "constructor", {
value: SpecialArray,
enumerable: false,
writable: true
});
SpecialArray.prototype.getSalutation = function() {
return "Hello my name is " + this.name;
};
const mySpecialArray = new SpecialArray("enrico");
// you can call the methods and properties defined on Array.prototype
mySpecialArray.push("hello");
mySpecialArray.push("world");
console.log(mySpecialArray.length); // prints 2
// you can use the methods and properties defined on SpecialArray.prototype
console.log(mySpecialArray.name); // prints enrico
console.log(mySpecialArray.getSalutation()); // prints Hello my name is enrico
// important sanity checks to be sure that everything works as expected
console.log(mySpecialArray instanceof Array); // prints true
console.log(mySpecialArray instanceof SpecialArray); // prints true
console.log(mySpecialArray.constructor === SpecialArray); // prints true
// you can iterate over the special array content
for (item of mySpecialArray){
console.log(item);
}
// you can read special array entries
console.log(mySpecialArray[1]); // prints world
关于javascript - 如何在没有类声明的情况下扩展 Array?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56721630/