• ES6 学习记录


    一、ECMAScript 和 JavaScript 的关系

    要讲清楚这个问题,需要回顾历史。1996 年 11 月,JavaScript 的创造者 Netscape 公司,决定将 JavaScript 提交给标准化组织 ECMA,希望这种语言能够成为国际标准。次年,ECMA 发布 262 号标准文件(ECMA-262)的第一版,规定了浏览器脚本语言的标准,并将这种语言称为 ECMAScript,这个版本就是 1.0 版。

    该标准从一开始就是针对 JavaScript 语言制定的,但是之所以不叫 JavaScript,有两个原因。一是商标,Java 是 Sun 公司的商标,根据授权协议,只有 Netscape 公司可以合法地使用 JavaScript 这个名字,且 JavaScript 本身也已经被 Netscape 公司注册为商标。二是想体现这门语言的制定者是 ECMA,不是 Netscape,这样有利于保证这门语言的开放性和中立性。

    因此,ECMAScript 和 JavaScript 的关系是,前者是后者的规格,后者是前者的一种实现(另外的 ECMAScript 方言还有 JScript 和 ActionScript)。日常场合,这两个词是可以互换的。

    二、class类和对象

    1、简介

    ①面向对象的思维特点:抽取(抽象)对象共用的属性和行为组织(封装)成一个类(模版)、对类进行实例化,获取类的对象。

    ②js中:对象是一组无序的相关属性和方法的集合,所有的事物都是对象。由属性和方法组成。(属性:事物的特征,方法:事物的行为)

    ③在ES6中可以使用class关键字声明一个类,之后以这个类来实例化对象。

    2、实例

    基本用法:通过class关键字,可以定义类。constructor()方法,这就是构造方法,而this关键字则代表实例对象

    class Point {
    //构造方法
      constructor(x, y) {
    //this关键字则代表实例对象
        this.x = x;
        this.y = y;
      }
    //不需要加function,方法与方法之间不需要逗号分隔
      toString() {
        return '(' + this.x + ', ' + this.y + ')';
      }
    }

    类的继承:通过extends关键字实现继承

    class Point {
      constructor(x, y) {
        this.x = x;
        this.y = y;
      }
    }
    
    class ColorPoint extends Point {
      constructor(x, y, color) {
        this.color = color; // ReferenceError
       //在子类的构造函数中,只有调用super之后,才可以使用this关键字
        super(x, y);
        this.color = color; // 正确
      }
    }
    
    
    //Object.getPrototypeOf方法可以用来从子类上获取父类。可以使用这个方法判断,一个类是否继承了另一个类。
    Object.getPrototypeOf(ColorPoint) === Point

    三、let和const

    1、let 语句声明一个块级作用域的本地变量,并且可选的将其初始化为一个值。

      let允许你声明一个作用域被限制在 级中的变量、语句或者表达式。与 var 关键字不同的是, var声明的变量只能是全局或者整个函数块的。 var 和 let 的不同之处在于后者是在编译时才初始化(见下面)。

    //作用域规则
    function varTest() {
      var x = 1;
      {
        var x = 2;  // 同样的变量!
        console.log(x);  // 2
      }
      console.log(x);  // 2
    }
    
    function letTest() {
      let x = 1;
      {
        let x = 2;  // 不同的变量
        console.log(x);  // 2
      }
      console.log(x);  // 1
    }
    View Code

      let声明的变量只在其声明的块或子块中可用,这一点,与var相似。二者之间最主要的区别在于var声明的变量的作用域是整个封闭函数。

    2、const常量是块级范围的,非常类似用 let 语句定义的变量。但常量的值是无法(通过重新赋值)改变的,也不能被重新声明。

      语法:const name1 = value1 [, name2 = value2 [, ... [, nameN = valueN]]];

      nameN常量名称,可以是任意合法的标识符valueN常量值,可以是任意合法的表达式

      此声明创建一个常量,其作用域可以是全局或本地声明的块。 与var变量不同,全局常量不会变为 window 对象的属性。需要一个常数的初始化器;也就是说,您必须在声明的同一语句中指定它的值(这是有道理的,因为以后不能更改)。

    // 定义常量MY_FAV并赋值7
    const MY_FAV = 7;
    
    // 报错 - Uncaught TypeError: Assignment to constant variable.
    MY_FAV = 20;
    
    // MY_FAV is 7
    console.log('my favorite number is: ' + MY_FAV);
    
    // 尝试重新声明会报错
    // Uncaught SyntaxError: Identifier 'MY_FAV' has already been declared
    const MY_FAV = 20;
    
    // MY_FAV 保留给上面的常量,这个操作会失败
    var MY_FAV = 20;
    
    // 也会报错
    let MY_FAV = 20;
    View Code

    四、数值的扩展

    1、ES6 提供了二进制和八进制数值的新的写法,分别用前缀0b(或0B)和0o(或0O)表示。

    0b111110111 === 503 // true
    0o767 === 503 // true

    2、ES6 在Number对象上,新提供了Number.isFinite()Number.isNaN()两个方法。

    Number.isFinite()用来检查一个数值是否为有限的(finite),即不是Infinity

    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

    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

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

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

    目的是逐步减少全局性方法,使得语言逐步模块化

    Number.parseInt === parseInt // true
    Number.parseFloat === parseFloat // true

    4、Number.isInteger()用来判断一个数值是否为整数。

    Number.isInteger(25) // true
    Number.isInteger(25.1) // false

    5、ES6 在Number对象上面,新增一个极小的常量Number.EPSILON。根据规格,它表示 1 与大于 1 的最小浮点数之间的差。

    五、数组的扩展

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

    // 1 2 3
    
    console.log(1, ...[2, 3, 4], 5)
    // 1 2 3 4 5
    
    [...document.querySelectorAll('div')]
    // [<div>, <div>, <div>]
    View Code

    替代apply方法

    // ES5 的写法
    function f(x, y, z) {
      // ...
    }
    var args = [0, 1, 2];
    f.apply(null, args);
    
    // ES6的写法
    function f(x, y, z) {
      // ...
    }
    let args = [0, 1, 2];
    f(...args);
    View Code

    2、Array.from方法用于将两类对象转为真正的数组:类似数组的对象(array-like object)和可遍历(iterable)的对象(包括 ES6 新增的数据结构 Set 和 Map)。

    let arrayLike = {
        '0': 'a',
        '1': 'b',
        '2': 'c',
        length: 3
    };
    
    // ES5的写法
    var arr1 = [].slice.call(arrayLike); // ['a', 'b', 'c']
    
    // ES6的写法
    let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']
    View Code

    3、Array.of()方法用于将一组值,转换为数组。

    Array.of(3, 11, 8) // [3,11,8]
    Array.of(3) // [3]
    Array.of(3).length // 1
    View Code

    4、数组实例的-find-和-findIndex

    ①数组实例的find方法,用于找出第一个符合条件的数组成员。它的参数是一个回调函数,所有数组成员依次执行该回调函数,直到找出第一个返回值为true的成员,然后返回该成员。如果没有符合条件的成员,则返回undefined

    [1, 4, -5, 10].find((n) => n < 0)
    // -5

    上面代码找出数组中第一个小于 0 的成员。

    [1, 5, 10, 15].find(function(value, index, arr) {
      return value > 9;
    }) // 10

    上面代码中,find方法的回调函数可以接受三个参数,依次为当前的值、当前的位置和原数组。

    ②数组实例的findIndex方法的用法与find方法非常类似,返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1

    [1, 5, 10, 15].findIndex(function(value, index, arr) {
      return value > 9;
    }) // 2

    另外,这两个方法都可以发现NaN,弥补了数组的indexOf方法的不足。

    [NaN].indexOf(NaN)
    // -1
    
    [NaN].findIndex(y => Object.is(NaN, y))
    // 0

    6、数组实例fill,fill方法使用给定值,填充一个数组。

    ['a', 'b', 'c'].fill(7)
    // [7, 7, 7]
    new Array(3).fill(7)
    // [7, 7, 7]

    上面代码表明,fill方法用于空数组的初始化非常方便。数组中已有的元素,会被全部抹去。

    fill方法还可以接受第二个和第三个参数,用于指定填充的起始位置和结束位置。

    ['a', 'b', 'c'].fill(7, 1, 2)
    // ['a', 7, 'c']

    7、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"
    View Code

    如果不使用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']
    View Code

    8、Array.prototype.includes方法返回一个布尔值,表示某个数组是否包含给定的值,与字符串的includes方法类似。ES2016 引入了该方法。

    [1, 2, 3].includes(2)     // true
    [1, 2, 3].includes(4)     // false
    [1, 2, NaN].includes(NaN) // true

    9、数组实例的-flat,flatMap

    ①数组的成员有时还是数组,Array.prototype.flat()用于将嵌套的数组“拉平”,变成一维的数组。该方法返回一个新数组,对原数据没有影响。

    [1, 2, [3, 4]].flat()
    // [1, 2, 3, 4]

    flat()默认只会“拉平”一层,如果想要“拉平”多层的嵌套数组,可以将flat()方法的参数写成一个整数,表示想要拉平的层数,默认为1。

    [1, 2, [3, [4, 5]]].flat()
    // [1, 2, 3, [4, 5]]
    [1, 2, [3, [4, 5]]].flat(2)
    // [1, 2, 3, 4, 5]

    如果不管有多少层嵌套,都要转成一维数组,可以用Infinity关键字作为参数。

    [1, [2, [3]]].flat(Infinity)
    // [1, 2, 3]

    如果原数组有空位,flat()方法会跳过空位。

    [1, 2, , 4, 5].flat()
    // [1, 2, 4, 5]

    ②flatMap()方法对原数组的每个成员执行一个函数(相当于执行Array.prototype.map()),然后对返回值组成的数组执行flat()方法。该方法返回一个新数组,不改变原数组。

    // 相当于 [[2, 4], [3, 6], [4, 8]].flat()
    [2, 3, 4].flatMap((x) => [x, x * 2])
    // [2, 4, 3, 6, 4, 8]

    10、数组实例的copyWithin()方法,在当前数组内部,将指定位置的成员复制到其他位置(会覆盖原有成员),然后返回当前数组。也就是说,使用这个方法,会修改当前数组。

    Array.prototype.copyWithin(target, start = 0, end = this.length)

    它接受三个参数。

    • target(必需):从该位置开始替换数据。如果为负值,表示倒数。
    • start(可选):从该位置开始读取数据,默认为 0。如果为负值,表示从末尾开始计算。
    • end(可选):到该位置前停止读取数据,默认等于数组长度。如果为负值,表示从末尾开始计算。

    这三个参数都应该是数值,如果不是,会自动转为数值。

    // 将3号位复制到0号位
    [1, 2, 3, 4, 5].copyWithin(0, 3, 4)
    // [4, 2, 3, 4, 5]
    
    // -2相当于3号位,-1相当于4号位
    [1, 2, 3, 4, 5].copyWithin(0, -2, -1)
    // [4, 2, 3, 4, 5]
    
    // 将3号位复制到0号位
    [].copyWithin.call({length: 5, 3: 1}, 0, 3)
    // {0: 1, 3: 1, length: 5}
    
    // 将2号位到数组结束,复制到0号位
    let i32a = new Int32Array([1, 2, 3, 4, 5]);
    i32a.copyWithin(0, 2);
    // Int32Array [3, 4, 5, 4, 5]
    
    // 对于没有部署 TypedArray 的 copyWithin 方法的平台
    // 需要采用下面的写法
    [].copyWithin.call(new Int32Array([1, 2, 3, 4, 5]), 0, 3, 4);
    // Int32Array [4, 2, 3, 4, 5]
    View Code
  • 相关阅读:
    函数模板和类模板
    Dojo常用函数
    ☆☆☆Dojo中define和declare的结合使用
    Dojo的declare接口
    Dojo的define接口
    Dojo的on函数(以前的dojo.connect)
    Dojo中的选择器
    Dojo的ready函数:dojo.ready(以前的dojo.addOnLoad)
    Dojo的dojoConfig函数
    Dojo操作dom元素的样式
  • 原文地址:https://www.cnblogs.com/qingdaye/p/14557240.html
Copyright © 2020-2023  润新知