
1、逗号运算符
,
是用于分隔表达式并返回链中最后一个表达式的运算符。javascript
let oo = (1, 2, 3)
console.log(oo) // 3
这里有三个主要表达式 1
、 2
和 3
。全部这些表达式均被求值,最后一个赋给 oo。java
咱们在 for 循环中看到这个:c++
for(let i = 0, ii = 1; i< 10; i++, ii--) { ... }
当咱们要编写短的 lambda 函数时,这会派上用场:web
const lb = (a, b, arr) => (arr.push(a*b), a*b)
这里有两个语句,第一个将乘法结果推入数组arr,第二个将乘数a和b推入数组。第二个结果就是返回给调用者的内容。编程
对于三元运算符,它也颇有用,由于与短lambda语法相同,它仅接受表达式而不是语句。数组
2、in
in 是用于检查对象中属性是否存在的关键字。咱们在 for..in
循环中使用了它,但没有意识到,其实 in
也是一个关键字:)安全
若是对象上存在属性,则 in
将返回 true
,不然将返回 false
。微信
const o = {
prop: 1
}
console.log("prop" in o) // true
看,in
能够独立使用,而不是在 for..in
中。编程语言
它将检查 "prop"
是否可做为 o
对象中的属性使用。它返回 true
,由于咱们在 o
中定义了 "prop"
属性。函数
若是咱们检查未定义的属性:
const o = {
prop: 1
}
console.log("prop1" in o) // false
它返回 false
,由于 "prop1"
在 o
中未定义。
3、Array 构造函数
你知道咱们能够不使用传统方法定义数组吗?
const arr = [1, 2, 3]
怎么样?
咱们也可使用 Array
:
const arr = new Array(1, 2, 3)
传递给 Array
构造函数的参数的排列将构成其索引的基础。
1
是第一个参数,其索引为 0;2
是第二个参数,其索引为 1;3
是第三个参数,其索引为 2。
arr[0] // 1
arr[1] // 2
arr[2] // 3
因此,
const arr = new Array(1, 2, 3)
和
const arr = [1, 2, 3]
表达的是一个意思。
但使用 new Array()
有一个问题,例如:
var a = new Array(10, 20);
a[0] // 返回 10
a.length // 返回 2
但:
var a = new Array(10);
a[0] // 返回 undefined
a.length // 返回 10
当你仅给 Array
构造函数一个整数(大于等于 0 的整数,不然将会报错)时,才会发生这种状况。这是为何喃?
其实,新的 Array
构造函数正在从某些编程语言中提取思想,在这些语言中,你须要为数组指定内存,这样就不会出现 ArrayIndexOutOfBounds
异常。
int *a = (int *) malloc( 10*sizeof(int) ); // ya ol' c
int *a = new int[10]; // c++
int[] a = new int[10]; // java
是的,它其实是在建立一个长度为 10
的数组。咱们在 Javascript
中没有 sizeof
函数,可是 toString
足以证实这一点。
a.toString() // 返回 ",,,,,,,,," 它至关于 [,,,,,,,,,]
a // [empty × 10]
因此,当将一个参数传递给的 new Array
,将致使 JS 引擎为传递的参数大小的数组分配空间。
而且这也在 EcmaScript 规范中:

