ECMAScript的学习(一)

初级入门Q&A

整理的一些问题

questionanswer
ECMAScript和js的关系前者是后者的规格,后者是前者的其中一种实现(ECMAScript 方言还有Jscript 和ActionScript)。日常场合这两个词是可以互换。
node是js的什么是 JavaScript 的服务器运行环境(runtime)。
let和var的区别let声明的变量,只在let命令所在的代码块有效,let适合用于for。var定义的变量全局只能有一个,且var会发生变量提升(就是变量可以再声明前使用,值为undefined)ps:如果区块中存在let和const命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。var x=x和let x=x不同,let会报错
声明变量var,function,let,const,import,class(还可以通过数组声明如:let [a, b, c] = [1, 2, 3];)

基本语法
块级作用域

  • 有了块级作用域可以再其中声明函数,这种函数类似let声明的变量,作用域以外不可以引用(要避免做这种函数,如果要用,最好写成函数表达式)
  • 函数声明语句和函数表达式
  • // 函数声明语句
    {
      let a = 'secret';
      function f() {
        return a;
      }
    }
    
    // 函数表达式
    {
      let a = 'secret';
      let f = function () {
        return a;
      };
    }

    const
    const命令一旦声明就要立即初始化,只在声明所在的块级作用域内有效
    顶层对象(在浏览器环境指的是window对象,在 Node 指的是global对象。)
    window:es5中全局变量就是window对象,但es6为了保持兼容性,var和function声明的是顶层变量,其他声明语句声明的不属于。
    global:我不懂!!!!!!!
    变量的解构赋值

  • set语句的用法:let [x, y, z] = new Set([‘a’, ‘b’, ‘c’]);
    x // “a”
  • 对象的解构赋值:不仅可以用于数组还可以用于对象(但是数组的元素是按次序排列,对象没有次序,且变量必须和属性同名)
  • let { foo, bar } = { foo: "aaa", bar: "bbb" };
    foo // "aaa"
    bar // "bbb"</li>

    如果变量和属性不同名

    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 obj = {
      p: [
        'Hello',
        { y: 'World' }
      ]
    };
    
    let { p: [x, { y }] } = obj;
    x // "Hello"
    y // "World"

    注意,这时p是模式,不是变量,因此不会被赋值。如果p也要作为变量赋值,可以写成下面这样。
    let { p, p: [x, { y }] } = obj;
    【二】
    ps:另一个例子()

    const node = {
      loc: {
        start: {
          line: 1,
          column: 5
        }
      }
    };
    
    let { loc, loc: { start }, loc: { start: { line }} } = node;
    line // 1
    loc  // Object {start: Object}
    start // Object {line: 1, column: 5}

    注意,最后一次对line属性的解构赋值之中,只有line是变量,loc和start都是模式,不是变量。
    【三】
    嵌套赋值

    let obj = {};
    let arr = [];
    
    ({ foo: obj.prop, bar: arr[0] } = { foo: 123, bar: true });
    
    obj // {prop:123}
    arr // [true]

    【四】
    已声明变量用于解构赋值

    // 错误的写法
    let x;
    {x} = {x: 1};
    // SyntaxError: syntax error
    // 正确的写法
    let x;
    ({x} = {x: 1});

    let { log, sin, cos } = Math;
    上面代码将Math对象的对数、正弦、余弦三个方法,赋值到对应的变量上,使用起来就会方便很多。
    【五】
    数组对对象属性的解构

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

  • 解析可以用于嵌套结构的对象
  • const [a, b, c, d, e] = 'hello';
    a // "h"
    b // "e"
    c // "l"
    d // "l"
    e // "o"
    let {length : len} = 'hello';
    len // 5

  • 函数参数的解构赋值
  • [[1, 2], [3, 4]].map(([a, b]) => a + b);
    // [ 3, 7 ]
    function add([x, y]){
      return x + y;
    }
    
    add([1, 2]); // 3

  • 圆括号问题
  • 【三不】
    变量声明不能使用

    let {(x: c)} = {};
    let {(x): c} = {};

    函数参数不能用

    // 报错
    function f([(z)]) { return z; }
    // 报错
    function f([z,(x)]) { return x; }

    赋值语句的模式不能用

    // 全部报错
    ({ p: a }) = { p: 42 };
    ([a]) = [5];

    【可以用】
    赋值语句的非模式部分,可以使用圆括号。

    [(b)] = [3]; // 正确
    ({ p: (d) } = {}); // 正确
    [(parseInt.prop)] = [3]; // 正确

  • 用途
  • (1)交换变量的值

    let x = 1;
    let y = 2;
    
    [x, y] = [y, x];

    (2)从函数返回多个值

    // 返回一个数组
    
    function example() {
      return [1, 2, 3];
    }
    let [a, b, c] = example();
    
    // 返回一个对象
    
    function example() {
      return {
        foo: 1,
        bar: 2
      };
    }
    let { foo, bar } = example();

    (3)函数参数的定义

    // 参数是一组有次序的值
    function f([x, y, z]) { ... }
    f([1, 2, 3]);
    
    // 参数是一组无次序的值
    function f({x, y, z}) { ... }
    f({z: 3, y: 2, x: 1});

    (4)提取 JSON 数据

    let jsonData = {
      id: 42,
      status: "OK",
      data: [867, 5309]
    };
    
    let { id, status, data: number } = jsonData;
    
    console.log(id, status, number);
    // 42, "OK", [867, 5309]

    (5)函数参数的默认值

    jQuery.ajax = function (url, {
      async = true,
      beforeSend = function () {},
      cache = true,
      complete = function () {},
      crossDomain = false,
      global = true,
      // ... more config
    } = {}) {
      // ... do stuff
    };

    (6)遍历 Map 结构

    const map = new Map();
    map.set('first', 'hello');
    map.set('second', 'world');
    
    for (let [key, value] of map) {
      console.log(key + " is " + value);
    }
    // first is hello
    // second is world
    // 获取键名
    for (let [key] of map) {
      // ...
    }
    
    // 获取键值
    for (let [,value] of map) {
      // ...
    }

    (7)输入模块的指定方法
    const { SourceMapConsumer, SourceNode } = require("source-map");

    字符串的扩展
    【一】Unicode表示法
    JavaScript 允许采用\uxxxx形式表示一个字符,其中xxxx表示字符的 Unicode 码点。

    '\z' === 'z'  // true
    '\172' === 'z' // true
    '\x7A' === 'z' // true
    '\u007A' === 'z' // true
    '\u{7A}' === 'z' // true

    【二】codePointAt()
    JavaScript 内部,字符以 UTF-16 的格式储存,每个字符固定为2个字节。对于那些需要4个字节储存的字符(Unicode 码点大于0xFFFF的字符),JavaScript 会认为它们是两个字符。
    ES6 提供了codePointAt方法,能够正确处理 4 个字节储存的字符,返回一个字符的码点。
    codePointAt方法是测试一个字符由两个字节还是由四个字节组成的最简单方法。

    function is32Bit(c) {
      return c.codePointAt(0) > 0xFFFF;
    }
    
    is32Bit("?") // true
    is32Bit("a") // false

    【三】String.fromCodePoint()
    ES5中用于从码点返回对应字符,但是这个方法不能识别 32 位的 UTF-16 字符(Unicode 编号大于0xFFFF)。
    ES6 提供了String.fromCodePoint方法,可以识别大于0xFFFF的字符,弥补了String.fromCharCode方法的不足。在作用上,正好与codePointAt方法相反。

    String.fromCodePoint(0x20BB7)
    // "?"
    String.fromCodePoint(0x78, 0x1f680, 0x79) === 'x\uD83D\uDE80y'
    // true

    【四】字符串的遍历器接口

    for (let codePoint of 'foo') {
      console.log(codePoint)
    }
    // "f"
    // "o"
    // "o"

    【五】normalize()
    【六】includes(), startsWith(), endsWith()
    -includes():返回布尔值,表示是否找到了参数字符串。
    -startsWith():返回布尔值,表示参数字符串是否在原字符串的头部。
    -endsWith():返回布尔值,表示参数字符串是否在原字符串的尾部。

    let s = 'Hello world!';
    
    s.startsWith('Hello') // true
    s.endsWith('!') // true
    s.includes('o') // true

    支持第二个参数,表示的是开始搜索的位置

    let s = 'Hello world!';
    
    s.startsWith('world', 6) // true
    s.endsWith('Hello', 5) // true
    s.includes('Hello', 6) // false

    【七】repeat()
    表示将一个字符串重复多少遍
    【八】padStart(),padEnd()

    'x'.padStart(5, 'ab') // 'ababx'
    'x'.padStart(4, 'ab') // 'abax'
    
    'x'.padEnd(5, 'ab') // 'xabab'
    'x'.padEnd(4, 'ab') // 'xaba'

    padStart()用于头部补全,padEnd()用于尾部补全。
    padStart和padEnd一共接受两个参数,第一个参数用来指定字符串的最小长度,第二个参数是用来补全的字符串。
    【九】模板字符串
    增强版的字符串,用反引号(`)标识。它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。

    // 普通字符串
    `In JavaScript '\n' is a line-feed.`
    
    // 多行字符串
    `In JavaScript this is
     not legal.`
    
    console.log(`string text line 1
    string text line 2`);
    
    // 字符串中嵌入变量
    let name = "Bob", time = "today";
    `Hello ${name}, how are you ${time}?`

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

    $('#list').html(`
    <ul>
      <li>first</li>
      <li>second</li>
    </ul>
    `);

    上面代码中,所有模板字符串的空格和换行,都是被保留的,比如

    • 标签前面会有一个换行。如果你不想要这个换行,可以使用trim方法消除它。

    $('#list').html(`
    <ul>
      <li>first</li>
      <li>second</li>
    </ul>
    `.trim());

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

    function authorize(user, action) {
      if (!user.hasPrivilege(action)) {
        throw new Error(
          // 传统写法为
          // 'User '
          // + user.name
          // + ' is not authorized to do '
          // + action
          // + '.'
          `User ${user.name} is not authorized to do ${action}.`);
      }
    }

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

    let x = 1;
    let y = 2;
    
    `${x} + ${y} = ${x + y}`
    // "1 + 2 = 3"
    
    `${x} + ${y * 2} = ${x + y * 2}`
    // "1 + 4 = 5"
    
    let obj = {x: 1, y: 2};
    `${obj.x + obj.y}`
    // "3"

    【 十】实例:模板编译:我不懂啊,不懂,过两天重新专门弄一段这个
    【十一】标签模板:它可以紧跟在一个函数名后面,该函数将被调用来处理这个模板字符串。这被称为“标签模板”功能

    function tag(stringArr, value1, value2){
      // ...
    }
    
    // 等同于
    
    function tag(stringArr, ...values){
      // ...
    }

    tag函数的第一个参数是一个数组,该数组的成员是模板字符串中那些没有变量替换的部分,也就是说,变量替换只发生在数组的第一个成员与第二个成员之间、第二个成员与第三个成员之间,以此类推。

    tag函数的其他参数,都是模板字符串各个变量被替换后的值。由于本例中,模板字符串含有两个变量,因此tag会接受到value1和value2两个参数。

    tag函数所有参数的实际值如下。

    第一个参数:[‘Hello ‘, ’ world ‘, ”]
    第二个参数: 15
    第三个参数:50
    也就是说,tag函数实际上以下面的形式调用。

    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
    // "OK"

    这都是些啥…….
    【十二】String.raw()
    String.raw方法,往往用来充当模板字符串的处理函数,返回一个斜杠都被转义(即斜杠前面再加一个斜杠)的字符串,对应于替换变量后的模板字符串。

    String.raw({ raw: 'test' }, 0, 1, 2);
    // 't0e1s2t'
    
    // 等同于
    String.raw({ raw: ['t','e','s','t'] }, 0, 1, 2);
    String.raw = function (strings, ...values) {
      let output = '';
      let index;
      for (index = 0; index < values.length; index++) {
        output += strings.raw[index] + values[index];
      }
    
      output += strings.raw[index]
      return output;
    }

    【十三】模板字符串的限制

    我一定要好好看一眼这个模板是个啥东西,哼(¬︿̫̿¬☆)生气

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值