手记

ES6总结(一) 初识

es6总结

xiong.jpg

往期文章

1.es6简介

  • 回顾javascrip组成:
    • 核心(ECMAScript)

      由ECMA-262定义的ECMAScript是一种在国际认可的标准的脚本语言规范,与Web浏览器没有依赖关系。

    • 文档对象模型(DOM)

      DOM(文档对象模型)是 HTML 和 XML 的应用程序接口(API)。DOM 将把整个页面规划成由节点层级构成的文档。HTML或XML页面中的每个组成部分都是某种类型的节点,这些节点又包含着不同类型的数据。

    • 浏览器对象模型(BOM)

      E 3.0 和 Netscape Navigator 3.0 提供了一种特性 - BOM(浏览器对象模型),可以对浏览器窗口进行访问和操作。使用 BOM,开发者可以移动窗口、改变状态栏中的文本以及执行其他与页面内容不直接相关的操作。

  • ECMAScript 6.0(以下简称 ES6)是 JavaScript 语言的下一代标准,已经在 2015 年 6 月正式发布了。它的目标,是使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言。

2.es6转码

  • 转码原因:现在的Chrome浏览器已经支持ES6了,但是有些低版本的浏览器还是不支持ES6的语法,这就需要我们把ES6的语法自动的转变成ES5的语法。

