ES6深入浅出(二)之字符串/解构

·  阅读 106
ES6深入浅出(二)之字符串/解构

这是我参与11月更文挑战的第3天,活动详情查看:2021最后一次更文挑战

1, 模板字符串

ES6引入了一种新型的字符串字面量语法,我们称之为模板字符串。

在最简单的情况下,他们与普通字符串表现一致, 除此之外,正如其名称一样,模板字符串为JavaScript提供了简单的字符串插值功能

(1) 模板字符串的使用方式成千上万,但是最舒服的应该莫过于:错误消息提示

function authMessage(user, action) {
     if(!user.hasPrivileage(action)) {
         throw new Error(
            `用户${user.name} 未被授权执行 ${action} 操作。`
          )
     }
}
复制代码

上面的实例中,${user.name}${action} 被称为模版占位符

(2)细节: 如果想在模版字符串中使用反撇号,或者$, 或者{, 你都需要使用反斜杠转义

`\``,  `\$` , `\{`
复制代码

与普通字符串不同的是: 模版字符串可以多行书写, 字符串中所有空格,换行,缩进都会原样输出

$("#id").html(`
   <h1>你好</h1>
   <p>未经过授权:
   奖金${manyMoney}钱</p>
`)
复制代码

但是模板字符串有一个缺点: 不会自动转义特殊字符。接下来引出了标签模板

(3) 标签模板: ES6为开发者提供了一个很好的衍生工具,借助这个特性可以突破模板字符串的很多限制,我们称之为标签模板。

​ 语法: 在模板字符串开始的反撇号前面附加一个额外的标签即可。例如:

var message = SaferHTML`<p>${bonk.sender}向你问好</p>`
复制代码

精准的来说:任何ES6的成员表达式或调用表达式都可以作为标签使用。

上面的代码等效于:

var message = SaferHTML(templateData, bonk.sender)
复制代码

参数一: templateData: 是一个不可变的数组,里面存储这模板中所有的字符串部分, 由JS引擎为我们创建的。

因为占位符将标签模板分割成两个字符串部分,所以templateData这个数组含有两个元素

形如:Object.freeze(["<p>", "向你问好</p>"])

function SaferHTML(templateData) {
   var = templateData[0]
   for (var i =1; i < arguments.length; i++) {
      var arg = String(arguments[i])
      // 转义占位符的特殊字符
     s += arg.replace(/&/g, "&")
             .replace(/</g, "<")
             .replace(/</g, ">");
     // 不转义模板中的特殊字符
     s +=templateData[i]
   }
   return s;
}
复制代码

即使黑客向用户发送一条骚扰消息,这条消息也能被转义为普通字符串,不会受到攻击威胁。

2, 不定参数和默认参数

通过一个简单的可变参数函数对比一下ES6提供的不定参数

功能:检查一个字符串中是否包含若干个子串

1,使用传统的方式

function containsAll(haystack) {
    for(var i=1; i < arguments.length; i++) {
        var needle = arguments[i]
        if(haystack.indexOf(needle) === -1) {
            return false;
        }
    }
            return true;
}

containsAll("banana", "b", "nan")
复制代码

缺点: 函数列表中只有一个参数,无法一眼看出这个函数实际上接手了多少个参数

2,使用ES6不定参数特性实现

function constainsA(hasytack, ...needles) {
    for (var needle of needles) {
        if(hasytack.indexOf(needle) === -1) {
            return false;
        }
    }
    return true;
}
constainsA("banana", "b", "nan")
复制代码

两种方式进行对比:与之前一样,传递进来的第一个参数 " 赋值给参数 haystack ,needles 前的省 略号表明它是一个不定参数,所有传递进来的其它参数都被放到一个数组中,赋值给变量 needles

切记:在所有函数参数中,只有最后一个才可以被标记为不定参数。

任何多余的参数都会被放进一个数组并赋值给不定参数, 如果没有额外的参数,不定参数就是一个空数组。

3, 默认参数

JavaScript有严格的默认参数,未被传值的参数默认是为:undefined,在ES6中,引入了新的方式,可以指定任意参数的默认值。

function a(b="zlm", c="18") {
  reutrn `Jamie and ${zlm} all ${c} ! `
}
复制代码

4, 停止使用arguments

认识到不定参数和默认参数,发现他们都可以替代arguments对象。要注意: 标注规定:在使用不定参数或默认参数的函数中禁止使用arguments对象。

3,解构

1, 什么是解构:解构赋值允许你使用类似数组或对象字面量的语法将数组和对象的属性赋值给各种变量, 类似下面的语法。

var [a, b, c] = testArray;
复制代码

理论上你可以对任意深度的嵌套数组进行解构

var [foo, [[bar], baz]] = [1, [[2], 3]]; 
console.log(foo); // 1 
console.log(bar); // 2
console.log(baz); // 3
复制代码

也可在对应位置留空来跳过解构数组中的某些元素

var [,,third] = ["foo", "bar", "baz"];
console.log(third); // "baz"
复制代码

而且也可通过不定参数捕获数组中的所有末尾元素

var [head, ...tail] = [1, 2, 3, 4];
console.log(tail); // [2, 3, 4]
复制代码

2, 对象的解构

当属性名与变量名一致时,可以简写

var { foo, bar } = { foo:'zlm', bar: '18' }
复制代码

和数组解构一样, 你可以随意嵌套并进一步组合对象解构

当你解构一个未定义的属性时,得到的值为 undefined

var { missing } = {};
console.log(missing); 
// undefined
复制代码

注意:

赋值语句前没有let, const, var 等变量声明的关键字,下面的解构会报错

{ test } = { test:20 }
// 语法错误  Syntax error
复制代码

为什么会报错: 因为JavaScript语法通知解析引擎将任何以{ 开始的语句解析为一个块语句,比如: { console} 是一个合法语块。解决方案:将整个表达式用一对小括号包裹

({ test } = { test:20 })
复制代码

如果去解构nullundefined时,你会得到一个类型错误:如果去解构其他原始类型,会得到undefined

var {a} = null; 
// 语法报错 TypeError: null has no properties(null没有属性)

var {b} = NaN;
console.log(b); // undefined

var {c} = String;
console.log(c); // undefined
复制代码

原理也很简单:当使用对象赋值模式,被解构的值需要被强制转换为对象,大多数类型都可以被转换为对象,但是nullundefined无法进行转换,所以在解构的时候辉报语法错误

开发常识:当你要解构的属性未定义的时候,你可以提供一个默认值

var [test = true] = []; 
console.log(test); 
// true

var { message: msg = "Something went wrong" } = {};
console.log(msg); 
// "Something went wrong"

var { x = 1 } = {}; 
console.log(x);
// 1

复制代码

4, 实际开发应用

为实现设计良好的API, 通常的做法是为函数设计一个对象作为入参,然后根据不同的实际参数作为对象属性,可以避免开发者需要记住多个参数和参数顺序,在赋值的时候,可以通过解构特性避免这种问题

1, 举个例子:

JQuery.ajax = function(url, {
     async = true,
     beforeSend = noop,
     cache = true,
     complete = noop,
     crossDomain = false,
     global = true,
     // ....
}) {
   // ... todo
}
复制代码

2, 实际开发中,对与Map对象,我们也可以使用解构

var map = new Map()
    map.set(a: 'zlm');
    map.set(b: 'Jamie');
    for( var [key, value] of map) {
      console.log(key, value)
    }
复制代码

如果只遍历键

for(var [key] of map) {
    console.log(key)
}
复制代码

如果只遍历值

for(var [,value] of map) {
   console.log(value)
}
复制代码

3, 实际开发中,我们习惯用函数作为容器

function returnMultipValues() {
  return {
    foo: 1,
    bar: 2
  }
}

var { foo, bar } = returnMultipValues()
复制代码

4, 解构还有用的最多的是导入

显示的定义模块的一部分功能,避免导入过多的没有用到的函数

cons { foo, bar } = require('util')
复制代码
分类:
前端
分类:
前端