11+ JavaScript Features You’ve Probably Never Used

最近在备考雅思,空下来就翻译一下技术文章,增加阅读能力。这篇文章来自medium,作者:Chidume Nnamdi,文章原文地址

⚠ 重要 ⚠

这篇文章描述的部分功能已经被弃用了,有些功能被EcmaScript禁用了。这些功能仍然在许多图书馆中很常见,还是值得我们学习了解的。

仅供参考。

标记模板字符串

taggingThis`Hey!!, I'm  ${name} !!`

如果已经用过React样式组件化,那么就已经用过标记模板字符串。
带有模板标记的字符串可以更好的控制字符串解析。允许我们使用函数来解析模板字符串。

taggingThis`Hey!!, I'm  ${name} !!`

taggingThis是一个功能。标记函数的第一个参数包含字符串值的数组,其余参数与表达式相关。

function taggingThis(strings, ...vals) {
    //...
}
taggingThis`Hey!!, I'm  ${name} !!`

strings参数将保持在[ "Hey!!, I'm ", ' !!' ],其余的参数传递到数组中,vals[ 'Nnamdi' ]

这个taggingThis函数里面,可以操作入参和返回不同内容。

function taggingThis(strings, ...vals) {
    return strings[0] + vals[0] + strings[1]
}
const name = "Nnamdi"
taggingThis `Hey!!, I'm  ${name} !!` // Hey!!, I'm  Nnamdi !!

样式组件标记字符串

逗号运算符

逗号运算符分割表达式和返回链中的最后一个表达式。

let expr = (99, 88, 77)
expr // 77

有三个表达式99,88和77。所有的表达式都被求值和最后一个被赋值给expr

下面这个for循环:

for(let i = 0, ii = 1; i< 10; i++, ii--) { ... }

当想写一个简短的lambda函数,逗号运算符会派上用场。

const lb = (a, b, arr) => (arr.push(a*b), a*b)

这里面有两个语句,第一个语句将乘法结构推入数组arr,第二个语句是a*b。第二个结果就是返回给回调者的内容。

三元运算符逗号也是很有用,和短lambda函数语法相同,仅接受表达式,不是接受语句。

with语句

⚠注意⚠
通常不建议使用with语句,已经被废弃了。在严格模式下被禁止了。使用with会增加js语言性能和安全上的问题。

with是JS中的关键字。用于扩展语句的作用于链。

下面这样使用:

with(expression)
    statement
// OR
with(expression) {
    statement
    statement
    ...
}

计算表达式并围绕表达式创建作用域。with语句的表达式和父作用域在大括号里面。

const a = 45
let b = 8
var f = 909
with(f) {
    log(f, b, a) // 909 8 45
}

f是包裹在作用域链中。fwith语句块外面声明的外部变量在with语句块里面可见。

注意,letconstwith语句里面声明的变量只能在语句里面可以用,外部不可以调用。

with(f) {
    log(f, b, a) // 909 8 45
    let withinF = 20
}
log(withinF) // undefined

调用withinF方法,将会抛出ReferenceError错误,因为变量withinF只存在with语句块里面。

尽量避免使用with

更多细节

in

in也是一个关键字,检查对象里面存在的属性。在for..in循环中就使用,但没有意识到in就是关键字。

如果对象里面存在这个属性in将返回true,否则将返回false。

const o = {
    prop: 90
}
log("prop" in o) // true

上面in是独立使用的,并没有for...in循环。

将检查prop是否可作为o对象里面的属性使用。返回ture,因为已经在o里面定义了prop

如果检查未定义的属性:

const o = {
    prop: 90
}
log("prop1" in o) // false

打印出false。因为prop1在o这个对象里面没有定义。

已经用过这些功能了吗?

更多了解

数组构造函数

知道吗?可以不用传统的方式定义数组。

const arr = [90,88,77]

用数组构造函数

const arr = new Array(90, 88, 77)

传递给构造函数的参数排序将构成其索引的基础。

90第一个参数索引是0,88第二参数索引是1,77最后一个参数索引是2.

arr[0] // 90
arr[1] // 88
arr[2] // 77

new Array(...)和使用数组是一样的。

那么

const arr = new Array(90, 88, 77)

同下面是一样的

const arr = [90, 88, 77]

有人认为使用数组构造函数功能有些缺点或不一致:
Why never use new Array in Javascript

