美文网首页
ES6新增扩展属性及语法格式

ES6新增扩展属性及语法格式

作者: 吴高亮 | 来源:发表于2017-08-18 19:45 被阅读0次

    let块级作用域

    怎么样更好的认识let;就是现有的声明方式进行比较;

    1:var的声明提升会在未初始化变量的时候提醒undefined;但是不报错;未遵循先定义后使用的逻辑;
    但是let是遵循的先定义后使用;未定义就是用的情况会报错;
    2:官方中的‘暂时性死区’;在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”;但是var不会;如图;在使用let绑定后;也就绑定了区块;在代码块内;let声明就会出现暂时死区;


    image.png

    3:不允许重复声明:前提是在统一代码块内;另外函数内部也不可以声明和和参数相同的变量;但是下图的方式可以;也就是刚才说到的在统一代码块内;


    image.png

    2:块级作用域存在的意义;

     首先防止内城变量覆盖外层变量;第二场景用来计数的循环变量泄露为全局变量;
    

    变量的解构【比较重要和常用】

    下面仅仅总结常用的一些语法;
    首先截取剩余的数组;
    let [head, ...tail] = [1, 2, 3, 4]; head // 1 tail // [2, 3, 4] 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();
    (4)提取 JSON 数据 解构赋值对提取 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] 上面代码可以快速提取 JSON 数据的值。

    字符串的扩展

    1:includes(str,开始检索的下标);使用includes()来代替indexOf;判断是否含有某个字符串;
    2:startsWith(str,开始检索的下标):返回布尔值,表示参数字符串是否在原字符串的头部。
    3:endsWith(str,检索这个下标前的数字):返回布尔值,表示参数字符串是否在原字符串的尾部。
    4:repeat方法返回一个新字符串,表示将原字符串重复n次
    5:padStart()用于头部补全,padEnd()用于尾部补全;这两个方法在
    

    第六章数值的扩展

    1:Number.isFinite()用来检查一个数值是否为有限的(finite)。

    Number.isFinite(15); // true
    Number.isFinite(0.8); // true
    Number.isFinite(NaN); // false
    Number.isFinite(Infinity); // false
    Number.isFinite(-Infinity); // false
    Number.isFinite('foo'); // false
    Number.isFinite('15'); // false
    Number.isFinite(true); // false
    

    2:Number.isNaN()用来检查一个值是否为NaN。

    Number.isNaN(NaN) // true
    Number.isNaN(15) // false
    Number.isNaN('15') // false
    Number.isNaN(true) // false
    Number.isNaN(9/NaN) // true
    Number.isNaN('true'/0) // true
    Number.isNaN('true'/'true') // true
    补充:Number.isInteger();Number.isInteger()用来判断一个值是否为整数。需要注意的是,在 JavaScript 内部,整数和浮点数是同样的储存方法,所以3和3.0被视为同一个值。
    

    对比:

    它们与传统的全局方法isFinite()和isNaN()的区别在于,传统方法先调用Number()将非数值的值转为数值,再进行判断,而这两个新方法只对数值有效,Number.isFinite()对于非数值一律返回false, Number.isNaN()只有对于NaN才返回true,非NaN一律返回false。

    isFinite(25) // true
    isFinite("25") // true
    Number.isFinite(25) // true
    Number.isFinite("25") // false
    
    isNaN(NaN) // true
    isNaN("NaN") // true
    Number.isNaN(NaN) // true
    Number.isNaN("NaN") // false
    Number.isNaN(1) // false
    

    3:ES6 将全局方法parseInt()和parseFloat(),移植到Number对象上面,行为完全保持不变。

    // ES5的写法
    parseInt('12.34') // 12
    parseFloat('123.45#') // 123.45
    
    // ES6的写法
    Number.parseInt('12.34') // 12
    Number.parseFloat('123.45#') // 123.45
    

    4:Number.EPSILON;ES6在Number对象上面,新增一个极小的常量Number.EPSILON。

    5.551115123125783e-17 < Number.EPSILON  但是如果这个误差能够小于Number.EPSILON,我们就可以认为得到了正确结果。
    

    5:Math方法的扩展;Math.trunc方法用于去除一个数的小数部分,返回整数部分。

    Math.trunc(4.1) // 4
    Math.trunc(4.9) // 4
    Math.trunc(-4.1) // -4
    Math.trunc(-4.9) // -4
    Math.trunc(-0.1234) // -0
    对于非数值,Math.trunc内部使用Number方法将其先转为数值。
    对于空值和无法截取整数的值,返回NaN。
    Math.trunc('123.456')
    Math.trunc(NaN);      // NaN
    Math.trunc('foo');    // NaN
    Math.trunc();         // NaN
    

    函数扩展

    1:函数参数的默认值;

    ES6之前的默认值显示方法
    function log(x, y) {
      y = y || 'World';
      console.log(x, y);
    }
    
    log('Hello') // Hello World
    log('Hello', 'China') // Hello China
    log('Hello', '') // Hello World
    上面代码检查函数log的参数y有没有赋值,如果没有,则指定默认值为World。这种写法的缺点在于,如果参数y赋值了,但是对应的布尔值为false,
    则该赋值不起作用。就像上面代码的最后一行,参数y等于空字符,结果被改为默认值。
    为了避免这个问题,通常需要先判断一下参数y是否被赋值,如果没有,再等于默认值。
    if (typeof y === 'undefined') {
      y = 'World';
    }
    
    ES6 允许为函数的参数设置默认值,即直接写在参数定义的后面。
    function log(x, y = 'World') {
      console.log(x, y);
    }
    
    log('Hello') // Hello World
    log('Hello', 'China') // Hello China
    log('Hello', '') // Hello
    

    注意;

    参数变量是默认声明的,所以不能用let或const再次声明。
    function foo(x = 5) {
      let x = 1; // error
      const x = 2; // error
    }
    

    与结构结合的用法;

    function foo({x, y = 5}) {
      console.log(x, y);
    }
    
    foo({}) // undefined 5
    foo({x: 1}) // 1 5
    foo({x: 1, y: 2}) // 1 2
    foo() // TypeError: Cannot read property 'x' of undefined
    基础用法和注意事项:上面代码只使用了对象的解构赋值默认值,没有使用函数参数的默认值。
    只有当函数foo的参数是一个对象时,变量x和y才会通过解构赋值生成。如果函数foo调用时没提供参数
      ,变量x和y就不会生成,从而报错。通过提供函数参数的默认值,就可以避免这种情况。
    
    
    function fetch(url, { body = '', method = 'GET', headers = {} }) {
      console.log(method);
    }
    
    fetch('http://example.com', {})
    // "GET"
    
    fetch('http://example.com')
    // 报错
    

    // 写法一
    function m1({x = 0, y = 0} = {}) {
      return [x, y];
    }
    
    // 写法二
    function m2({x, y} = { x: 0, y: 0 }) {
      return [x, y];
    }
    

    上面两种写法都对函数的参数设定了默认值,区别是写法一函数参数的默认值是空对象,但是设置了对象解构赋值的默认值;写法二函数参数的默认值是一个有具体属性的对象,但是没有设置对象解构赋值的默认值。

    // 函数没有参数的情况
    m1() // [0, 0]
    m2() // [0, 0]
    
    // x 和 y 都有值的情况
    m1({x: 3, y: 8}) // [3, 8]
    m2({x: 3, y: 8}) // [3, 8]
    
    // x 有值,y 无值的情况
    m1({x: 3}) // [3, 0]
    m2({x: 3}) // [3, undefined]
    
    // x 和 y 都无值的情况
    m1({}) // [0, 0];
    m2({}) // [undefined, undefined]
    
    m1({z: 3}) // [0, 0]
    m2({z: 3}) // [undefined, undefined]
    

    参数默认值的位置

    // 例一
    function f(x = 1, y) {
      return [x, y];
    }
    
    f() // [1, undefined]
    f(2) // [2, undefined])
    f(, 1) // 报错
    f(undefined, 1) // [1, 1]
    
    // 例二
    function f(x, y = 5, z) {
      return [x, y, z];
    }
    
    f() // [undefined, 5, undefined]
    f(1) // [1, 5, undefined]
    f(1, ,2) // 报错
    f(1, undefined, 2) // [1, 5, 2]
    

    rest 参数

    ES6 引入 rest 参数(形式为...变量名),用于获取函数的多余参数,
    这样就不需要使用arguments对象了。rest 参数搭配的变量是一个数组,该变量将多余的参数放入数组中。
    function add(...values) {
      let sum = 0;
      for (var val of values) {
        sum += val;
      }
      return sum;
    }
    
    add(2, 5, 3) // 10
    //正常将argument变为数组的办法就是使用var arr = Array.prototype.slice.apply(arguments);
    或者Array.prototype.slice.call(arguments).sort();
    

    注意:

    1 注意,rest 参数之后不能再有其他参数(即只能是最后一个参数),否则会报错
    // 报错
    function f(a, ...b, c) {
      // ...
    }//就会报错
       2: ES2016 做了一点修改,规定只要函数参数使用了默认值、解构赋值、或者扩展运算符,那么函数内部就不能显式设定为严格模式,否则会报错。
    3:这样规定的原因是,函数内部的严格模式,同时适用于函数体和函数参数。但是,函数执行的时候,先执行函数参数,然后再执行函数体。
    这样就有一个不合理的地方,只有从函数体之中,才能知道参数是否应该以严格模式执行,但是参数却应该先于函数体执行。
    // 报错
    function doSomething(value = 070) {
      'use strict';
      return value;
    }
    上面代码中,参数value的默认值是八进制数070,但是严格模式下不能用前缀0表示八进制,
    所以应该报错。但是实际上,JavaScript 引擎会先成功执行value = 070,然后进入函数体内部,发现需要用严格模式执行,这时才会报错。
    
    虽然可以先解析函数体代码,再执行参数代码,但是这样无疑就增加了复杂性。
    因此,标准索性禁止了这种用法,只要参数使用了默认值、解构赋值、或者扩展运算符,就不能显式指定严格模式。
    两种方法可以规避这种限制。第一种是设定全局性的严格模式,这是合法的。第二种是把函数包在一个无参数的立即执行函数里面。
    

    2:箭头函数

    ES6 允许使用“箭头”(=>)定义函数。

    var f = () => 5;
    // 等同于
    var f = function () { return 5 };
    
    var sum = (num1, num2) => num1 + num2;
    // 等同于
    var sum = function(num1, num2) {
      return num1 + num2;
    };
    

    用法1:与结构的配合

    const full = ({ first, last }) => first + ' ' + last;
    
    // 等同于
    function full(person) {
      return person.first + ' ' + person.last;
    }
    

    用法2:简化回调函数

    [1,2,3].map(function (x) {
      return x * x;
    });
    
    // 箭头函数写法
    [1,2,3].map(x => x * x);
    

    关于箭头函数中this指向问题的变化

    var x=11;
    var obj={
      x:22,
      say:function(){
        console.log(this);
        obj2={
            x:33,
            say:function(){
                console.log(this);
            }
        }
        obj2.say()
      }
    }
    obj.say();//22
    

    数组的扩展属性;

    ES5中数组方法复习:

    image.png

    1:扩展运算符(spread)是三个点(...)。它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列

    ES5中使用toString的方法
    console.log(...[1, 2, 3])
    // 1 2 3
    
    console.log(1, ...[2, 3, 4], 5)
    // 1 2 3 4 5
    
    [...document.querySelectorAll('div')]
    // [<div>, <div>, <div>]
    

    1:该运算符主要用于函数调用

    function push(array, ...items) {
      array.push(...items);
    }
    
    function add(x, y) {
      return x + y;
    }
    
    var numbers = [4, 38];
    add(...numbers) // 42
    
    扩展运算符与正常的函数参数可以结合使用,非常灵活。
    function f(v, w, x, y, z) { }
    var args = [0, 1];
    f(-1, ...args, 2, ...[3]);
    

    2:替代数组的 apply 方法 由于扩展运算符可以展开数组,所以不再需要apply方法,将数组转为函数的参数了。

    // ES5 的写法
    function f(x, y, z) {
      // ...
    }
    var args = [0, 1, 2];
    f.apply(null, args);
    
    // ES6的写法
    function f(x, y, z) {
      // ...
    }
    var args = [0, 1, 2];
    f(...args);
    下面是扩展运算符取代apply方法的一个实际的例子,应用Math.max方法,简化求出一个数组最大元素的写法。
    // ES5 的写法
    Math.max.apply(null, [14, 3, 77])
    
    // ES6 的写法
    Math.max(...[14, 3, 77])
    
    // 等同于
    Math.max(14, 3, 77);
    

    3:另一个例子是通过push函数,将一个数组添加到另一个数组的尾部。

    // ES5的 写法
    var arr1 = [0, 1, 2];
    var arr2 = [3, 4, 5];
    Array.prototype.push.apply(arr1, arr2);
    
    // ES6 的写法
    var arr1 = [0, 1, 2];
    var arr2 = [3, 4, 5];
    arr1.push(...arr2);
    上面代码的 ES5 写法中,push方法的参数不能是数组,所以只好通过apply方法变通使用push方法。有了扩展运算符,就可以直接将数组传入push方法。
    

    扩展运算符的应用

    1:合并数组

    // ES5
    [1, 2].concat(more)
    // ES6
    [1, 2, ...more]
    
    var arr1 = ['a', 'b'];
    var arr2 = ['c'];
    var arr3 = ['d', 'e'];
    
    // ES5的合并数组
    arr1.concat(arr2, arr3);
    // [ 'a', 'b', 'c', 'd', 'e' ]
    
    // ES6的合并数组
    [...arr1, ...arr2, ...arr3]
    // [ 'a', 'b', 'c', 'd', 'e' ]
    

    2:与解构赋值结合

    // ES5
    a = list[0], rest = list.slice(1)
    // ES6
    [a, ...rest] = list
    

    3:扩展运算符还可以将字符串转为真正的数组。

    [...'hello']
    // [ "h", "e", "l", "l", "o" ]
    

    7:数组实例的 entries(),keys() 和 values()

    ES6 提供三个新的方法——entries(),keys()和values()——用于遍历数组。
    它们都返回一个遍历器对象(详见《Iterator》一章),可以用for...of循环进行遍历,
    唯一的区别是keys()是对键名的遍历、values()是对键值的遍历,entries()是对键值对的遍历。
    `for (let index of ['a', 'b'].keys()) {
      console.log(index);
    }
    // 0
    // 1
    for (let elem of ['a', 'b'].values()) {
      console.log(elem);
      }
    // 'a'
    // 'b'
    for (let [index, elem] of ['a', 'b'].entries()) {
      console.log(index, elem);
    }
    // 0 "a"
    // 1 "b"`
    如果不使用for...of循环,可以手动调用遍历器对象的next方法,进行遍历。
    let letter = ['a', 'b', 'c'];
    let entries = letter.entries();
    console.log(entries.next().value); // [0, 'a']
    console.log(entries.next().value); // [1, 'b']
    console.log(entries.next().value); // [2, 'c']
    
    ES5中的迭代的方法.png

    对象中新增的方法;

    var obj={ fun:function(){"函数内容"} } 原来写法,在简写对应的属性的时候,需要名字相同,和定义的对象的属性名字相同,
    const obj={ fun(){"函数的内容"} } ES6中函数的写法
    var target={a:1}; var source1={b:2}; var source2={c:3}; Object.assign(target,source1,source2) 这个时候target的值就是target={a:1,b:2,c:3} Object.assign属于浅拷贝;只是拷贝的指针,如果源对象某个属性的值是对象,那么目标对象拷贝得到的是这个对象的引用。

    :Symbol

    数组的扩展

    扩展运算符(...);就是这三个点

    相关文章

      网友评论

          本文标题:ES6新增扩展属性及语法格式

          本文链接:https://www.haomeiwen.com/subject/aiqrlxtx.html