当我在循环中使用arr.lenght(misspelt)而不是arr.length时,为什么JavaScript不警告我?我也使用严格模式

Man*_*ato 64 javascript

我花了几个小时,只是找出我拼错字.length作为.lenght.它可以正常运行,完全没有警告.为什么...?

'use strict'在Node.js 10.13.0上使用并运行.

码:

'use strict';
let arr = [1, 2, 3, 4];
for(let i = 0; i < arr.lenght; i++) {
  console.log(arr[i]);
}
Run Code Online (Sandbox Code Playgroud)

eag*_*845 72

因为当你试图获得一个不存在的属性时,它会返回undefined,并且0 < undefinedfalse.

let arr = [1, 2, 3, 4];
console.log(arr.lenght) // undefined
console.log(arr.qwerty) // undefined
console.log(arr.lenght < 9999) // false
console.log(arr.lenght > 9999) // false

arr.length = 7 // <-- it's not a good idea
for(let i = 0; i < arr.length; i++) {console.log(arr[i])}
Run Code Online (Sandbox Code Playgroud)

编辑

我说'javascript不是强类型语言',这是真的.但正如@Voo所说,这种添加新属性的方式是基于原型的编程的一个特性.

我还说.length=7这是一个坏主意.在阅读了一点之后,在这种情况下,我仍然认为length在添加元素后增加属性有点奇怪.也许可以截断,删除元素或清空一个数组,尽管在后一种情况下我更愿意arr=[]而不是arr.length=0.

Mozilla文档中有一些有关length属性的有趣示例.

JavaScript数组的长度属性和数字属性是连接的.几个内置数组方法(例如,join(),slice(),indexOf()等)在调用时考虑了数组长度属性的值.其他方法(例如,push(),splice()等)也会导致更新数组的length属性.

var fruits = [];
fruits.push('banana', 'apple', 'peach');
console.log(fruits.length); // 3
Run Code Online (Sandbox Code Playgroud)

当属性是有效的数组索引并且该索引超出数组的当前边界时,在JavaScript数组上设置属性时,引擎将相应地更新数组的length属性:

fruits[5] = 'mango';
console.log(fruits[5]); // 'mango'
console.log(Object.keys(fruits));  // ['0', '1', '2', '5']
console.log(fruits.length); // 6
Run Code Online (Sandbox Code Playgroud)

增加长度.

fruits.length = 10;
console.log(Object.keys(fruits)); // ['0', '1', '2', '5']
console.log(fruits.length); // 10
Run Code Online (Sandbox Code Playgroud)

但是,减小length属性会删除元素.

fruits.length = 2;
console.log(Object.keys(fruits)); // ['0', '1']
console.log(fruits.length); // 2
Run Code Online (Sandbox Code Playgroud)

  • @ GOTO0是的,你刚刚总结了我对开发世界在过去几年中对JavaScript的讨厌方式的讽刺意味,同时又厌恶PHP. (8认同)
  • PHP也不是强类型语言,但是当您访问不存在的属性时,它会向您发出警告.另一方面,JavaScript没有生成运行时警告的标准方法. (5认同)
  • 设置数组的`.length`是一个非常普遍的想法,它没有任何问题. (4认同)
  • @JacobRaihle To [empty](/sf/ask/86242831/),否则截断,或(很少)预先分配它. (3认同)
  • 无论您是否在访问不存在的属性时遇到错误,如果语言是强类型的,则无需执行任何操作.这更像是基于原型的OOP语言的一个特性. (3认同)

Roh*_*har 14

JavaScript数组被视为对象(尽管它们是Array的实例).因此,当您编写时arr.lenght,它将视为lenght未定义的对象的属性.因此,您不会收到错误.

它只是试图获得一个未定义的属性.此外,在您的情况下,循环只是不执行,因为循环的条件永远不会满足.


T.J*_*der 8

为什么

标准JavaScript数组根本不是真正的数组,它们是对象,如果你读取了一个不存在的对象属性(比如lenght),你就得到了值undefined(即使在严格模式下):

console.log(({}).foo); // undefined
Run Code Online (Sandbox Code Playgroud)

当您undefined在与数字一起使用<>与数字一起使用的关系操作中,它会转换为数字,但它获得的数字值是特殊数字NaN,它具有始终导致比较为假的奇怪属性:

console.log(NaN < 0);     // false
console.log(NaN > 0);     // false
console.log(NaN === 0);   // false
console.log(NaN === NaN); // false!!
Run Code Online (Sandbox Code Playgroud)

你可以做些什么呢

在简单的情况下,Linter工具通常会选择这些东西.

或者,TypeScript在JavaScript之上提供了一个完整的静态类型,可以捕获这些类型的错误.

如果你想(这很可能是矫枉过正),你可以换一个代理在你的对象,当你试图读取并不存在的属性,它扔了积极的错误:

function proactive(obj) {
  return new Proxy(obj, {
    get(target, propName, receiver) {
      if (!Reflect.has(target, propName)) {
        throw new TypeError(`Property '${propName}' not found on object`);
      }
      return Reflect.get(target, propName, receiver);
    }
  });
}

const a = proactive(["a", "b"]);
a.push("c");
for (let i = 0; i < a.length; ++i) {
  console.log(a[i]);
}
console.log(`Length is: ${a.lenght}`); // Note the typo
Run Code Online (Sandbox Code Playgroud)
.as-console-wrapper {
  max-height: 100% !important;
}
Run Code Online (Sandbox Code Playgroud)

但是,有一个重要的运行时惩罚.


¹ (这是我贫血的小博客上的帖子)


mmo*_*oya 6

您可以轻松地向arr对象添加新属性,JavaScript不会向您发出警告,而是会尝试查找您正在调用的属性,如果它没有找到任何此类结果将是未定义的,那么比较实际上是i < undefined每次因为您正在调用尚未在对象上创建的属性.我建议你阅读JavaScript中的"use strict"做什么,背后的原因是什么?.


fuz*_*uzz 5

循环的上限被指定为lenght局部变量长度的拼写错误.在运行时,lenght将评估为undefined,所以检查0 < undefinedfalse.因此,循环体永远不会被执行.

  • 没有回答这个问题 (5认同)