Tho*_*hor 26 javascript arrays
我对Array.length属性(即length在Array函数对象上命名的属性)和array_instance.length(即length在数组对象的实例上命名的属性)有点困惑
那么,这两个length属性有什么区别?何时/不应该使用它们?
编辑1:
对象length上还有一个属性Array.prototype。我感到很困惑。
编辑2
为了画出更清晰的图片,这是length我发现的不同属性
编辑3
这是我在评论部分中提出的跟进问题之一,但我认为该问题对于充分理解length财产很重要,因此我在主部分中粘贴了此内容。
后续问题:
Array.prototype.hasOwnProperty('length')和Array_instance.hasOwnProperty('length')return true,是否表示存在两个length属性,一个在on array_instance,一个在Array.prototypeobject,并且将array_instance.lengththeshashaping了Array.prototype.length?
Nic*_*wer 28
函数具有一个.length属性,该属性对应于它们期望的参数数量。例如:
const unary = (a) => {
}
const binary = (a, b) => {
}
console.log(unary.length);
console.log(binary.length);Run Code Online (Sandbox Code Playgroud)
因此Array构造函数的长度为1,因为它希望将一个参数(即数组的大小)传递给它。
数组对象还具有一个.length属性,除了具有相同的名称之外,该属性是无关的。该属性表示当前阵列的大小。
Kai*_*ido 12
第一部分已经回答,Array构造函数是一个函数,而函数具有一个.length属性。
对于第二个,Array.prototype.length它有点模糊...
Array.prototype 实际上是一个数组:console.log(Array.isArray(Array.prototype)); // true
Array.prototype.push('hello');
console.log(Array.prototype.length); // 1
console.log(Array.prototype[0]); // "hello"Run Code Online (Sandbox Code Playgroud)
至于为什么是数组?因为规格是这样说的:
Array原型对象是Array奇异对象,并具有为此类对象指定的内部方法。它具有一个length属性,其初始值为0,其属性为{[[Writable]]:true,[[Enumerable]]:false,[[Configurable]]:false}。
还有一条注释说明它是出于与规范先前版本的兼容性原因。
至于为什么被设计为数组?我没有一个好主意...
我确实认为很多其他答案都涵盖了此处所需的所有内容,但是OP似乎并没有他们所看到的明确答案,因此我将尽一切努力尽一切可能-但要尽可能清楚地列出所有内容-为了澄清。(很抱歉,如果有人认为我在“窃取”他们的答案,我向您保证这不是故意的,在我输入此内容时,我刻意不看他们,但我确实阅读了其中的大部分内容,甚至对a几个。)
数组长度
上面已经很好地介绍了这一点。Array是本机JS函数,可用于创建数组。它不那么简单,而是简单地定义一个数组文字(据我所知,没有理由更可取),但是var a = [1,2,3]允许您这样做:
var a = Array(1,2,3);
console.log(a);Run Code Online (Sandbox Code Playgroud)
顺便指出,你不希望这样做,以创造一个单阵列,还有就是当你提供这恰好是一个整数正好一个参数的特殊情形的完全疯了疑难杂症:
var a = Array(5);
console.log(a);Run Code Online (Sandbox Code Playgroud)
尽管undefined在SO使用的任何JS控制台实现中,这似乎都显示了由5个值组成的数组,但这实际上并不是所创建的内容(也不包含当前版本的Chrome中显示的内容)。我正走出正题,但我将向您推荐凯尔·辛普森(Kyle Simpson)的疯狂之旅。
无论如何,由于Array是一个函数,正如其他人已经观察到的那样,它具有所有函数一样的length属性。我真的不确定为什么要求值-对于用户定义的函数,它是函数正式声明的参数数量,但是由于像所有本机JS函数一样,实际上并未在JS中实现,因此我无法告诉您实施的实际运作方式。显然,它可以接受任意数量的参数,因此是一个相当“奇特”的功能。我不认为1ArrayArray.length无论将什么值赋给它,它总是有用的,但是似乎大多数实现都为1,即使规范保持打开状态也是如此。(我还不是一个专门的技术人员,不知道这是在其中实际定义的还是要留给实现的。)
arrayinstance.length
这只是我们一直都知道和使用的数组的功能。所有JS数组都具有此属性-请注意,尽管它是属性而不是方法(即,它不是函数),但是随着数组的变长或变短,它仍会“自动更新”:
var a = [1,2,3];
console.log(a.length);
a.push(4);
console.log(a.length);
a.pop();
a.pop();
console.log(a);
console.log(a.length);Run Code Online (Sandbox Code Playgroud)
尽管正如我所说,JavaScript的本机构造函数不是用JS本身实现的,但是您可以通过定义getter来实现这种行为(至少从ES5开始)。
Array.prototype.length
要完全解释什么Array.prototype(以及类似的对象),将使我深入了解Javascript的对象系统是如何工作的。在这里足以说出,与基于类的语言不同(尽管JS 甚至在ES6中JS也没有类,尽管class语法经常允许我们假装确实如此),但JS没有通常所谓的“继承”概念。 OO语言可以。在JS的版本中(有时称为“原型继承”),每个对象都有一个引用了其他对象的“内部原型”会发生什么情况;如果您尝试访问该对象所没有的属性,那么JS引擎将在该“原型对象”中查找该属性,并使用其值代替。
这实际上是一种非常简单的机制,但是在语言中有很多东西使这一点感到困惑,其中之一就是函数(也是对象)具有称为prototype- 的属性的事实,该属性并不指向真正的“原型”如果在函数对象上引用了不存在的属性,则会查询该对象。(普通函数foo具有的Function.prototype是它委托给的对象-而不是foo.prototype。)但是,如果声明一个函数foo,foo.prototype则会创建一个称为的对象-基本上是一个空的,非描述性的对象。它的意义在于,如果函数foo用作“构造” -也就是说,如果你通过调用使对象new foo()-foo.prototype如果由此构造的任何对象foo碰巧无法通过属性查找,则它将成为JS查找属性(包括方法)的对象。
这就是为什么至少在ES6之前的代码中您经常看到这种模式的原因:
function foo(a,b) {
this.a = a;
this.b = b;
}
foo.prototype.add = function() {
this.a = this.a + this.b;
}
var myFoo = new foo(1,2);
console.log(myFoo.a);
myFoo.add();
console.log(myFoo.a);
myFoo.add();
console.log(myFoo.a);
console.log(myFoo.hasOwnProperty("add"));Run Code Online (Sandbox Code Playgroud)
尽管出现了,myFoo但add在此示例中实际上没有方法-由final确认console.log。但是,当JS引擎无法找到该属性时,它将转到myFoo的“内部原型”,恰好是foo.prototype。这就是为什么该方法可以正常工作的原因,就像对任何使用构造的对象一样foo。
无论如何,这导致了一个事实,即可以通过调用(虽然new Array我从来没有使用new上面的运算符,但是我可以做到,在这种情况下没有区别)构造(虽然几乎从来没有)构造过的数组。因此,请委托给Array.prototype。您知道并喜欢的所有那些数组方法并不“真正”存在于您调用它们的数组上:
var a = [1,2,3];
a.push(4);
console.log(a);
console.log(a.hasOwnProperty("push"));
console.log(Array.prototype.hasOwnProperty("push"));Run Code Online (Sandbox Code Playgroud)
因此,数组方法之所以起作用,是因为这些方法实际上是在Array.prototype对象上找到的,如果在数组本身上查找不成功,则所有数组都将其委托给属性/方法访问。(这就是为什么如果您在MDN上查找它们中的任何一个,页面顶部总是显示Array.prototype.<method_name>,因为这是方法“真正”存在的地方。)
对此进行了激烈的演示(请不要在生产代码中这样做!)
// you're used to doing this, and it works:
[1,2].push(3);
console.log("that went fine");
// vandalism on a grand scale!
Array.prototype.push = undefined;
// now you can'tse the "push" method anymore!
[1,2,3].push(4);Run Code Online (Sandbox Code Playgroud)
但是我将以反高潮结束。上面的内容适用于数组方法-但lengtharray属性不是方法。如上所述,它只是一个“普通”(非函数)属性,其“神奇地”表现有点像函数调用。正如在OP中观察到的那样,.length属性访问不像上面显示的方法调用那样委派,该属性本身存在于每个数组中。
那么,为什么本身Array.prototype仍然拥有length财产?好吧,Array.prototype实际上它本身就是一个数组。实际上,这不是唯一的事情:
Array.prototype.push(1);
console.log(Array.prototype);
Function.prototype();Run Code Online (Sandbox Code Playgroud)
请注意,Array.prototype.push(1)最终以Array.prototype单例数组结束[1]。所以Array.prototype是“有点像”空数组(这是不完全一样的,因为它拥有所有这些方法上述目的本身,这是“正常的”空数组不直接访问)。并且使用Function.prototype,尽管调用它没有输出任何东西,但没有TypeError引发的事实证明它确实是一个函数(它实际上是一个“ no-op”函数,例如function() {},但又一次带有各种不同的方法-方法每个函数都可以访问的内容,例如.call和.bind。
无论如何,为了缩短题外距离,因为Array.prototype至少就普通数组属性而言,它是一个空数组,这解释了为什么它具有length属性,以及为什么它等于0。
我希望这可以使事情变得清晰,并演示一些更有趣的Javascript部分。
Disclaimer: I have tried to show how constructor and instance works in general. But in fact, they have huge difference between different constructors.
Any constructor has been set its length with the value specified by the spec. Specially most of them are set to 1:
Number.length // 1
Object.length // 1
Function.length // 1
Array.length // 1
// etc.
Run Code Online (Sandbox Code Playgroud)
Similarly,
Array.constructor.length // 1
// etc.
Run Code Online (Sandbox Code Playgroud)
Like @Kaiido pointed out in the comment, you can see some constructor length is set:
Document.length // 0
Int8Array.length // 3
Date.length // 7
Run Code Online (Sandbox Code Playgroud)
And you may also notice the length of the instance is undefined as they are not set. - It's out of the scope though.
let d = new Date
d.length === undefined // true
Run Code Online (Sandbox Code Playgroud)
See at the bottom for relevant references.
But when you have an instance of it, then you're creating a new value of it:
typeof new Array === typeof Array.prototype // true
typeof new Function === typeof Function.prototype // true
// etc.
Run Code Online (Sandbox Code Playgroud)
So, when you use an instance it has no length value set because it has no any parameters:
let arr = new Array // Array.prototype
arr.length === 0 // true
Run Code Online (Sandbox Code Playgroud)
But when you use an instance with parameter, then you have the length property with the value of parameters
let arr = new Array(20)
arr.length === 20 // true
let func = function(a1,a2,a3,a4){}
func.length === 4 // true
// etc.
Run Code Online (Sandbox Code Playgroud)
So now, you have been wondering why the constructor has length value equal to 1?
It's because the spec has set the value to be 1 initially.
Every built-in Function object, including constructors, has a length property whose value is an integer. Unless otherwise specified, this value is equal to the largest number of named arguments shown in the subclause headings for the function description, including optional parameters.
The value of the [[Prototype]] internal slot of the Object constructor is the intrinsic object %FunctionPrototype%.
Besides the length property (whose value is 1),
See these references:
19.1.2 Properties of the Object Constructor,
19.2.2 Properties of the Function Constructor,
etc.
Also, you can see the prototype has length to 0, you already know it why in the preceding example.
Though, here's just a reference stating that:
19.2.3 Properties of the Function Prototype Object
And there some constructor whose length is set different. This is the out of scope of this answer. Though, here's a reference for the date constructor:
20.3.3 Properties of the Date Constructor
So, it's totally up to the spec how they have been defined.
Array是构造函数,表示其类型为"function"。您尝试检查控制台。
typeof Array //"function"
Run Code Online (Sandbox Code Playgroud)
根据MDN
该
length属性指示所需的参数数量function。
由于Array函数需要单个参数,因此Array.length = 0
作为
length类型实例的对象的属性Array设置或返回该数组中元素的数量
众所周知,数组实际上是对象,因此对象可以具有属性。该属性length位于数组的实例上。
现在,您可能会问第二个问题,为什么我们不length使用Object.keysor for..in循环获得数组的属性。答案是因为此属性不是Enumerable。
typeof Array //"function"
Run Code Online (Sandbox Code Playgroud)
根据DOCS
的初始值
Array.prototype.constructor是标准内置Array的Array原型对象本身是一个数组;它[[Class]]是“ Array”,并且具有length属性(其初始值为+0)构造函数
其实Array.prototype是一个数组。并记住数组始终是对象。因此它可以具有属性。Array的方法以的形式存储key:value。并且该数组中没有元素,因此它Array.prototype.length返回0。如果您在push()其中添加了一些元素,则将其视为数组。
let arr= [];
//this.property 'length2' will not be shown in for..in or Object.keys();
Object.defineProperty(arr,'length2',{
value:'length2 for test',
enumerable:false
})
//this property 'x' will be displayed in for..in loop and Object.keys()
Object.defineProperty(arr,'x',{
value:'length2 for test',
enumerable:true
})
console.log(Object.keys(arr)); //["x"]Run Code Online (Sandbox Code Playgroud)
正如我在第二部分中所述,您可以Object通过设置隐藏属性enumerable:false。所有方法都是Array.prototypeBut的键,但是现在for..in循环显示。
| 归档时间: |
|
| 查看次数: |
878 次 |
| 最近记录: |