浏览器es6支持度测试:ruanyf.github.io/es-checker

  • 建立工程目录:

    • 先建立一个项目的工程目录,并在目录下边建立两个文件夹:src和dist

    • src:书写ES6代码的文件夹,写的js程序都放在这里。

    • dist:利用Babel编译成的ES5代码的文件夹,在HTML页面需要引入的时这里的js文件。

  • 编写index.html:

    文件夹建立好后,我们新建一个index.html文件,需要注意的是index.html在引入js文件时,引入的是dist目录下的文件。

  • Babel 转码器:
    {  "name": "es6",  "version": "1.0.0",  "description": "",  "main": "index.js",  "scripts": {  "test": "echo \"Error: no test specified\" && exit 1"
      },  "keywords": [],  "author": "",  "license": "ISC",  "devDependencies": {  "babel-cli": "^6.26.0",  "babel-preset-es2015": "^6.24.1"
      }
     }
      {   "presets":[   "es2015"
       ],   "plugins":[]
      }
     //es6  目录src/index.js
     let a=1; console.log(a); 
     //es5  目录dist/index.js "use strict"; var a = 1; console.log(a);
    • 修改package.json文件

    • npm run build 转码指令

      npm run XXX是执行配置在package.json中的脚本

    • 简化转化命令

       {   "name": "es6",   "version": "1.0.0",   "description": "",   "main": "index.js",   "scripts": {   "build": "babel src/index.js -o dist/index.js" //更换指令
         },   "keywords": [],   "author": "",   "license": "ISC",   "devDependencies": {   "babel-cli": "^6.26.0",   "babel-preset-es2015": "^6.24.1"
         }
        }
    • babel src/index.js -o dist/index.js ES6成功转化为ES5的命令

      转换后:

    • 新建.babelrc 在根目录下新建.babelrc文件,并打开录入下面的代码

    • npm init -y 先初始化我们的项目,-y代表全部默认同意,就不用一次次按回车了。命令执行完成后,会在项目根目录下生产package.json文件,可以根据自己的需要进行修改,比如我们修改name的值```
      //package.json文件
      {
      "name": "es6",
      "version": "1.0.0",
      "description": "",
      "main": "index.js",
      "scripts": {
      "test": "echo "Error: no test specified" && exit 1"
      },
      "keywords": [],
      "author": "",
      "license": "ISC"
      }


    • npm install -g babel-cli 全局安装Babel-cli

    • npm install --save-dev babel-preset-es2015 babel-cli 本地安装babel-preset-es2015 和 babel-cli

      成功后package.json文件多了devDependencies选项

3.变量声明

  • let声明
      // 报错
      function func() {   let a = 10;   var a = 1;
      }  // 报错
      function func() {   let a = 10;   let a = 1;
      }  function func(arg) {   let arg; // 报错
      }  function func(arg) {
       {   let arg; // 不报错
       }
      }
    块级作用域的需求场景
    • 内层变量可能会覆盖外层变量。

        var tmp = new Date();  function f() {   console.log(tmp);   if (false) {   var tmp = 'hello world';
         }
        }
        f(); // undefined

      f()方法内定义的tmp变量提升,覆盖外部的变量,所有undefined

    • 用来计数的循环变量泄露为全局变量

        var s = 'hello';  for (var i = 0; i < s.length; i++) {   console.log(s[i]);
        }  console.log(i); // 5

      循环结束后i并没有消失,而是变成了全局变量

    • 块级作用域
       {   let a = 10;   var b = 1;
        }
        a // 报错: a is not defined.
        b // 1
      
        var a = [];  for (var i = 0; i < 10; i++) {
         a[i] = function () {   console.log(i);
         };
        }
        a[6](); // 10
        for (let i = 0; i < 10; i++) {
         a[i] = function () {   console.log(i);
         };
        }
        a[6](); // 6

      分析:在var声明的循环中,在全局范围内都有效,所以全局只有一个变量i。每一次循环,变量i的值都会发生改变,而循环内被赋给数组a的函数内部的console.log(i),里面的i指向的就是全局的i

      在let声明的循环中:变量ilet声明的,当前的i只在本轮循环有效,所以每一次循环的i其实都是一个新的变量,所以最后输出的是6

    • 声明变量不能提升
       // var 的情况
       console.log(foo); // 输出undefined
       var foo = 2; // let 的情况
       console.log(bar); // 报错ReferenceError
       let bar = 2;

      且let不能提升和块级的特性,导致暂时性死区

       var tmp = 123; if (true) {
        tmp = 'abc'; // ReferenceError
        let tmp;
       }

      区块中存在letconst命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。

    • 不允许重复声明
  • const声明
      const PI = 3.1415;
      PI // 3.1415
      PI = 3;  // TypeError: Assignment to constant variable.
    • 性质:块级作用域、不可变量提升、短暂死区、不可重复声明

    • 定义const声明一个只读的常量。一旦声明,常量的值就不能改变。

  • 小知识:javascript6种变量声明

    var命令、function命令、letconst命令、import命令和class命令

4.解构赋值

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

  • 数组解构赋值

 //基础用法
 let [a, b, c] = [1, 2, 3]; let [foo, [[bar], baz]] = [1, [[2], 3]];
 foo // 1
 bar // 2
 baz // 3
 let [ , , third] = ["foo", "bar", "baz"];
 third // "baz"
 let [x, , y] = [1, 2, 3];
 x // 1
 y // 3
 let [head, ...tail] = [1, 2, 3, 4];
 head // 1
 tail // [2, 3, 4]
 let [x, y, ...z] = ['a'];
 x // "a"
 y // undefined
 z // []
 
 //不完全解构,解构不成功,变量的值就等于undefined
 let [foo] = []; //foo的值undefined
 let [bar, foo] = [1]; //foo的值undefined
 
 //解构设置默认值
 let [x, y = 'b'] = ['a']; // x='a', y='b'
 let [x, y = 'b'] = ['a', undefined]; // x='a', y='b'</pre>
  • 对象解构赋值

    与数组解构不同点:数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。

     let { bar, foo } = { foo: "aaa", bar: "bbb" };
     foo // "aaa"
     bar // "bbb"
     let { baz } = { foo: "aaa", bar: "bbb" };
     baz // undefined
  • 字符串结构
  const [a,b,c,d,e,f]="fengai";
  console.log(a);//f
  console.log(b);//e
  console.log(c);//n
  console.log(d);//g
  console.log(e);//a
  console.log(f);//i
  • 函数解构
 //函数数组解构
 function add([x, y]){  return x + y;
 }
 add([1, 2]); // 3
 //函数对象解构
 let json = {  a:'xiao',  b:'feng'
 } function fun({a,b='ha'}){//默认b='ha'
  console.log(a,b);
 }
 fun(json);
  • 圆括号使用

    如果在解构之前就定义了变量,这时候你再解构,编译会报错

 //不使用圆括号
  let {foo} ={foo:'JSPang'};  //使用圆括号
  let foo;
  ({foo} ={foo:'JSPang'});  console.log(foo); //控制台输出jspang

5.字符串扩展

  • for...of 字符串遍历
    for (let codePoint of 'foo') {  console.log(codePoint)
     } // "f"
     // "o"
     // "o"
  • includes(), startsWith(), endsWith()
     let s = 'Hello world!';
     s.startsWith('Hello') // true
     s.endsWith('!') // true
     s.includes('o') // true
    • includes():返回布尔值,表示是否找到了参数字符串。

    • startsWith():返回布尔值,表示参数字符串是否在原字符串的头部。

    • endsWith():返回布尔值,表示参数字符串是否在原字符串的尾部。

  • repeat() 字符串重复次数
 'x'.repeat(3) // "xxx"
 'hello'.repeat(2) // "hellohello"
 'na'.repeat(0) // ""
  • 字符串模板
 //之前版本
  let jspang='字符串';  let blog = '原来'+jspang+'拼接';  //es6版本
  let jspang='字符串';  let blog = '原来${jspang}拼接';  //支持运算
  let a=1;  let b=2;  let result=`${a+b}`;//3

6.正则扩展

  • String.prototype.matchAll

    可以一次性取出所有匹配。不过,它返回的是一个遍历器(Iterator),而不是数组。

 const string = 'test1test2test3';
 
 // g 修饰符加不加都可以
 const regex = /t(e)(st(\d?))/g; 
 for (const match of string.matchAll(regex)) {
  console.log(match);
 }
 // ["test1", "e", "st1", "1", index: 0, input: "test1test2test3"]
 // ["test2", "e", "st2", "2", index: 5, input: "test1test2test3"]
 // ["test3", "e", "st3", "3", index: 10, input: "test1test2test3"]

7.数值的扩展

  • 二进制、八进制表达

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

    0b111110111 === 503 // true0o767 === 503 // true
  • Number.isFinite(), Number.isNaN()

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

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

  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</pre>
  • Number.parseInt(), Number.parseFloat()

    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</pre>
  • Number.isInteger()

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

    Number.isInteger(25) // trueNumber.isInteger(25.1) // false</pre>
  • 安全整数和 Number.isSafeInteger()

    JavaScript 能够准确表示的整数范围在-2^532^53之间(不含两个端点),超过这个范围,无法精确表示这个值。

    • 最大安全数:Number.MAX_SAFE_INTEGER

    • 最小安全数:Number.MIN_SAFE_INTEGER

    • Number.isSafeInteger() :判断一个数是否为安全数

      Number.isSafeInteger('a') // falseNumber.isSafeInteger(null) // falseNumber.isSafeInteger(NaN) // falseNumber.isSafeInteger(Infinity) // falseNumber.isSafeInteger(-Infinity) // falseNumber.isSafeInteger(3) // trueNumber.isSafeInteger(1.2) // falseNumber.isSafeInteger(9007199254740990) // trueNumber.isSafeInteger(9007199254740992) // falseNumber.isSafeInteger(Number.MIN_SAFE_INTEGER - 1) // falseNumber.isSafeInteger(Number.MIN_SAFE_INTEGER) // trueNumber.isSafeInteger(Number.MAX_SAFE_INTEGER) // trueNumber.isSafeInteger(Number.MAX_SAFE_INTEGER + 1) // false

8.Math对象的扩展

  • Math.trunc() 数字取整数
  • Math.sign() 判断一个数是否为正数、负数、0

    参数为正数,返回+1

    参数为负数,返回-1

    参数为 0,返回0

    参数为-0,返回-0;

    其他值,返回NaN

  • Math.cbrt() 计算一个数的立方根。
  • Math.hypot() 返回所有参数的平方和的平方根。
    Math.hypot(3, 4);        // 5Math.hypot(3, 4, 5);     // 7.0710678118654755Math.hypot();            // 0Math.hypot(NaN);         // NaNMath.hypot(3, 4, 'foo'); // NaNMath.hypot(3, 4, '5');   // 7.0710678118654755Math.hypot(-3);          // 3

9.函数的扩展

  • 函数参数设置默认值
    function log(x, y = 'World') { console.log(x, y);
    }
    log('Hello') // Hello Worldlog('Hello', 'China') // Hello Chinalog('Hello', '') // Hello
  • 函数的 length 属性

    指定了默认值以后,函数的length属性,将返回没有指定默认值的参数个数。也就是说,指定了默认值后,length属性将失真。

    (function (a) {}).length // 1(function (a = 5) {}).length // 0(function (a, b, c = 5) {}).length // 2</pre>

    同理,后文的rest 参数也不会计入length属性。

  • rest 参数

    rest 参数(形式为...变量名),用于获取函数的多余参数,这样就不需要使用arguments对象了。rest 参数搭配的变量是一个数组,该变量将多余的参数放入数组中。

rest是真数组

function add(...values) { let sum = 0; for (var val of values) {
 sum += val;
 } return sum;
 }
 add(2, 5, 3) // 10
 //剩余参数
 function feng(first,...arg){ for(let val of arg){ console.log(val); //1,2,3,4,5,6,7
 }
 }
 feng(0,1,2,3,4,5,6,7);
  • arguments回顾

    arguments对象不是数组,而是一个类似数组的对象,伪数组

    arguments.length 参数个数

    arguments[0] 第一个参数,...

    转换成真数组:

    function arg2arr(){ var arr = Array.prototype.slice.call(arguments); console.log(arr);
    }
    arg2arr(1,2,3);
  • name 属性

    函数的name属性,返回该函数的函数名。

    function foo() {}
    foo.name // "foo"</pre>
  • 箭头函数
    var f = () => 5;// 等同于var f = function () { return 5 };var sum = (num1, num2) => num1 + num2;// 等同于var sum = function(num1, num2) { return num1 + num2;
    };//多个代码段用{}var sum = (num1, num2) => { 
     console.log("feng"); return num1 + num2; 
     }
    • 函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。

    • 不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。

    • 不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。

  • 函数体中的严格模式

    我们在ES中就经常使用严谨模式来进行编程,但是必须写在代码最上边,相当于全局使用。在ES6中我们可以写在函数体中,相当于针对函数来使用。

    function add(a,b=1){ 'use strict'
     if(a == 0){ throw new Error('This is error');
     } return a+b;
    }console.log(add(1));
  • 双冒号运算符

    函数绑定运算符是并排的两个冒号(::),双冒号左边是一个对象,右边是一个函数。该运算符会自动将左边的对象,作为上下文环境(即this对象),绑定到右边的函数上面。(可替代apply,call,bind)

    foo::bar;// 等同于bar.bind(foo);
    
    foo::bar(...arguments);// 等同于bar.apply(foo, arguments);const hasOwnProperty = Object.prototype.hasOwnProperty;function hasOwn(obj, key) { return obj::hasOwnProperty(key);
    }

10.数组的扩展

  • 扩展运算符

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

    console.log(...[1, 2, 3])// 1 2 3console.log(1, ...[2, 3, 4], 5)// 1 2 3 4 5[...document.querySelectorAll('div')]// [<div>, <div>, <div>]//替代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);
    [...'hello']
     // [ "h", "e", "l", "l", "o" ]</pre>
    • 复制数组

      数组是复合的数据类型,直接复制的话,只是复制了指向底层数据结构的指针,而不是克隆一个全新的数组。

        const a1 = [1, 2];  const a2 = a1;//传址而非传值
        a2[0] = 2;
        a1 // [2, 2]
        //改变a2会影响a1的值

      ...扩运算克隆

      const a1 = [1, 2];// 写法一const a2 = [...a1];// 写法二</pre>
    • 合并数组

      const arr1 = ['a', 'b'];
      const arr2 = ['c'];
      const arr3 = ['d', 'e'];
      
      // ES5 的合并数组
      arr1.concat(arr2, arr3);
      // [ 'a', 'b', 'c', 'd', 'e' ]
      
      // ES6 的合并数组
      [...arr1, ...arr2, ...arr3]
      // [ 'a', 'b', 'c', 'd', 'e' ]
    • 与解构赋值结合

      // ES5a = list[0], rest = list.slice(1)// ES6[a, ...rest] = list
    • 字符串
  • Array.from() 将伪数组转化为真数组
    //伪数组: 1、伪数组是一个对象  2、这个对象必须要有length属性 3、如果这个对象的length不为0,那么必须要有按照下标存储的数据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'];/ arguments对象function foo() {var args = Array.from(arguments);// ...}
  • Array.of() 将一组值,转换为数组
    Array.of(3, 11, 8) // [3,11,8]Array.of(3) // [3]Array.of(3).length // 1
  • find() 和 findIndex()实例方法

    find(): 用于找出第一个符合条件的数组成员。

    回调函数参数依次为当前的值当前的位置原数组

     find(function(value, index, arr) {  return value > 9;
     })</pre>

    findIndex(): 数组实例的findIndex方法的用法与find方法非常类似,返回第一个符合条件的数组成员的位置

  • fill()实例方法 用给定值填充数组
 ['a', 'b', 'c'].fill(7) // [7, 7, 7]
 
 new Array(3).fill(7) // [7, 7, 7]
  • entries(),keys() 和 values()实例方法 数组遍历 同 for...of 循环使用

    keys()是对键名的遍历

    values()是对键值的遍历

    entries()是对键值对的遍历

    for (let index of ['a', 'b'].keys()) {console.log(index);
    }// 0// 1for (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"
  • includes()实例方法 判断数组是否包含某一数组元素
    [1, 2, 3].includes(2)     // true[1, 2, 3].includes(4)     // false[1, 2, NaN].includes(NaN) // true
  • entries( )实例方法

    entries()实例方式生成的是Iterator形式的数组,那这种形式的好处就是可以让我们在需要时用next()手动跳转到下一个值。我们来看下面的代码:

    let arr=['hao','ha','hi']let list=arr.entries();console.log(list.next().value);//haoconsole.log(list.next().value);//haconsole.log(list.next().value);//hi

11.对象的扩展

  • 声明变量直接赋值
    let name="jspang";let skill= 'web';var obj= {name,skill};console.log(obj);  //Object {name: "jspang", skill: "web"}
  • 对象Key值构建

    有时候我们会在后台取出key值,而不是我们前台定义好的,这时候我们如何构建我们的key值那。比如我们在后台取了一个key值,然后可以用[ ] 的形式,进行对象的构建

    let key='skill';var obj={
     [key]:'web'}console.log(obj.skill);
  • Object.is( ) 对象比较

    ES5 比较两个值是否相等,只有两个运算符:相等运算符(==)和严格相等运算符(===)。它们都有缺点,前者会自动转换数据类型,后者的NaN不等于自身

    Object.is就是部署这个算法的新方法。它用来比较两个值是否严格相等,与严格比较运算符(===)的行为基本一致

    var obj1 = {name:'feng'};var obj2 = {name:'feng'};console.log(obj1.name === obj2.name);//trueconsole.log(Object.is(obj1.name,obj2.name)); //trueconsole.log(+0 === -0);  //trueconsole.log(NaN === NaN ); //falseconsole.log(Object.is(+0,-0)); //falseconsole.log(Object.is(NaN,NaN)); //true
  • Object.assign() 对象的合并

    Object.assign(参数1,参数2,参数3) 将源对象(source)的所有可枚举属性,复制到目标对象(target)

    一个参数是目标对象,后面的参数都是源对象

    const target = { a: 1 } 
    const source1 = { b: 2 };const source2 = { c: 3 };Object.assign(target, source1, source2);
    target // {a:1, b:2, c:3}

    注意:

    Object.assign([1, 2, 3], [4, 5])
    // [4, 5, 3]
    //相当于同名属性替换
    ```

    • 浅拷贝 拷贝对象属性的址,而非值

      const obj1 = {a: {b: 1}};const obj2 = Object.assign({}, obj1);
      
      obj1.a.b = 2;
      obj2.a.b // 2
    • 同名属性替换

      const target = { a: { b: 'c', d: 'e' } }const source = { a: { b: 'hello' } }Object.assign(target, source)// { a: { b: 'hello' } }
    • 数组处理


  • Object.keys(),Object.values(),Object.entries()

    Object.keys() 返回对象所有键的新数组

    var obj = { foo: 'bar', baz: 42 };Object.keys(obj)// ["foo", "baz"]

    Object.values() 返回对象所有值的新数组

    const obj = { 100: 'a', 2: 'b', 7: 'c' };Object.values(obj)// ["b", "c", "a"]

    Object.entries() 返回对象所有键值对的新数组

    const obj = { foo: 'bar', baz: 42 };
    Object.entries(obj)
    // [ ["foo", "bar"], ["baz", 42] ]

12.in的用法

in是用来判断对象或者数组中是否存在某个值的。我们先来看一下用in如何判断对象里是否有某个值

判断对象:

let obj={ a:'jspang', b:'技术胖'}console.log('a' in obj);  //true

判断数组:

ES5判断的弊端:以前会使用length属性进行判断,为0表示没有数组元素。但是这并不准确,或者说真实开发中有弊端

let arr=[,,,,,];console.log(arr.length); //5 这是个坑//es6let arr=[,,,,,];console.log(0 in arr); //false  空数组,判断0下标是否存在let arr1=['jspang','技术胖'];console.log(0 in arr1);  // true



作者:理想三旬7
链接:https://www.jianshu.com/p/969460bd4951


0人推荐
随时随地看视频
慕课网APP