使用new的方式创建一个数组,适用于构造函数new Array()的参数大于或等于2的情况。

这样做

const arr = new Array(90, 88, 77)

将创建数组[90, 88, 77].因为new Array(..)的参数为3,即>=2.

new Array(..)传递一个参数,将导致JS引擎为传递参数大小的数组分配空间。

const arr = new Array(6)

将创建一个包含6项或元素的数组,长度为6。

const arr = new Array(6)
arr // [ <6 empty items> ]
arr.length // 6

const arr = new Array(6)同下:

const arr = [, , , , , ]
arr // [ <6 empty items> ]
arr.length // 6

如果说这是JS不一致或偏激的功能,我不会同意。这在EcmaScript规范中。


这并不矛盾。规范中都有描述。在给出结论之前,我们首先应该始终先阅读语言的规范。

Function构造函数

可以用Function构造函数定一个一个Function。

接下来讲清楚。在JS里我们定义一个函数像这样:

const mul = (a, b) => a * b

// OR

function mul(a, b) {
    return a * b
}

// OR

const mul = function(a, b) {
    return a * b
}

我们仍然可以像下面这样做:

const mul = new Function("a", "b", "return a * b")

传递给Function的参数形成函数的参数和主体。mul变量变成函数的名称。

最后的参数将变成函数的主体,那么最后参数的前面将会变成函数的参数。

mul中,参数ab是函数将接收的参数,参数return a * b是函数的主体。a和b相乘然后返回结果。

调用函数在括号里面传参数mul(…)

const mul = new Function("a", "b", "return a * b")

log(mul(7, 8)) // 56

根据MDN 文档:

直接调用构造函数可以动态创建函数,但存在安全和评估方面类似的(但重要性不高)问题。但是,与eval不同,Function构造函数创建的函数仅在全局范围内执行。

更多内容

解构数组

我们可以使用元素的索引来分解数组的元素。

const arr = [99, 88, 77]

元素99, 88, 77有索引0, 1, 2.从数组arr中获取元素99,我们将其作为属性传递给arr,

arr[1]

就像处理对象一样:

let o = {
    prop: 99
}
o[prop] // 99

可以像这样从o对象里面解构属性:

const {prop} = o
prop // 99

同样可以这样操作数组:

const arr = [99, 88, 77]

const { 1: secA } = arr
secA // 88

const { 0: firstA, 1: secA, 2: thirdA  } = arr

firstA // 99
secA // 88
thirdA // 77

我们使用索引号提取元素。索引是定义数组中元素位置的属性。

const arr = [99, 88, 77]

和下面的相同:

const arr = {
    0: 99,
    1: 88,
    2: 77,
    length: 3
}

数组也是对象,这就是为什么用对象的方式去解构数组效果一样,但还有一种特殊的语法解构数组:

const [first, second, third] = arr;

尽可能的避免知道数组中的特定位置信息(开始索引,结束索引)。

Reducing Array contents using the length property

可以操作length属性减少数组。

数组中的length属性是指数组中的长度。

const arr = [99, 88, 77]
arr.length // 3

减少length属性,JS引擎将元素减少为与length属性。

const arr = [99, 88, 77]
arr.length // 3
arr.length = 1
arr // [ 99 ]

arr的length属性更改为1,因此从右侧减少了元素,使其长度等于设置的length属性的值。
如果增加length属性,JS引擎将会增加元素(未定义),使数组元素长度符合length属性值。

const arr = [99, 88, 77]
arr.length // 3
arr.length = 1
arr // [ 99 ]

arr.length = 5
arr // [ 90, <4 empty items> ]

数组中只有一个,如果增加长度到5,那么增加了4个空到数组里面,使数组长度达到5.

Arguments

arguments获取函数传递的参数。这样做的好处,可以使用arguments对象传参数给函数,无需确切的定义函数参数。

function myFunc() {
    arguments[0] // 34
    arguments[1] // 89
}

myFunc(34,89)

arguments对象是数组索引。也就是说,属性是数字,所以就可以通过键值索引。
arguments对象是通过Arguments类实例化的,该类具有一些很酷的属性。

arguments.callee.name这是指当前被调用的函数名称。

function myFunc() {
    log(arguments.callee.name) // myFunc
}

myFunc(34, 89)

