本文翻译自《Little known features of JavaScript》javascript
人们一般认为 JavaScript 是一门很容易上手的语言,可是要作到精通却不简单。是的,这是由于 JavaScript 是一种很是古老且很是灵活的语言。它充满了神秘的语法和过期的功能。到目前为止,我已经使用 JavaScript 多年了,可是仍是时不时就会发现一些我不知道的隐藏语法或技巧。java
我试图列出一些不为人知的JavaScript功能。尽管其中一些功能在严格模式下无效,但它们仍然是彻底有效的JavaScript代码。可是请注意,我不建议您开始使用全部这些功能。尽管它们绝对酷,但若是您开始使用它们,颇有可能会让你的队友很生气。node
此处提供了全部使用的源代码。Happy Coding!git
注意:本文并不包括诸如提高(Hoisting),闭包,代理,原型继承,async-await,生成器之类的东西。虽然这些功能可能不被大部分人所了解,但它们仍然是众所周知的。github
JavaScript 具备一元void运算符。您可能已经看到它用做void(0)
或void 0
。它的生命中只有一个目标——在表达式的正确位置返回**undefined**
。使用“0”只是一个约定。您不必定必须使用“ 0”,它能够是任何有效的表达式void
,而且仍返回**undefined
。**web
为何创造了一个特殊的关键字来返回 undefined 而不是直接返回 undefined呢?express
听起来好像有一点冗余对吧?c#
🚩 趣闻数组
好吧,事实证实,在ES5以前,您实际上能够在大多数浏览器中为原始的 undefined 分配一个新值,像是 undefined =“ abc”。浏览器
定义 undefined?!
所以在那个时候,使用 void 是确保您始终返回原始 undefined 的一种方法。
是的,在调用构造函数时,咱们在类名后添加的括号是彻底可选的!😮(前提是您不须要将任何参数传递给构造函数)
如下两种代码样式均被视为有效的 JS 语法,而且结果是相同的!
对于我来讲,IIFE(当即调用功能表达式)的语法老是有点奇怪。
那些括号我到底应该怎么用?
事实证实,这些额外的括号仅仅是为了告诉 JavaScript 解析器即将发布的代码是函数表达式,而不是函数。能够想象,知道了这一点,有不少方法能够跳过那些多余的括号,而且仍然能够制做出有效的IIFE。
void
运算符告诉解析器代码是函数表达式。所以,咱们能够跳过函数定义的括号。你猜怎么着?咱们可使用任何一元运算符(void
,+,!,-等)来让它奏效!
太酷了!
可是,若是您是一个敏锐的观察者,您可能会想,
一元运算符不会影响IIFE返回的任何结果吗?
好吧,这会影响结果。可是,好消息是,若是您关心结果并说要将其存储在某个变量中,那么首先就不须要多余的括号。
确实如此!
咱们添加这些括号只是为了提升人类可读性。
想要了解有关IIFE结账的更多信息,能够去看看 Chandra Gundamaraju的这篇很酷的文章
您知道吗,JavaScript有一个with
语句块?实际上它是JS中的关键字。编写with
块的语法以下:
with (object)
statement
// for multiple statements add a block
with (object) {
statement
statement
...
}
复制代码
with
把传入的对象的全部属性添加到当前做用域链中:
🚩趣闻
with听起来很是酷,对吧?它甚至比对象解构更好。
好吧,不是这样的。
一般不建议使用with语句,由于它已被弃用。在严格模式下彻底禁止这样作。事实证实,使用块会增长该语言的性能和安全性问题!
译者注:
不建议使用
with
,由于with
语句将对象的成员添加到当前做用域,从而没法说出块内的变量实际指的是什么。因为难以调试和读取这些类型的功能,所以许多人认为这是一种很差的作法,能够参考如下信息了解更多:
https://eslint.org/docs/rules/no-with
https://eslint.org/docs/rules/no-new-func#disallow-function-constructor-no-new-func
函数声明不是定义新函数的惟一方法;您可使用Function()
构造函数以及new
运算符动态地定义函数。
最后一个构造函数参数是函数的字符串化代码以及以前的其余参数为函数参数。
🚩趣闻
Function
构造函数是 JavaScript 中全部构造函数的母亲。甚至Object
的构造函数都是Function
构造函数。Function
本身的构造函数也是Function
自己。所以,调用object.constructor.constructor ...
足够的次数最终将返回JavaScript中任何对象上的Function
构造函数。
众所周知,函数是JavaScript中的「一等公民」。所以,没有人阻止咱们向函数添加自定义属性。这在JS中是彻底正确的事情。可是,它不多使用。
那么咱们何时想要这样作呢?
嗯,有一些很好的用例。例如:
假设咱们有一个叫作greet
的函数。咱们但愿咱们的函数根据不一样的语言环境打印不一样的问候消息。此语言环境也应该是可配置的。咱们能够在某个地方维护全局语言环境变量,也可使用以下所示的函数属性来实现函数:
另外一个相似的例子。假设您要实现一个数字生成器——该数字生成器生成一系列有序数字。一般,您将使用带有静态的counter
变量的类或IIFE来跟踪上一个值。这样,咱们能够限制访问counter
,还能够避免因额外的变量污染全局空间。
可是,若是咱们想灵活地读取甚至修改计数器而又不污染全局空间怎么办?
是的,咱们仍然能够建立一个类,它带有counter
变量和一些其余读取counter
的方法;或者咱们偷个懒,只在函数上使用属性。
这是一个很长的 list,咱们刚刚写了一半。若是您想休息一下,如今是个好时机。若是您要继续看下去,好吧,我向您致敬!
让咱们继续!
我敢确定大家大多数人都知道函数内的arguments
对象。它是一个数组,相似于对象,能够在全部函数中使用。它具备在调用时传递给函数的参数列表。可是它还具备其余一些有趣的特性,
arguments.callee
:引用当前调用的函数
arguments.callee.caller
:引用已调用当前函数的函数
注意:尽管ES5禁止在严格模式下使用
callee
和caller
,但在许多已编译的库中仍然很常见。所以,值得学习。
除非您与世隔绝,不然您确定据说过模版字符串。模版字符串是ES6提供的许多不错的功能之一。可是,您知道标记模版字符串吗?
带有标记的模板字符串能够经过向模板字符串添加自定义标记,来更好地控制将模板字符串解析为字符串的过程。Tag只是一个解析器函数,它获取由字符串模板解释的全部字符串和值的数组,并返回最终字符串。
在下面的示例中,咱们的自定义标签highlight
解释模板字符串的值,而且还将解释后的值使用<mark>
元素包装在结果字符串中以突出显示。
在许多库均可以发现一些有趣的用例是利用此功能来实现的。
如下是一些很酷的例子,
React styled-components es2015-i18n-tag 用于翻译和国际化 chalk 用于彩色的 log
在大多数状况下,JavaScript对象很简单。假设咱们有一个user
对象,并尝试使用user.age
访问其年龄属性,若是定义了年龄属性,咱们将得到年龄属性的值;不然,将得到未定义属性。简单。
可是,能够没必要这么简单。JavaScript对象具备Getter
和Setter
的概念。能够直接编写自定义Getter
函数以返回所需的任何内容,而不是直接返回对象的值。设置值也同样。
这使咱们在获取或设置字段时拥有虚拟字段,字段验证,反作用等强大的能力。
Getters
和Setters
在 ES5 中不是新增功能。他们一直在那里。ES5 只是在现有功能中添加了方便的语法。要了解有关Getters&Setters
的更多信息,请参阅这篇不错的[文章]( nice article)
Colors 是一个流行的node.js库,它是利用Getters的一个很好的例子。
该库扩展了String类,并在其上添加了一堆Getter方法。这使咱们可以经过简单地访问其属性,将任何字符串转换为其彩色版本,以便于打印。
JavaScript 具备逗号运算符。它容许咱们在一行中编写多个用逗号分隔的表达式,并返回最后一个表达式的结果
// syntax
let result = expression1, expression2,... expressionN
复制代码
在上面的代码中,将对全部表达式进行求值,并将对expressionN
返回的值赋值给result
变量。
您可能已经在for
循环中使用了逗号运算符:
for (var a = 0, b = 10; a <= 10; a++, b--)
复制代码
有时它能够用来帮助咱们在同一行中写多个语句:
function getNextValue() {
return counter++, console.log(counter), counter
}
复制代码
或者写短的lamda
函数:
const getSquare = x => (console.log (x), x * x)
复制代码
你是否曾经遇到过须要将字符串快速转换为数字的场景?
只需在字符串前面加上+运算符便可。
加号运算符还适用于负,八进制,十六进制,指数值。并且,它甚至能够将Date
或Moment.js
对象转换为时间戳!
好的,从技术上讲,它不是独立的 JavaScript 运算符。只是把 JavaScript 否认运算符使用了两次。
可是Bang Bang(!!)听起来很酷!Bang Bang或Double Bang是将全部表达式转换为布尔值的巧妙技巧。
若是表达式是 truthy 的值,则返回 true;不然返回 false。
面对现实吧——没人在意按位运算符。咱们何时才能使用它!
好吧,按位非(~)运算符天天都有用例。
事实证实,当与数字一块儿使用时,按位非运算符才有效。好比:〜N =>-(N + 1)
。仅当N == -1
时,此表达式的计算结果才为“ 0”。
咱们能够经过将〜
放在indexOf(...)
函数前面来检查某一项是否存在于一个字符串或者数组中:
注意:ES6和ES7分别在
String
和Array中添加了一个新的.includes()
方法。无疑,这是一种比~运算符更简洁的方法来检查数组或字符串中是否存在项。
JavaScript 具备label
语句的概念。它容许咱们在 JavaScript 中命名循环和块。而后,咱们能够在之后使用break
或continue
时使用这些标签来引用代码。
带标签的语句在嵌套循环中特别方便。可是咱们也可使用它们将代码简单地组织成块或建立可退出的块。
注意:与其余某些语言不一样,JavaScript没有goto构造。所以,咱们只能使用带有break和continue的标签。
若是你还有一些 JavaScript 中不为人知的用法,能够在评论里分享您的经验~