为什么JavaScript不会为此代码示例抛出异常?

时间:2017-02-27 20:53:26

标签: javascript arrays exception indexoutofboundsexception

我希望人们会原谅我一个相当基本的JavaScript问题(对我而言,它通常不是#34;主要的#34;语言)。我正在研究W3Schools的JavaScript教程以供审查;他们的lesson on arrays有以下警告和代码示例:

  

警告:添加具有高索引的元素可能会创建未定义的"空洞"在数组中:

var fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits[6] = "Lemon"; // adds a new element (Lemon) to fruits

这将导致索引4和5包含undefined

此外,我可以做一些像alert(fruits[20]);(它给我一个弹出式提示"未定义")毫无例外。

在大多数对键入更严格的语言中,尝试执行这些操作中的任何一个都会导致运行时异常。我确实意识到我们这里没有人在JavaScript设计委员会(据我所知),但有谁知道为什么这些被允许(即为什么他们不会抛出运行时异常或类似的东西)?< / p>

我可以理解做fruits[4] = "Lemon"之类的事情的目的(因为它基本上附加到数组中),但是有没有正当理由去做fruits[6] = "Lemon"之类的事情?

似乎做alert(fruits[20]);之类的事情几乎总是表示错误 - 我实际上无法想到它的任何合法用例。这是对的吗?

我对this question的答案的理解是,JavaScript数组&#34;实际上更像是使用属性作为索引的自定义对象&#34;比起Java或C#中的数组。其中一个答案还说明了

  

Javascript数组不是像C / C ++或其他语言那样的真正数组。因此,它们并不具有效率,但它们可以说更容易使用,并且不会抛出异常的例外。

这些陈述是否正确?这是JavaScript中这种行为的原因吗?

4 个答案:

答案 0 :(得分:2)

Javascript不会将不存在的数组元素和对象属性视为错误。当代码尝试访问时,它只返回function validateForm() { var valid = true; document.getElementById("activityName").innerHTML = ""; document.getElementById("reporter").innerHTML = ""; var x = document.forms["myForm"]["activityName"].value; if (x == "" || x == null) { document.getElementById("activityName").innerHTML = "Please Enter Activity Name"; valid= false; } var r = document.forms["myForm"]["reporter"].value; if (r == "") { document.getElementById("reporter").innerHTML = "Please Enter Reporter"; valid = false; } return valid; }

一些常见的习语利用了这一点。你可以写:

undefined

由于var fruit20 = fruits[20] || defaultFruit; 是假的,当它不存在时它将返回undefined。这比以下更简单:

defaultFruit

通常,您会从尝试使用结果值的代码中收到错误。例如,如果你这样做:

var fruit20 = '20' in fruits ? fruits[20] : defaultFruit;

由于尝试访问var firstLetter = fruits[20].substr(0, 1); 的{​​{1}}属性,它会发出异常信号,因为substr没有任何属性。

答案 1 :(得分:2)

用C语言或其他语言用&#34; true&#34;数组(即连续内存中的指针序列),越界写入可能会破坏正在运行的程序甚至是另一个进程。

JavaScript Array可以动态调整大小,因此不存在非法访问或损坏的风险。

作为规则,JavaScript只会在没有替代方法时抛出运行时异常。在这种情况下,有一种替代方案 - 动态调整数组的大小 - 所以它更倾向于抛出。

答案 2 :(得分:2)

我看到你说它不是你的主要语言...所以我会与c ++进行比较

在c ++中你声明了一部分内存:int a[50]; //系统为我们提供50 * sizeof(int)的一部分,我们可以在那里做我们想要的。 a是指向第一个int

的指针

例如:cout<<a[20]; //将返回存储器中的变量,它是我们的内存部分,即使我们没有提前设置它。 cout<<a[51] //错误...为什么?...因为该程序会尝试访问我们没有访问权限的地址(或操作系统未授权);

你可以在js中执行:console.dir(fruits); ......你会在那里看到很多功能......甚至是&#34;长度&#34;您在水果中没有说过设置长度属性的属性吗?... js中的基本数组是c ++中的类

在c ++中引用数组时,指的是指针A的内存+数组类型的大小:

示例:cout<<*A; //与cout<<A[0]; or cout<<*(A+0);相同 cout<<*(A+5); //与cout<<A[5];

相同

A [5] = *(A + 5)= *(5 + A)= 5 [A]

所以

for(int i=0; i<n; i++)
   cout<<i[A];

//与cout<<A[i]相同......疯了吗?

答案 3 :(得分:2)

在回答你的问题时,先做一个演示:

&#13;
&#13;
var a = [];
console.log( "initial length is: " + a.length);

a[1.5] = 1.5
console.log( "a[1.5] is " + a[1.5] + ", length is " + a.length);

a["foo"] = "bar";
console.log( "a.foo is " + a.foo + ", length is " + a.length);

a[-1] = -1;
console.log( "a[-1] is " + a[-1] + ", length is " + a.length);

a[10] = "item 10";
console.log( "a[10] is " + a[10] + ", length is " + a.length);

a[20] = "item 20";
console.log( 'a[ 20 ] is ' + a[ 20 ] + ", length is " + a.length);
console.log( 'a["20"] is ' + a["20"] + ", length is " + a.length);
console.log( 'a["0x14"] is ' + a["0x14"]);
console.log( "a.hasOwnProperty( 20) " + a.hasOwnProperty( 20));

console.log( "a[ 15] " + a[ 15]);
console.log( "a.hasOwnProperty( 15) " + a.hasOwnProperty( 15));
a[15] = undefined;
console.log( "a[ 15] " + a[ 15]);
console.log( "a.hasOwnProperty( 15) " + a.hasOwnProperty( 15));
&#13;
&#13;
&#13;

  • JavaScript中的数组被视为异域对象。它们表现为普通对象,除非使用非负整数数值设置属性。
  • 数组由全局Array构造函数构建,并从Array.prototype继承方法。
  • 长度属性保持为比数组中包含的最高非负整数属性多一个(这是异国情调的部分)。
  • 元素的索引和值都存储在数组中。数字索引转换为基数10格式的字符串值,用作元素的(对象)属性名称。虽然代码不常见,但您可以将a[20]引用为a["20"]。您不能引用与a["0x14"]相同的元素,因为属性字符串名称&#34; 0x14&#34;不存在。
  • &#34; hole&#34;的技术名称和数组在它是&#34;稀疏阵列&#34;。
  • 稀疏数组不包含缺失元素的undefined值。尝试查找不存在的元素时返回undefined。 (这与查找不存在的对象属性时的行为相同。)
  • 由于undefined是原始值,因此您可以将数组元素设置为undefined。该元素现在存在而不是被发现。
  • 为什么调用JavaScript数组&#34; associative&#34;是他们没有为尚未设置的数组内容保留内存。当访问具有有效数字索引的元素时,他们必须搜索属性名称列表可能,而不是说可能是什么类型的搜索。