您可以通过左右滑屏查看更多笔记内容。。

Es6变量的结构赋值

11 Sep 2019 . category: tech .
更多笔记

变量的结构赋值

一.数组的解构赋值

<1>解构:ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构;

模式匹配:只要等号两边的模式相同,左边的变量就会被赋予对应的值

​ 如果解构不成功,变量的值就等于undefined

数组的元素是按次序排列的,变量的取值由它的位置决定;

案例:

function* fibs() {
  let a = 0;
  let b = 1;
  while (true) {
    yield a;
    [a, b] = [b, a + b];
  }
}

let [first, second, third, fourth, fifth, sixth] = fibs();
sixth // 5

<2>默认值

  • ES6 内部使用严格相等运算符(===),判断一个位置是否有值。所以,只有当一个数组成员严格等于undefined,默认值才会生效;

  • 案例:

    let [x = 1] = [undefined];
    x // 1
    let [x = 1] = [null];
    x // null     null不严格等于undefined,所以默认值无效
    
  • 如果默认值是一个表达式,那么这个表达式是惰性求值的,即只有在用到的时候,才会求值;

  • 默认值可以引用解构赋值的其他变量,但该变量必须已经声明。

二.对象的解构赋值

对象的解构:对象的属性没有次序,变量必须与属性同名,才能取到正确的值。

  • 如果解构失败,变量的值等于undefined;

    let { bar, foo } = { foo: 'aaa', bar: 'bbb' };
    foo // "aaa"
    bar // "bbb"
    ------------------------------------------------
    let {foo} = {bar: 'baz'};
    foo // undefined
    
  • 如果变量名与属性名不一致时:

    let { foo: baz } = { foo: 'aaa', bar: 'bbb' };
    baz // "aaa"
      
    let obj = { first: 'hello', last: 'world' };
    let { first: f, last: l } = obj;
    f // 'hello'
    l // 'world'
    

对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者。

  • let { foo: baz } = { foo: 'aaa', bar: 'bbb' };
    baz // "aaa"
    foo // error: foo is not defined
      
    //foo是匹配的模式,baz才是变量。真正被赋值的是变量baz,而不是模式foo。
    
  • Object.setPrototypeOf() 方法设置一个指定的对象的原型 ( 即, 内部[[Prototype]]属性)到另一个对象或 null

    Object.setPrototypeOf(obj, prototype)
    * obj  --要设置其原型的对象。.
    * prototype  --该对象的新原型(一个对象 或 null).
    
  • 对象的解构赋值可以取到继承的属性:

    案例:

    const obj1 = {};
    const obj2 = { foo: 'bar' };
    Object.setPrototypeOf(obj1, obj2);
      
    const { foo } = obj1;
    foo // "bar"
    //对象obj1的原型对象是obj2。foo属性不是obj1自身的属性,而是继承自obj2的属性,解构赋值可以取到这个属性
    
  • 注意:

    • 将一个已经声明的变量用于解构赋值时,大括号不可以写在行首;
    • 解构赋值允许等号左边的模式之中,不放置任何变量名;
    • 数组本质是特殊的对象,因此可以对数组进行对象属性的解构。

    案例:

    let arr = [1, 2, 3];
    let {0 : first, [arr.length - 1] : last} = arr;
    console.log(first) // 1
    console.log(last) // 3
    

<3>字符串的解构赋值

  • 此时,字符串被转换成了一个类似数组的对象。

    const [a, b, c, d, e] = 'hello';
    a // "h"
    b // "e"
    c // "l"
    d // "l"
    e // "o"
    
  • 可以对length属性解构赋值。

    let {length : len} = 'hello';
    len // 5
    

<4>数值和布尔值的解构赋值

解构赋值的规则是,只要等号右边的值不是对象或数组,就先将其转为对象;

let {toString: s} = 123;
s === Number.prototype.toString // true

let {toString: s} = true;
s === Boolean.prototype.toString // true

<5>函数参数的解构赋值

function move({x = 0, y = 0} = {}) {
  return [x, y];
}

move({x: 3, y: 8}); // [3, 8]
move({x: 3}); // [3, 0]
move({}); // [0, 0]
move(); // [0, 0]
function move({x, y} = { x: 0, y: 0 }) {
  return [x, y];
}

move({x: 3, y: 8}); // [3, 8]
move({x: 3}); // [3, undefined]
move({}); // [undefined, undefined]
move(); // [0, 0]

上面代码是为函数move的参数指定默认值,而不是为变量x和y指定默认值,所以会得到与前一种写法不同的结果。

<6>不能使用圆括号的情况

以下三种解构赋值不得使用圆括号:

(1)变量声明语句;

(2)函数参数;

(3)赋值语句的模式;

### 可以使用圆括号的情况:赋值语句的非模式部分,可以使用圆括号。

<7>解构赋值的用途:

  1. 交换变量的值(不需要引入第三个值)

    let x = 1;
    let y = 2;
       
    [x, y] = [y, x];
    
  2. 从函数返回多个值:

  3. 函数参数的定义:方便地将一组参数与变量名对应起来;

  4. 提取 JSON 数据;

  5. 指定参数的默认值;

  6. 遍历 Map 结构;

  7. 输入模块的指定方法;


字符串的扩展

<1>字符的 Unicode表示法

console.log("\u0061");// "a"
console.log("\uD842\uDFB7");//𠮷
console.log("\u{20BB7}");//𠮷
console.log("\u{41}\u{42}\u{43}");//ABC
let hello = 123;
console.log(hell\u{6F}) // 123
console.log('\u{1F680}' === '\uD83D\uDE80')//true