arguments.callee.name引用调用当前执行函数的函数的名称。

function myFunc() {
    log(arguments.callee.name) // myFunc
    log(arguments.callee.caller.name) // myFuncCaller
}

(function myFuncCallee() {
    myFuncCaller(34, 89)
})()

可变参数在函数中是特别有用的。

更多内容

Skip the brackets

实例化对象,可以忽略括号().

例如:

class D {
    logger() {
        log("D")
    }
}

// Normally, we do this:
(new D()).logger() // D

// Also, we can skip the ():
(new D).logger() // D
// and it still works

括号是可选的,即使在内置类中也是如此。

(new Date).getDay()
(new Date).getMonth()
(new Date).getYear()

void operator

void是JS中的关键字,是一个陈述语句,然后返回undefined.

例如:

class D {
   logger() {
        return 89
    }
}

const d = new D

log(void d.logger()) // undefined

logger方法应该返回89,但void关键字将无效并返回undefined.

之前未定义的值可以被分配给另一个值,会伪造定义。void操作符可以确保真正的undefined。用于最小化目的。

更多内容

Function property

可以在函数中设置属性:

function func() {
    func.prop1 = "prop1"
}
func.prop2 = "prop2"

函数也是对象,所以上面的写法是有效的。当使用对象时,Function属性将是Function所有实例的静态属性。

const j1 = new func()
const j2 = new func()
j1.prop1 // prop1
j2.prop1 // prop1
j1.prop1 = "prop1 changed"
j2.prop1 // prop1 changed

当用作是函数时,将是全局属性。

function func() {
    func.prop1 === undefined ? func.prop1 = "yes" : null
    if(func.prop1 === "yes")
        log("Prop with Yes")
    if (func.prop1 == "no")
        log("Prop with No")
}
func() // Prop with Yes
func.prop1 = "no"
func() // Prop with No

Inheritance via proto

_proto_是从JavaScript中的对象继承属性的方法。
Object.prototype__proto__ 属性是一个访问器属性(一个getter函数和一个setter函数), 暴露了通过它访问的对象的内部[[Prototype]] (一个对象或 [null])。

看一个例子:

// proto.js
const log = console.log
const obj = {
    method: function() {
        log("method in obj")
    }
}
const obj2 = {}
obj2.__proto__ = obj
obj2.method()

两个对象字面量:obj和obj2都有一个merhod属性方法。obj2是一个空对象字面量,没有属性。

接下来,访问obj2的__proto__,并将obj赋值给它。通过Object.prototype将obj所有的可访问的属性赋值给obj2.这就是为什么在没有定义的情况下可以调用obj2上面的method,而且没有报错。

$ node proto
method in obj

obj2继承了obj的属性,那么在它的属性里面,method方法将可用。

proto用于对象,例如:object literal, Object, Array, Function, Date, RegEx, Number, Boolean, String.

Unary + Operator

一元+操作符将其操作数转换为Number类型。

+"23" // 23
+{} // NaN
+null // 0
+undefined // NaN
+{ valueOf: () => 67 } // 67
+"nnamdi45" // NaN

当我们想快速将变量转换为Number类型时,这非常方便。

Unary — Operator

一元运算符将其操作数转换为Number类型,然后取反。
该运算符将一元+运算符的结果取反。首先,它将操作数转换为Number值,然后取反该值。

-"23" // -23

字符串“23”将转换为Number类型,得到23.然后,正数将会转换为复数形式-23.

-{} // NaN
-null // -0
-undefined // NaN
-{ valueOf: () => 67 } // -67
-"nnamdi45" // NaN

如果转换为数值的结果为NaN,则不会取反。

取负+0产生-0,取负-0产生+0。

- +0 // -0
- -0 // 0

Exponentiation ** operator

该运算符用于查找数字的指数。数字的幂上升到一个确定的级。
在数学中,如果2的3次方(找到2的指数),则意味着将2乘以三次:

2 * 2 * 2

我们可以用**运算符在JS中相同的操作:

2 ** 3 // 8
9 ** 3 // 729

Conclusion

JS中有很多很棒的功能。即将推出更多功能,将不断更新。

如果拥有或发现了JS很少使用的任何功能,可以在评论中回复。很高兴能知道这些。

翻译结束!

你可能感兴趣的:(11+ JavaScript Features You’ve Probably Never Used)