看,这不是矛盾的。规格中都有全部描述。在得出任何结论以前,咱们应该始终先阅读任何语言的规范。
4、Function 构造函数
你是否知道咱们可使用 Function
构造函数定义 Function
。
你不明白吧?让我更清楚。在 JavaScript 中,咱们定义以下函数:
const mul = (a, b) => a * b
// 或
function mul(a, b) {
return a * b
}
// 或
const mul = function(a, b) {
return a * b
}
咱们也能够这样作,来实现相同的功能:
const mul = new Function("a", "b", "return a * b")
传递给 Function
的参数造成函数的参数和主体。变量 mul
成为函数名称。
而且,最后一个参数将是函数的主体,而最后一个参数以前的参数将成为函数的参数。
在在 mul
中。 "a"
和 "b"
是函数将接收的参数,"return a * b"
是函数的主体。它实现将 "a"
和 "b"
相乘并返回结果。
咱们使用 mul(…)
调用该函数,并传入参数:
const mul = new Function("a", "b", "return a * b")
console.log(mul(7, 8)) // 56
根据 MDN:
Function 构造函数建立一个新的
Function
对象。直接调用此构造函数可用动态建立函数,但会遭遇来自eval
的安全问题和相对较小的性能问题。然而,与 eval 不一样的是,Function 构造函数只在全局做用域中运行。
5、数组解构
咱们能够经过使用元素的索引号来分解数组中的元素。
const arr = [1, 2, 3]
元素 1
、2
、3
的索引分别为 0、一、2,即:
arr[0] // 1
在平常开发中,咱们最常使用的是对象解构:
let o = {
prop: 1
}
o["prop"] // 1
// 解构
const {prop} = o
prop // 1
因此,咱们将解构用于数组上:
const arr = [1, 2, 3]
const { 0: firstA, 1: secA, 2: thirdA } = arr
firstA // 1
secA // 2
thirdA // 3
因此咱们可使用索引号来提取元素。索引是定义数组中元素位置的属性。
const arr = [1, 2, 3]
至关于:
const arr = {
0: 1,
1: 2,
2: 3,
length: 3
}
数组也是对象,这就是为何要对其进行对象分解的缘由,可是还有一种特殊的数组分解语法:
const [first, second, third] = arr
first // 1
second // 2
third // 3
注意:应尽量避免知道数组中的特定位置信息(开始、结束索引是什么)。
6、使用 length 属性减小数组内容
数组中的 length
属性表示数组中元素的数目。
const arr = [1, 2, 3]
arr.length // 3
减少 length
属性值,会使 JS
引擎将数组元素个数减小到与 length
属性的值相等。
const arr = [1, 2, 3]
arr.length // 3
arr.length = 1
arr // [1]
arr
的 length
属性值更改成 1
,所以 arr
减小了元素个数,使其等于 length
属性值。
若是增长 length
属性,则 JS
引擎将添加元素(未定义的元素)以使数组中的元素数量达到 length
属性的值。
const arr = [1, 2, 3]
arr.length // 3
arr.length = 1
arr // [1]
arr.length = 5
arr // [1, empty × 4]
arr
中的元素只有一个,而后咱们将长度增长到 5 ,所以又增长了 4 个元素长度,使元素数达到 5。
7、Arguments
咱们可使用 arguments
对象获取传递给函数的参数,而无需在函数中明肯定义 arguments
变量:
function myFunc() {
console.log(arguments[0]) // 34
console.log(arguments[1]) // 89
}
myFunc(34,89)
arguments
对象是数组索引的。也就是说,属性是数字,所以能够经过键引用进行访问。
arguments
对象是从 Arguments
类实例化的,该类具备一些很酷的属性。
arguments.callee.name
指当前正在调用的函数的名称。
function myFunc() {
console.log(arguments.callee.name) // myFunc
}
myFunc(34, 89)
arguments.callee.caller.name
是指调用当前执行函数的函数的名称。
function myFunc() {
console.log(arguments.callee.name) // myFunc
console.log(arguments.callee.caller.name) // myFuncCallee
}
(function myFuncCallee() {
myFunc(34, 89)
})()
这在可变参数功能中特别有用。
8、跳过 ()
你是否知道实例化对象时能够跳过方括号 ()
?
例如:
class D {
logger() {
console.log("D")
}
}
// 通常状况下,咱们这么作:
(new D()).logger(); // D
// 其实,咱们能够跳过 ():
(new D).logger(); // D
// 而且它能够正常运行
即便在内置类中,括号也是可选的:
(new Date).getDay();
(new Date).getMonth();
(new Date).getYear();
9、void
void
是 JS 中的关键字,用于评估语句并返回未定义。
例如:
class D {
logger() {
return 89
}
}
const d = new D
console.log(void d.logger()) // undefined
logger
方法应该返回 89
,可是 void
关键字将使其无效并返回 undefined
。
我曾经读到过 undefined
以前可能会被赋予另外一个值,而这会伪造其语义。所以,使用 void
运算符可确保你获得一个真正的 undefined
。也用于最小化目的。
10、经过 `proto` 继承
_proto_
是从 JavaScript
中的对象继承属性的方法。__proto__
是 Object.prototype
的访问器属性,它公开访问对象的 [[Prototype]]
。
此 __proto__
将其 [[Prototype]]
中设置的对象的全部属性设置为目标对象。
让咱们看一个例子:
const l = console.log
const obj = {
method: function() {
l("method in obj")
}
}
const obj2 = {}
obj2.__proto__ = obj
obj2.method() // method in obj
咱们有两个对象常量:obj
和 obj2
。obj
具备 method
属性。obj2
是一个空的对象常量,即它没有属性。
咱们访问 obj2
的 __proto__
并将其设置为 obj
。这会将经过 Object.prototype
可访问的 obj
的全部属性复制到 obj2
。这就是为何咱们能够在 obj2
上调用方法而不会在没有定义的状况下获得错误的缘由。
obj2
继承了 obj
的属性,所以 method
方法属性将在其属性中可用。
原型可用于对象,例如对象常量、对象、数组、函数、日期、RegEx、数字、布尔值、字符串。
11、一元运算符 +
一元 +
运算符将其操做数转换为数字类型。
+"23" // 23
+{} // NaN
+null // 0
+undefined // NaN
+{ valueOf: () => 67 } // 67
+"nnamdi45" // NaN
当咱们但愿将变量快速转换为 Number
时,这很是方便。
12、一元运算符 -
一元运算符 -
将其操做数转换为 Number
类型,而后取反。
该运算符将一元 +
运算符的结果取反。首先,它将操做数转换为其 Number
值,而后取反该值。
-"23" // -23
此处发生的是,字符串 "23"
将转换为其数字类型,从而获得 23
。而后,此正数将转换为其负数形式 -23
。
-{} // NaN
-null // -0
-undefined // NaN
-{ valueOf: () => 67 } // -67
-"nnamdi45" // NaN
若是转换为数值的结果为 NaN
,则不会应用取反。
取负 +0
产生 -0
,取负 -0
产生 +0
。
- +0 // -0
- -0 // 0
十3、指数运算符 **
该运算符用于指定数字的指数。
在数学中, 2 的 3 次方意味着将 2 乘以 3 次:
2 * 2 * 2
咱们可使用 **
运算符在 JS 中进行相同的操做:
2 ** 3 // 8
9 ** 3 // 729
参考
本文来翻译自 https://blog.bitsrc.io/features-of-javascript-you-probably-never-used-4c117ba3f025
❤️感谢阅读
本文分享自微信公众号 - 鱼头的Web海洋(krissarea)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。