javascript - 如何在没有类声明的情况下扩展 Array?

标签 javascript ecmascript-6 es6-class

我真的很努力创建一个可以继承数组所有属性的自定义对象,但其行为也与普通实例相同,也就是说,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/

相关文章:

javascript - 为什么将注释的开头向下移动一行空格会破坏此 JavaScript 代码在 WordPress 中的编译?

javascript - 谷歌图表 : how do I change the percentage label color?

javascript - `{ }` 和 `[ ]` 和有什么区别?

javascript - 如何将类组件转换为函数无状态组件?

javascript - 如何在 Javascript 中调用祖父类的 setter

JavaScript ES6 装饰器模式

javascript - 暂时阻塞 UI,并运行回调

javascript - ES6 Map 的键相等在 Chrome 内容脚本中表现奇怪

node.js - co node.js 库的用途是什么?

JavaScript:任何人都可以让它工作或解释为什么它不起作用吗?