<2>字符串的遍历器接口

for…of:可以识别大于0xFFFF的码点

<3>直接输入U+2028 和U+2029

JavaScript 规定有5个字符,不能在字符串里面直接使用,只能使用转义形式:

  • \u005C:反斜杠(reverse solidus)
  • \u000D:回车(carriage return)
  • \u2028:行分隔符(line separator)
  • \u2029:段分隔符(paragraph separator)
  • \u000A:换行符(line feed)

<4>JSON.stringify()的改造

如果遇到0xD8000xDFFF之间的单个码点,或者不存在的配对形式,它会返回转义字符串,留给应用自己决定下一步的处理。

SON.stringify('\u{D834}') // ""\\uD834""
JSON.stringify('\uDF06\uD834') // ""\\udf06\\ud834""

<5>模板字符串

模板字符串(template string)是增强版的字符串,用反引号(`)标识。它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。

let a=10;
let b=23;
console.log(`和是 ${a+b}
不是 ${2*a+b}`);
//和是 33
不是 43     进行了换行
<script>
 let basket={count:1000,onSale:100}
 let a=10;
 let b=20;
 function fn() {
  return "Hello World";
}
$(function(){
    $('#result').append(`
    哈哈哈<h1>${basket.count}</h1>
      嘿嘿嘿<h2>${basket.onSale}</h2>
      哦哦哦<h3>${a+b}</h3>
      eee<h3>${fn()}</h3>`
    )
    $('#list').html(`
      <ul>
        <li>first</li>
        <li>second</li>
      </ul>
      `.trim());
})
</script>

1568206871120

  • 模板字符串,都是用反引号表示。如果在模板字符串中需要使用反引号,则前面要用反斜杠转义。

  • 使用模板字符串表示多行字符串,所有的空格和缩进都会被保留在输出之中。

  • 模板字符串中嵌入变量,需要将变量名写在${}之中。basket.count

  • 大括号内部可以放入任意的 JavaScript 表达式,可以进行运算,以及引用对象属性。

  • 模板字符串之中还能调用函数。

  • 模板字符串甚至还能嵌套.

    const tmpl = addrs => `
      <table>
      ${addrs.map(addr => `
        <tr><td>${addr.first}</td></tr>
        <tr><td>${addr.last}</td></tr>
      `).join('')}
      </table>
    `;
    const data = [
        { first: '<Jane>', last: 'Bond' },
        { first: 'Lars', last: '<Croft>' },
    ];
    console.log(tmpl(data));
      
    //结果:
     <table>
        
        <tr><td><Jane></td></tr>
        <tr><td>Bond</td></tr>
        
        <tr><td>Lars</td></tr>
        <tr><td><Croft></td></tr>
        
      </table>
      
    

<6>模块编译—-不理解

<7> 标签模板

可以紧跟在一个函数名后面,该函数将被调用来处理这个模板字符串。这被称为“标签模板”功能(tagged template)。

alert`123`
// 等同于
alert(123)

“标签”指的就是函数,紧跟在后面的模板字符串就是它的参数。

如果模板字符里面有变量,就不是简单的调用了,而是会将模板字符串先处理成多个参数,再调用函数。

let a = 5;
let b = 10;
function tag(s, v1, v2) {
  console.log(s[0]);
  console.log(s[1]);
  console.log(s[2]);
  console.log(v1);
  console.log(v2);
  return "OK";
}
tag`Hello ${ a + b } world ${ a * b}`;

//结果:
    Hello
    World

    15 
    50

tag函数:

function tag(stringArr, value1, value2){
  // ...
}
// 等同于
function tag(stringArr, ...values){
  // ...
}
---------------------------
let a = 5;
let b = 10;
tag`Hello ${ a + b } world ${ a * b }`;
// 等同于
tag(['Hello ', ' world ', ''], 15, 50);
---------------------------

  • tag函数的第一个参数是一个数组,该数组的成员是模板字符串中那些没有变量替换的部分,
  • tag函数的其他参数,都是模板字符串各个变量被替换后的值。

案例1:如何将各个参数按照原来的位置拼合回去。

let total = 30;
let msg1 =`The total is ${total} (${total*1.05} with tax)`;

let msg = passthru`The total is ${total} (${total*1.05} with tax)`;

function passthru(literals) {
  let result = '';
  let i = 0;
  while (i < literals.length) {
    result += literals[i++];
    if (i < arguments.length) {
      result += arguments[i];
    }
  }
  return result;
}
console.log(msg);  //The total is 30 (31.5 with tax)
console.log(msg1); //The total is 30 (31.5 with tax)

“标签模板”的一个重要应用,就是过滤 HTML 字符串,防止用户输入恶意内容。

let sender = '<script>alert("abc")</script>'; // 恶意代码
let message =
  SaferHTML`<p>${sender} has sent you a message.</p>`;

function SaferHTML(templateData) {
  let s = templateData[0];
  for (let i = 1; i < arguments.length; i++) {
    let arg = String(arguments[i]);
    // Escape special characters in the substitution.
    s += arg.replace(/&/g, "&amp;")
            .replace(/</g, "&lt;")
            .replace(/>/g, "&gt;");

    // Don't escape special characters in the template.
    s += templateData[i];
  }
  return s;
}
console.log(message);
//<p>&lt;script&gt;alert("abc")&lt;/script&gt; has sent you a message.</p>