const impl = Symbol()
class MyArrayLike {
constructor() {
this[impl] = [2, 1]
Object.freeze(this)
}
get 0() { return this[impl][0] }
set 0(value) { this[impl][0] = value }
get 1() { return this[impl][1] }
set 1(value) { this[impl][1] = value }
get length() { return 2 }
}
const xs = new MyArrayLike()
Array.prototype.sort.call(xs) // (A)
console.log(xs[0], xs[1])
在上面的代码中,我希望显示已排序的值1 2
。但是,Chrome和Firefox的结果不同。
(A)
处引发了TypeError,因为访问者属性this
为undefined
。规范如下:https://www.ecma-international.org/ecma-262/8.0/#sec-array.prototype.sort 但是英语对我来说很难。
Chrome在Array.prototype.sort的访问者属性中没有提供this
这是一个错误吗?或者它是一种非特定的设计行为?
答案 0 :(得分:1)
这不适用于Chrome的原因是Chrome和其他浏览器在排序调用期间处理this
的方式。在其他浏览器中,this
仍然是实例。但是,在Chrome中,this
指的是MyArrayLike原型,它是定义访问器属性(getter和setter)的地方。在原型上,impl
属性不存在(它在实例上),这就是结果未定义的原因。
与数组的一个区别是它们似乎是为实例本身的每个索引定义属性,而不是原型。您可以通过在数组实例上调用Object.getOwnPropertyNames()来测试它。这将返回索引数组和“length”。另一方面,如果您尝试在类的实例上调用该函数,则返回一个空数组。
如果您希望自己的代码也可以在Chrome上运行,那么可以选择在实例本身定义属性,例如下面的代码段:
var impl = Symbol()
class MyArrayLike {
constructor() {
this[impl] = [2, 1];
Object.defineProperty(this, 0, {
get: function() { return this[impl][0] },
set: function(value) { this[impl][0] = value }
});
Object.defineProperty(this, 1, {
get: function() { return this[impl][1] },
set: function(value) { this[impl][1] = value }
});
Object.defineProperty(this, "length", {
get: function() { return 2; }
});
Object.freeze(this)
}
}
var xs = new MyArrayLike();
Array.prototype.sort.call(xs);
console.log(xs[0], xs[1]);
这是否是一个错误,可能需要从Chrome团队检查。但是,它也可能只是Chrome的实施方式的差异。