Javascript 数组.of()是否按照es6中的指定工作?

Javascript 数组.of()是否按照es6中的指定工作?,javascript,arrays,ecmascript-6,Javascript,Arrays,Ecmascript 6,根据文档,Array.of()是new Array()的一种替代方法,它允许您在运行时创建数组文字,即使它只有一个元素(new Array()出现故障的情况)。我喜欢这样,并且用.of()替换了对自定义数组子类的大多数new()调用,但是自从转换之后,我现在在尝试某些事情时发现了错误 该链接声称()的.of等同于: Array.of = function() { return Array.prototype.slice.call(arguments); } 为了检查这是否正确,我编写了这个测试

根据文档,
Array.of()
new Array()
的一种替代方法,它允许您在运行时创建数组文字,即使它只有一个元素(new Array()出现故障的情况)。我喜欢这样,并且用
.of()
替换了对自定义数组子类的大多数
new()
调用,但是自从转换之后,我现在在尝试某些事情时发现了错误

该链接声称()的
.of
等同于:

Array.of = function() { return Array.prototype.slice.call(arguments); }
为了检查这是否正确,我编写了这个测试来比较()的真实
和polyfill:

Array.of_polyfill = function( ...args )           // Fake of().
{ 
    console.log( args );
    return Array.prototype.slice.call( args );
}

class A extends Array      // So we can peek inside what the real of() is doing.
{ 
    constructor( ...args )   // Using of() on an "A" calls this constructor. 
    { 
        console.log( args );
        return Array.prototype.slice.call( args );
    }
}

var a1 = A.of         ( 5,6,7,8 );
var a2 = A.of_polyfill( 5,6,7,8 );
a1和a2最终都包含正确的值
[5,6,7,8]
,但内部使用这两行不一致,如控制台日志所示:

[4]
(4) [5, 6, 7, 8]
从那里的第一行开始,调用
.of()
并没有导致整个文本都在范围内,而只是
[4]
,就好像它在内部调用
A
构造函数来预分配四个插槽,这不是polyfill提到的

我关心内部行为,因为()的
of
的主要建议用途之一是自定义数组子类,如上面的
A
,以允许我指定新类型的数组文本。为此,我的
A
构造函数应该能够手动处理文本(传入的参数),但由于上述原因,它无法访问它。有没有其他方法可以让我进入


这是对()的
所建议的polyfill准确吗?还是我误解了JavaScript和构造函数的某些方面
Array.of
允许您创建数组,而不是“数组文字”。“literal”指的是允许您描述和创建带有初始化数据(如果有)的数组的语法,如
var a=[1,2,3]


最终,这些文件没有声称polyfill完全等效。MDN是一个wiki,因此如果polyfill可以改进,那么欢迎任何人贡献更改。请记住,它将在ES5及更低版本中工作,因此实现完整的子类化行为将需要更多的工作。

因此,我们在这个问题中混合了多种内容。您正在使用不应该使用的扩展运算符,并且似乎对本机代码是什么存在误解。Array.of是一个静态函数;创建构造函数不会模仿它的行为。但是,您可以重写静态方法并使用spread操作符。在这种情况下,它将是

class B extends Array {
    static of(...args) {
        return args;
    }
}
或者使用参数

class A extends Array {
    static of() {
        return Array.prototype.slice.call(arguments);
    }
}
或者只是

class A extends Array {
    static of() {
        return Array.from(arguments);
    }
}
同样,你的“polyfill”做得太多了。通过使用spread操作符,您已经获得了一个数组。这就足够了:

Array.of_polyfill = function (...args) {
    return args;
};
在下面,您将获得相同阵列的三倍:

Array.of_polyfill=函数(…args){
返回args;
};
类扩展数组{
静态的(){
返回Array.prototype.slice.call(参数);
}
}
B类扩展了数组{
静态参数(…args){
返回args;
}
}
var a1=A.of(5,6,7,8);
var a2=一种聚填充物(5,6,7,8);
var b=b.of(5,6,7,8);
控制台日志(a1);
控制台日志(a2);

控制台日志(b)
假设调用构造函数时使用传递给
A.of
的参数。那是错误的

让我们看一下以下各项的规格:

  • 让len为传递给此函数的实际参数数

  • 让items作为传递到此函数的参数列表

  • 设C为该值的最大值

  • 如果
    IsConstructor(C)
    为真,则

    a。让A是
    ?构造(C,«len»)

  • 否则,

    a。让A是
    ?ArrayCreate(len)

  • [……]

    在我们的例子中,“C”是
    A
    ,您定义的类,它是一个构造函数。创建了
    A
    的一个新实例,使用“len”(传递给
    Array.of
    的参数数)调用构造函数

    通常,构造函数是
    Array
    ,因此将调用
    Array(len)
    。这里,调用
    A(4)
    。因此,
    …args
    [4]

    之后,算法将用正确的值填充新构造的数组


    这意味着
    Array.of
    Array.prototype.slice.call
    的结果是等效的,但不是它们内部的工作方式。

    经过一些测试后,
    Array.of()
    的实际实现似乎是这样的:

    Array.of = function() {
      //check wether `this` is a constructor, otherwise fall back to the `Array` constructor
      //maybe there's a better way to determine wether `this` is a constructor _before_ calling it.
      var constructor = typeof this === "function" && "prototype" in this? this: Array, 
        result = new constructor(arguments.length);
    
      for(var i=0; i<arguments.length; ++i)
        //FF and Chrome use defineProperty()
        Object.defineProperty(result, i, {
          value: arguments[i], 
          writable: true, 
          enumerable: true,
          configurable: true
        })
        //Edge simply assigns the values
        //result[i] = arguments[i];
        //didn't test IE, Opera, Safari or any mobile browser
    
      //and again, setting the length after the items have been defined
      result.length = arguments.length;
      return result;
    }
    
    Array.of=function(){
    //检查'this'是否为构造函数,否则返回'Array'构造函数
    //在调用它之前,也许有更好的方法来确定“this”是否是构造函数。
    var constructor=typeof this===“函数”和“原型”在此?this:Array中,
    结果=新构造函数(arguments.length);
    
    对于(var i=0;iYou正在扩展数组,但没有调用
    super()
    为了正确初始化派生的对象,需要执行此操作。由于神奇的
    .length
    属性不适用于ES5中的子分类,因此无法对数组的正确子类进行多填充。对于数组的真实子类,需要ES6,如果有ES6,则不需要
    数组。of()
    polyfill@jfriend00:难道不能用setter和getter来模拟神奇的
    .length
    吗?@spanky-不完全可以。你必须覆盖所有可能改变数组长度的操作来跟踪它。你可以创建一个包含数组的新对象,并将所有数组操作代理给它,然后使用
    .length
    来自您所包含的实际数组,但它并不像您所展示的那样从数组继承。可以说,在ES5中尝试对数组进行子类化是不值得的。@jfriend00:Hmmm…我不认为内部操作实际使用了
    .length
    属性