在JavaScript while循环中使用“未定义”作为哨兵是否安全?

时间:2019-06-08 21:01:30

标签: javascript arrays while-loop sentinel

在Javascript中使用这种循环是否安全?

denseArray = [1,2,3,4,5, '...', 99999]

var x, i = 0
while (x = denseArray[i++]) {
    document.write(x + '<br>')  
    console.log(x)  
}

document.write('Used sentinel: ' + denseArray[i])
document.write('Size of array: ' + i)  
 

使用内置的哨兵,它比for循环要短,并且对于大型阵列也可能更有效。 sentinel 将呼叫者标记为发生了不寻常的事情

该数组必须是dense array才能起作用!这意味着没有其他 undefined 值,除了数组中最后一个元素之后的值。我几乎从不使用稀疏数组,而仅使用密集数组,所以对我来说没关系。

要记住的另一个更重要的要点(感谢@Jack Bashford提醒)是,这不仅是未定义为哨兵。如果数组值为0,false或其他任何伪造的值,则循环将停止。因此,您必须确保数组中的数据没有0""'',``,null,{ {1}}和undefined

这里是否存在“超出范围”的问题,或者我们可以将Javascript中的数组视为“无限”(如果内存不满)? 未定义意味着浏览器可以将其设置为任何值,因为它是未定义的,还是我们可以认为条件测试始终有效? Javascript中的数组很奇怪,因为“它们是对象”,所以最好问一下。

我无法使用以下标签在Stackoverflow上找到答案:NaN结果为零

我已经考虑了一段时间,并用了足够多的时间开始担心。但我要使用它,因为它美观大方,易于查看,简短,在大数据中可能有效。 [javascript] [sentinel] [while-loop] [arrays]是数组的大小很有用。

更新

  • @Barmar告诉: JS保证未初始化的数组 元素将返回未定义的值。
  • falsy values使用 无效的索引号返回未定义。
  • @ schu34的注释:最好使用经过i优化且已为开发人员使用的denseArray.forEach((x)=>{...code})。无需遇到虚假的价值观。它有MDN confirms

2 个答案:

答案 0 :(得分:1)

即使以后您的代码不会被其他人查看,最好还是使其更具可读性和组织性。条件测试中的值分配(递增和递减运算符除外)通常不是一个好主意。

您的检查也需要更加具体,因为[0, '']都为假。

denseArray = [1,2,3,4,5, '...', 99999]

for(let i = 0; i < denseArray.length; i++) {
  let x = denseArray[i]
  document.write(x + '<br>');
  console.log(x);
  if (/* check bad value */) break;
}

document.write('Used sentinel: ' + denseArray[i])
document.write('Size of array: ' + i)  

根据我的经验,如果以可读性甚至可靠性为代价,那么节省几行代码通常是不值得的。

编辑:这是我用来测试速度的代码

const arr = [];
let i;

for (i = 0; i < 30000000; i++) arr.push(i.toString());

let x;

let start = new Date();

for(i = 0; i < arr.length; i++) {
  x = arr[i];
  if (typeof x !== 'string') break;
}

console.log('A');
console.log(new Date().getTime() - start.getTime());

start = new Date();

i = 0;
while (x = arr[i++]) {
}

console.log('B');
console.log(new Date().getTime() -start.getTime());

start = new Date();

for(i = 0; i < arr.length; i++) {
  x = arr[i];
  if (typeof x !== 'string') break;
}

console.log('A');
console.log(new Date().getTime() - start.getTime());

start = new Date();

i = 0;
while (x = arr[i++]) {
}

console.log('B');
console.log(new Date().getTime() -start.getTime());


start = new Date();

for(i = 0; i < arr.length; i++) {
  x = arr[i];
  if (typeof x !== 'string') break;
}

console.log('A');
console.log(new Date().getTime() - start.getTime());

start = new Date();

i = 0;
while (x = arr[i++]) {
}

console.log('B');
console.log(new Date().getTime() -start.getTime());

for循环甚至还有一个额外的if语句来检查错误的值,并且仍然更快。

答案 1 :(得分:0)

搜索ScrollView会得到结果:

意见从it looks like a common error where you try to compare valuesIf there is quirkiness in all of this, it's the for statement's wholesale divergence from the language's normal syntax不等。 javascript assignment in while是添加冗余的语法糖。它尚未与for一起过时while

首先要考虑的问题是它是否安全。 MDN在数组中说:Using an invalid index number returns undefined,所以使用起来很安全。在有条件的情况下对作业进行测试是安全的。可以同时完成多个分配,但是带有if-gotovarlet的声明不会像assign do那样返回,因此该声明必须在条件之外。敬请发表评论,以日后向其他人或您自己解释,数组必须保持密集且没有虚假的值,否则它可能会出错

要允许constfalse0(除""以外的任何虚假名称),然后将其扩展为:undefined,但它并不比普通数组长度比较。

有用吗? Yes

while ((x = denseArray[i++]) !== undefined) ...

否则必须写

while( var = GetNext() )
{
  ...do something with var 
}

通常,最好使用开发人员熟知的var = GetNext(); while( var ) { ...do something var = GetNext(); } 。无需考虑虚假的价值观。它有good browser support但是,它很慢!

I made a jsperf显示 forEach比白名单慢了60%!测试还显示,在我的计算机上denseArray.forEach((x) => { ... })for快一点!另请参阅@Albert答案以及测试结果,显示 for的速度比while稍快

使用while是安全的,它可能并非没有错误。在编码时,您可能知道您的数据,但是您不知道是否有人复制粘贴该代码以用于其他数据。