原文: The JavaScript `in` Operator Explained With Examples

在学习 JavaScript(或任何其他编程语言)时,你首先会遇到的话题之一是运算符。

最常见的运算符是算术、逻辑和比较运算符。但是你知道 JavaScript 有一个 in 运算符吗?

如果你不知道,不要着急。我最近在谷歌上搜索一个问题的解决方案时才发现了它。

在这篇文章中,你将了解到 JavaScript in 运算符的确切作用、何时使用它,以及如何使用它。

JavaScript in 操作符是什么

JavaScript in 操作符用于检查一个对象或其继承的属性(换句话说,它的原型链)中是否存在一个指定的属性。如果指定的属性存在,in 操作符返回 true

const-linda-----name_--Linda---job_--frontend-developer---
剖析一个简单的 JavaScript 对象

JavaScript 原型链是实现对象或对象实例访问原本不属于它们的属性和方法。这些对象继承了在其构造函数或原型中定义的属性和方法,可以通过它们的 __proto__ 属性来访问。

本文假设你对什么是对象、如何创建对象、它们的用途以及 JavaScript 的继承如何运行有基本的了解。如果你不知道,MDN 上的这篇文章应该会有帮助。(译者注:也可以参考 freeCodeCamp 专栏的这篇文章。)

什么时候使用 JavaScript in 操作符

为了验证一个对象是否存在一个属性

const car = {
  make: 'Toyota',
  model:'Camry',
  year: '2018',
  start: function() {
    console.log(`Starting ${this.make} ${this.model}, ${this.year}`);
  }
}

'make' in car // 返回 true.
'start' in car // 返回 true.
'Toyota' in car // 返回 false. 'Toyota' 不是一个属性名称,而是一个值

为了验证一个属性是否被一个对象所继承

让我们使用 ES6 class 语法来构造对象。这也适用于构造函数:

class Car {
  constructor(make, model, year) {
    this.make = make;
    this.model = model;
    this.year = year;
  }
  start() {
    console.log(`Starting ${this.make} ${this.model}, ${this.year}`);
  }
}

const toyota = new Car('Toyota', 'Camry', '2018');

'start' in toyota;
/* 返回 true,因为 toyota 是 Car 对象构造函数的一个实例。因此,toyota 对象继承了 Car 构造函数的所有属性。*/

'toString' in toyota;
/* 返回 true。toString 是 Object 类型的一个方法属性,Car 构造函数是该类型的一个实例。*/

验证一个数组上是否存在一个索引/键

你可能想知道,既然我们确定了 JavaScript in 操作符可以用于对象,我们是否也可以将其用于数组呢?

嗯,数组实际上是 Object 类型的一个原型(实例)。事实上,JavaScript 中的所有东西都是 Object 类型的一个实例。

这听起来很疯狂,但让我们在浏览器的控制台中运行一个简单的程序来确认。

首先,定义一个数组,用 instanceof 操作符确认它是否是 Object 类型的实例:

const number = [2, 3, 4, 5];

number instanceof Object // 返回 true

理解了吗?在控制台中输入 number 并按回车键,然后打开输出。

你会注意到一个属性列表,其中一个是 __proto__,指向 Array。把它打开,然后往下看,我们会看到另一个 __proto__ 属性,其值为 Object

这表明 number 数组是一个 Array 类型的实例,而 Array 类型是一个 Object 类型的实例。

现在,回到使用 in 操作符的问题上:

const number = [2, 3, 4, 5];

3 in number // 返回 true.
2 in number // 返回 true.

5 in number // 返回 false,因为 5 不是数组上现有的索引,而是一个值;

'filter' in number
/* 返回 true,因为 filter 是 Array 类型的方法属性,number 数组是其实例。number 数组继承了 filter 属性。*/

验证一个 HTML 元素上是否存在一个属性

在 Kirupa 的文章《检查你是否在一个支持触摸的设备上》中,他强调了这个功能:

function isTouchSupported() {
  var msTouchEnabled = window.navigator.msMaxTouchPoints;
  var generalTouchEnabled = "ontouchstart" in document.createElement("div");

  if (msTouchEnabled || generalTouchEnabled) {
    return true;
  }
  return false;
}

通过检查 window.navigator.msMaxTouchPointsontouchstart 属性是否存在,如果你在一个支持触摸的设备上,该函数返回 true;如果你在一个不支持触摸的设备上,则返回 false。这些属性只存在于支持触摸的设备上。

相当简单明了!

让我们把注意力集中在强调的那一行。还记得我们是如何确定,如果指定的属性存在于一个对象中,in 操作符就会返回 true 吗?在 JavaScript 中使用的 HTML 元素实际上成为 Object 类型的实例,因此被称为“文档对象模型”或 DOM。

当然,如果没有某种证明,你可能不会相信我。像以前一样,让我们在控制台中输入一些命令。

创建一个 div 元素,用 console.dir() 列出其属性:

const element = document.createElement('div');

console.dir(element);

然后你会看到控制台中列出 div 元素及其属性。

打开下拉菜单,你会注意到它有一个 __proto__ 属性是 HtmlDivElement。打开它,你会发现另一个 __proto__  属性是 HtmlElement,然后是 ElementNodeEventtarget,最后是 Object

并运行:

element instanceof Object

这将返回 true,表明 div 元素是 Object 类型的一个实例,这就是为什么可以对其使用 in 操作符。

总结

你已经了解了不太流行的 JavaScript in 操作符,它被用来验证对象或 Object 类型实例上的属性是否存在。这在编写验证逻辑时应该会很方便。

如果你喜欢这篇文章,你一定会喜欢我博客 codewithlinda.com 上的其他文章。在那里,我发布了对初学者友好的关于前端开发的文章。