zoukankan      html  css  js  c++  java
  • ES6/ES2015常用知识点和概念

    越来越多的开源库开始使用ES2015来构建代码了,大家知道ES6=ES2015,ES6在2015年被ECMAScript标准化组织approve,各大浏览器厂商要完全支持ES6的强大功能还须一些时日,对于喜爱新尝试的同学难道只有干等吗?幸运的是有了babel,traceur等transpiler的帮助,我们根本不用等待浏览器原生支持ES6才开始使用新技术了!其实babel做的事情很简单,他就是把es6的代码转换成浏览器认识的ES5代码。简单举一个例子,比如ES6中引入的语言原生支持模块的关键字import, export在仅实现ES5的浏览器中无法运行,因此babel做的就是将import, export转换为commonJS的模块格式require, exports, 随后在加载到浏览器端的SystemJS模块加载器的帮助下(或者通过webpack,browserify Module bundler工具整合),就能完全实现了ES6模块的功能。

    本文视图整理我在学习ES6过程中遇到的一些常见重要知识点和疑惑的问题

    Variable and Parameters

    block scope

    ES6中引入了block scope的概念,配合使用let来declare一个变量的话,该变量就只在block中可见

    if (flag){
      let x = 3; // x只在这个{}block中可见  
    }
    return x; // x is not defined error! 

    declared vs initialized

    var x;  // declared

    x = 5 ; // initialized

    'use strict';
    function udpate(){
      pid = 12;
    }
    let pid = null;
    update();
    console.log(pid); //12  和var声明的变量类似,外部scope可以被inner访问,由于pid在全局定义,函数内可以访问全局变量

    let vs var

    let支持块作用域,不会像var那样hoisted到前面 

    同样let支持for block

    for (let i=0;i <10; i++)
    {
    }
    return i // i not defined, 原因是i只在for loop中可见
    
    for (var i=0;i <10; i++)
    {
    }
    return i // i==10

    let在for loop中以及closure下和传统var的区别

    'use strict';
    let updatefns = [];
    for (let i=0;i<2;i++){
        updatefns.push(function(){
    
        return i; //注意let在for loop中使用时,每一次循环都会在for block中定义一个新的i,所以updatefns[0]()将返回0而不是2~!!
    //好好体会这一点:在es5中的closure则会返回2
    });
      
    consoloe.log(updatefns[0]()); //返回0 
    
    consoloe.log(updatefns[1]()); //返回1 

    const(chrome,firefox支持的,貌似非es6标准)

    const MAX_AGE 130 
    MAX_AGE = 200 //syntax error
    const NOTINIT //语法错误,const必须初始化!

    注意:const的scope和let是一致的,这是es6引入的新特性 

    Destructuring

    let x = 2; 
    let y = 3;
    [x,y] = [y,x] //[3,2]     
    // 右边的是array, 左边不是array,而是destructuring,只对x,和y赋值
    // destructuring assignment, 注意
    
    let [x,y]=[2,3] //这里对x,y两个单个变量赋值: x=2, y=3并且在后面可以直接访问
    expect(x).toBe(2)
    expect(y).toBe(3);
    
    var retv = function(){
          return [1,2,3];
    }
    let [, x , y] = retv(); // [1,2,3]解构  这里 , 号表示忽略部分结构单元
    exepct(x).toBe(2) 
    exepct(y).toBe(3) 
    
    var retO = function(){
       return {
       firstName: "alice",
       lastName: "zhang",
       social: {
             qq: "13442",
             wechat: "wechatalice"
       }
      }
    }
    
    let { firstName: f, lastName: l, social:{wechat: weixin}} = retO();
    //f = "alice", l = "zhang"  , weixin = "wechatalice"
    
    let { firstName, lastNamel, social:{wechat}} = retO();
    //firstName= "alice", lastName = "zhang"  , wechat = "wechatalice"
    
    
    //模拟一个ajax call返回结果解构:
    let ajax = function(url, {data, cache}{
           return data; //注意这里data是从ajax调用者传入的配置对象解构出来data字段后直接返回的
    //在通常的ajax调用中,则从server端返回
    }
    let result = ajax("api/test", {
       data: "test data for ajax", //这是ajax调用的传入对象,可以被ajax解构成变量
       cache: false
    });
    expect(result).toBe("test data for ajax") // true

    再看一些例子:

    let salary = ['1000',3000','2000'];
    let [ low, ...remaining ] = salary; //在destructuring中使用rest操作符
    console.log(remaining); // ["3000","2000"] 
    
    let salary = ['1000',3000'];
    let [ low, average, hight = '8000' ] = salary; //在destructuring中使用默认参数
    console.log(high); // 8000
    
    
    let salary = ['1000',3000'];
    let low, average, hight; // 先let声明变量
    [ low, average, hight = '8000' ] = salary;  //通过destructuring来赋值变量
    console.log(high); // 8000
    
    function reviewSalary([low, average], high = '8000'){
      console.log(average);  //在这里通过destructure传入的数组来赋值average
    }
    reviewSalary(['2000','3000']); //3000

    destucturing object需要注意的点:

    let salary = {
     low: '3000',
     average: '4000',
     high: '5000'
    }
    let newLow, newAverage, newHigh;
    { low: newLow, average: newAverage, high: newHigh} = salary; //注意额,这个是会出现syntax error的,原因是js引擎会认为是一条语句,
    //解决方案是用()括起来
    ({ low: newLow, average: newAverage, high: newHigh} = salary); // 5000
    
    let [high, low] = null; //会出错,destructure的对象必须要支持iterator

     default value(默认参数值)

    var doWork = function(name){
        // es5中对默认name参数的处理方法:使用|| 操作符,如果不传入name,则name就为zhangsan
         name = name || "zhangsan" ;
         return name;
    };
    
    var doWork = function(name = "zhangsan"){
        // es6给name参数一个默认值,如果不传入name,则name就为zhangsan 
         return name;
    };
    
    doWork();
    
    //默认参数同样适用于解构:
    let ajax = function(url, {data = “default data”, cache}{
           return data; //注意这里data是从ajax调用者传入的配置对象解构出来data字段后直接返回的,
    // 如果传入对象不含data,则取默认值 default data
    //在通常的ajax调用中,则从server端返回
    }
    let result = ajax("api/test", {
       cache: false
    });
    expect(result).toBe("default data") // true

     Rest Parameters ...paraName (必须是最后一个参数)

    let sum = function(name, ...numbers){
       // rest parameter必须是函数的最后一个参数 
       let result = 0;
       for (let i=0;i<numbers.length;i++){
          result += numbers[i];  
    }
       return result;
    }
    
    let result = sum("alicechang") // 0    // 如果不传入numbers参数,则numbers就是一个空数组[]
    let result = sum("alicechang",1,2,3) // 6 // 注意这时numbers就是一个数组了[1,2,3]  let result = sum("alicechang",1,3,5,6) //15 // 注意这时numbers就是一个数组了[1,3,5,6]

     Spread Operator ...[a1,a2,a3]

    let dowork = function(x,y,z){
       return x+y+z;
    }
    var result =dowork(...[1,2,3]);  //将数组中的3个数分别传给x,y,z形参
    expect(result).toBe(6)
    
    //也可以用来构建新的数组:
    var a = [4,5,6];
    var b = [1,2,3, ...a, 7,8,9];
    // b就等于 [1,2,3,4,5,6,7,8,9]了!!

     同时也可以用在对字符串的操作上:

    var maxCode = Math.max(..."43201");
    console.log(maxCode);  // 4
    
    var codeArray = ["A",..."BCD","E"];
    console.log(codeArray);// ["A","B","C","D","E"];

    通过...实现配置项的合并

    export default {
        install(vue, opts){
    
            // Merge options argument into options defaults
            const options = { ...optionsDefaults, ...opts }
            
            ...
        }
    }

    Template Literal: `template String ${ varName }`

    let category = "music";
    let id = 1234;
    let url = `http://myserver.com/${category}/${id}`;
    //这时 url中的变量就会被替换,最后的value = http://myserver.com/music/1234

    更多的例子:

    let invoiceNum = '1350';
    console.log(`Invoice Number: ${"INV-"+invoiceNum}`); //Invoice Number: INV-1350
    
    //插值早于函数被调用!
    function showMsg(message){
      let invoiceNum = '99';  //注意这个invoiceNum不会被用到,因为插值要早于函数调用
    }
    let invoiceNum = '1350';
    showMsg(`Invoice Number: ${invoiceNum}`); //Invoice Number: 1350

    template还支持所谓的tag, tag template literal 比如:

    let upper = function(strings,...values){
       let result = "";
       for (var i=0; i <strings.length; i++){
        result+=strings[i];
        if (i<values.length){
            result+= values [i];
      }
    }
    return result.toUpperCase();
    }
    var x = 1; y =3;
    var result = upper `${x} + ${y} is equal to ${x+y}`;
    // result为: 1 + 3 IS EQUAL TO 4

    再看看几个所谓tag template literal的例子:

    function processInvoice(segments){
      console.log(segments);
    }
    processInvoice `template` ; // ["template"] 这是我们的template literal的value
    
    //更复杂一点的例子:
    function processInvoice(segments, ...values){
      console.log(segments);
      console.log(values);
    }
    let invoiceNum = '1350';
    let amount = '2000';
    // 在这里tag就是processInvoice, template literal就是`Invoice......${amount}`
    processInvoice `Invoice: ${invoiceNum} for ${amount}`;  
    //输出内容
    ["Invoice: "," for ", ""]   //这就是所有独立的string内容
    [1350,2000] //这就是所有插值的value

     可以参考: http://exploringjs.com/es6/ch_template-literals.html 来详细了解所谓tag template literal的功用

     

     Arrow Functions =>(this指向问题)

    var getPrice = () => 5.99;
    console.log(typeof getPrice); // function
    var getPrice = count => count*4.00; //只有一个参数时,可以不用()
    console.log(getPrice(2)); // 8

    arrow functions除了具有以上语法格式简洁的优点外,更重要的是为了解决es5中的this难题:

    document.addEventListener('click',function(){
       console.log(this); //这里this为#document(接收事件的哪个对象),而不
    //不是代码执行的context(代码执行时function的context实际上应该是window!
    });
    document.addEventListener('click',() =>
       console.log(this); //这里this为window!也就是function执行时的context
    );

    更多关于arrow function中的this指向问题

    var invoice = {
      number: 123,
      process: function(){
       consoloe.log(this);
     }
    }
    invoice.process(); // object invoice, ES5中this is being set to the object on which the function(owns the this) is called
     
    
    var invoice = {
      number: 123,
      process: () =>{
       consoloe.log(this);
     }
    }
    invoice.process(); // window, arrow function中的this指向context the code running on 
    
    var invoice = {
      number: 123,
      process: function(){
        return () => consoloe.log(this.number);
     }
    }
    involice.process()(); //123, this指向invoice
    
    
    var invoice = {
      number: 123,
      process: function(){
        return () => consoloe.log(this.number);
     }
    }
    var newInvoice = {
      number: 456
    }
    involice.process().bind(newInvoice)(); //123, 注意bind不能绑定一个对象到一个arrow function!甚至js会抛出错误, 不能修改arrow的this
    involice.process().call(newInvoice); //123, 注意call也不能绑定一个对象到一个arrow function!甚至js会抛出错误, 不能修改arrow的this
        

    arrow function不具有prototype属性(传统ES5的函数都具有该属性可以访问使用)

    var getPrice = () => 5.99;
    console.log(getPrice.hasOwnProperty('prototype') //false,因为arrow function不具有prototype属性!

    Object Literal extension

    var price = 5, quantity = 30;
    var productView = {
      price,   // = price: price
      quantity // =quantity: quantity
    }
    console.log(productView); // {price: 5, quantity: 30}
    
    var field = 'dynamicField';
    var price = 5;
    var productView = {
      [field+"-001"]: price
    }
    console.log(productView); //返回{dynamicFiled-001: 5}

    for ... of loops

    var cates = ['hardware','software'];
    for (var item of cates){
       cosole.log(item);   // hardware software
    }
    
    var cates = [,,];
    for (var item of cates){
       cosole.log(item);   // undefined undefined
    }
    
    
    var codes = "ABCDE";
    var count = 0;
    for (var code of codes){
    count++;
    }
    console.log(count); //5 for ... of可以loop字符串

  • 相关阅读:
    设置VMware Player中的虚拟机和宿主机共享文件
    C++20尝鲜:概念(Concepts)
    ReactiveX 学习笔记(31)ReactiveUI 使用笔记
    TypeScript语言学习笔记(4)枚举
    TypeScript语言学习笔记(3)函数,泛型
    趣味编程:FizzBuzz(Haskell版)
    Haskell语言学习笔记(95)Semiring
    Haskell语言学习笔记(94)Enum Bounded
    ReactiveX 学习笔记(30)操作符辨析
    ReactiveX 学习笔记(29)使用 RxCpp(RxQt)+ Qt 进行 GUI 编程
  • 原文地址:https://www.cnblogs.com/kidsitcn/p/5798543.html
Copyright © 2011-2022 走看看