• Vue.js源码中大量采用的ES6新特性介绍:模块、let、const


    1 关于ES6
          ECMAScript6(以下简称ES6)是JavaScript语言的最新一代标准,发布于2015年6月,因为ECMA委员会决定从ES6起每年更新一次标准,因此ES6被改名为ES2015,后面的标准将按照发布的年份命名,比如ES2016、ES2017。

           ES6引入了很多新特性,这些特性解决了JavaScript长久以来别开发者所诟病的很多缺点。同时,ES6也给JavaScript的语言带来了重大变革,它使JavaScript变得更加强大、更富有表现力。尽管属于重大升级,但ES6仍然秉持了最大化兼容已有代码的设计理念,因此采用ES5及之前的标准编写的JavaScript代码在ES6环境下将继续正常运行。

           由于发布日期尚短,当前主流的浏览器对ES6还没有全面支持,不过好消息是支持程度正在逐步提高,目前在各大浏览器的最新版本中ES6的大部分特性都已经实现。而Node.js对ES6的支持性还要优于浏览器,通过node可以体验更多ES6特性。也可以使用Babel等JavaScript预编译器将ES6代码转化WieES5代码,从而在现有环境中执行。

    2 模块
           历史上,JavaScript一直没有模块的概念,这会导致当项目大到一定程度时JavaScript代码将变得难以复用且极难维护。因此,在相当长的一段时间内,对于大型复杂项目来说,JavaScript基本从一开始就被排除在方案之外。JavaScript官网一直缺少对模块的定义,直到ES6出现。

           ES6从官方标准中带来了模块化开发规范。下面主要介绍模块化开发当中最重要的export和import概念。

    export
           在ES6中,一个文件就是一个模板,一个模板内的所有变量,对于外部来说都是无法获取的,除非使用关键词export对外暴露接口,暴露的各接口通过名字来进行区分。如以下代码,lib.js模块通过sqrt、square、diag向外界暴露三个接口。

    //---------lib.js-----------
    /*
    暴露三个接口给外界
    */
    export const sqrt=Math.sqrt;
    export function square(x){
      retrun x*x;
    }
    export function diag(x,y){
      return sqrt(Square(x)+Square(y));


          export也可以采用下面的方式暴露接口:

    //---------lib.js-----------
    const sqrt=Math.sqrt;
     
    function square(x){
      retrun x*x;
    }
     
    function diag(x,y){
      return sqrt(Square(x)+Square(y));
    //通过export暴露接口的第二种语法,使用大括号指定要暴露的接口
    export{sqrt,square,dig};


    //通过export暴露接口的第二种语法,使用大括号指定要暴露的接口
    export{sqrt,square,dig};
          通常情况下,export暴露的接口就是器本来的名字,不过可以采用as语法进行别名export,这种导出方式可以将一个接口通过n个名字对外暴露。示例代码如下:

    //---------lib.js-----------
    const sqrt=Math.sqrt;
    export{sqrt as sq1,sqrt as sq2}; 

         
    注:在ES6规范中,如果b模块从a模块中导入一个原始值后,在a模块中修改了这个原始值,那么b模块中的值也会与a模块中最新的值保持同步,即export暴露的接口与其在模块内部对应的值是一种动态绑定的关系,通过接口可以获取模块内部实时的值。

    import
           使用export命令对外暴露接口以后,其他JavaScript文件就可以通过import命令加载这个模块(文件)。在main.js模块中就可以通过import引入上一节中lib.js暴露的接口,代码示例如下:

    //---------main.js-----------
    /*
    通过import语法从lib模块中导入所需要的接口,大括号中的接口名必须在lib.js模块中,通过export关键词导出
    */ 
    import {square,diag} from './lib';
    console.log(square(11)); //121
    console.log(diag(4,3));//5


           import也可以采用as语法对引入的变量重命名,代码示例如下:

    //---------lib.js-----------
    export var myVar1="var1";
    //---------main.js-----------
    import{myVar1 as myCustomVar1} from './lib';
    console.log(myCustomVar1);


           import会执行加载的模块,因此有空import的语法。代码示例如下:

    //只加载执行模块,不引用任何接口
    import 'lib'
           import 还可以整体加载模块,达到命名空间的效果。代码示例如下:

    //---------lib.js-----------
    export var myVar1=...;
    export var myVar2=...;
    export const MY_CONST=...;
    
    export function myFunc(){
    ...
    }
    export function* myGeneratorFunc(){
    ...
    }
    export class MyClass{
    ...
    }
    //---------main.js-----------
    import * as lib from './lib';
    console.log(lib.myVar1);
    console.log(lib.myVar2);
    new lib.MyClass();
    export default


           有时候一个模块实际上只对外暴露一个接口,这时候实际上没必要再限定暴露的接口名字,在ES6中可以使用export default语法让模块调用者自定义要导入的接口的名字。代码示例如下:

    //---------myFunc.js-----------
    export default function(){}
    //---------main1.js-----------
    /*
    注意:myFunc不能包含在{}里;myFunc可以替换为任意喜欢的名字
    */
    import myFunc from 'myFunc';
    myFunc();


    本质上,export default就是输出一个名为default的变量或方法,然后系统允许我们进行重命名。代码示例如下:

    //lib.js
    function add(x,y){
    return x*y;
    }
    export {add as default};
    
    //等同于
    //export default add;
    
    //main.js
    import {default as myAdd} from 'lib';
    
    //等同于
    //import myAdd form 'lib';


          使用export default命令,可以直观地引入模块,比如引用jquery模块可以这样写:

    import $ form 'jquery';
    export/import在Vue.js中的使用
          Vue.js采用export/import进行模块化开发,文件通过export暴露接口,通过import引用其他文件的内容。Vue.js的源码结构优雅、层次严谨,而这一切都离不开export和import。
    
          举例来说,Vue.js的入口文件是/src/index.js,该文件开头如下:
    
    import Vue from './instance/vue'
    import installGlobalAPI from './global-api'
    import {inBrowser, devtools} from './util/index'
    import config from './config'
          index.js从其他4个文件引用了必要的变量和方法。进入引用的第一个文件/src/instance/vue.js中,可以看到,其采用了export default命令:
    
    export default Vue
           也有不采用export default方式暴露接口的,比如在/src/filters/array-filters.js中采用以下语法对外暴露了三个函数方法:
    
    export function limitBy(...){},
    export function limitBy(...){},
    export function limitBy(...){}
    在/src/filters/index.js中引入上述三个函数:
    
    import{orderBy,filterBy,limitBy} from './array-filters'

    3 let
           代码中任何一对花括号({和})中的语句集都属于一个块,其中定义的所有变量在代码块外都是不可见的,称之为块级作用域。在ES5及之前的版本中均不存在块级作用域,只有全局作用域和函数作用域。由此带来的问题很多,比如内层变量可能会覆盖外层变量、用于计数的循环变量泄露为全局变量等。以往,开发者往往要通过闭包等方式来模拟块级作用域,非常繁琐。

           let关键词的出现为JavaScript带来了期待已久的块级作用域。

    (1)let的使用

            let的作用是声明变量,用法类似于var。与var所不同的是,let声明的变量只在let命令所在的代码块内有效。代码示例如下:

    {
    let a='ddfe';
    var b='didiFamily';
    }


            在let中声明的a的代码块之外调用a会报错,用var声明的b可以返回正确的值。这表明let声明的变量只在其所在代码块内有效。

    let很适合用来声明循环变量。代码示例如下:
    for(let i=0;i<10;i++){
    ...//i只在for循环体内有效
    }
    console.log(i);//ReferenceError: i is not defined
    let不允许重复声明。在相同作用域内,重复声明同一个变量会报错。代码示例如下:

    {
    let a='ddfe';
    let a='didiFamilyt'//报错
    }
    
    {
    let a='ddfe';
    var a='didiFamilyt'//报错
    }


    let不存在变量提升。因此,变量需要在声明后才可以使用,否则会报错。代码示例如下:

    console.log(foo);//输出undefined
    console.log(bar);//报错ReferenceError
    
    var foo='ddfe';
    let bar='ddfe';


    let存在暂时性死区(temporal deadzone,以下简称TDZ),即指在当前代码块内如果使用了let声明变量,则在该条声明语句之前,该变量不可用。代码示例如下:

    if(true){
    //TDZ开始
    tmp='ddfe';//ReferenceError
    console.log(tmp);//ReferenceError
    
    let tmp;//TDZ结束
    console.log(tmp);//undefined
    
    tmp=123;
    console.log(tmp);//123
    }


    (2)let在Vue.js中的使用

            由于使用let具有严谨、不易发生错误同时含有块级作用域等诸多优点,在Vue.js中运用let命令的情况比较多,比如:

    //在src/config.js文件中保存了全局配置信息
    let delimiters=['{{','}}']
    let unsafeDelimiters=['{{{','}}}']
            再比如:在src/batcher.js文件中,runBatcherQueue函数中的for循环变量也是采用let声明的:
    
    function runBatcherQueue(queue){
    for(let i=0;i<queue.lenght;i++){
    ...
    }
    queue.length=0
    }

    4 const
    (1) const的使用

    const用于声明一个变量,一旦声明,常量的值便不能再被更改,进入只读模式。代码示例如下:

    const PI=3.141;
    PI//3.141
    PI=3;
    PI//3.141,重新赋值无效,PI值不变


    使用const声明后不得再更改的特性,也就是说在声明变量时就必须初始化,不能留到以后再赋值。代码示例如下:

    const ddfe;
    ddfe='wonderful';//重新赋值无效
    ddfe//undefined
    const的作用域与let相同,只在声明所在的块级作用域内有效。
    const与let一样,同样不允许重复声明,不存在变量提升以及TDZ。
    const在声明复合类型的变量时,只能保证变量名指向的地址不变,并不保证该地址的数据不变(因为复合类型的变量名指向数据地址而不指向数据)。因此,如果使用const声明一个对象,并不能保证对象不可更改。示例代码如下:
    const ddfe={};
    ddfe.age=4;
    ddfe.age//4
    ddfe={};// TypeError: "foo" is read-only


          由上例可以看到,使用const声明一个对象ddfe后,对象内的属性仍然可以修改。但不可改变ddfe指向的对象的地址。若想达到对象本身不可变的效果,应当使用Object.freeze方法。

    (2)const在Vue.js中的使用

          在Vue.js中对于一些常用的变量都采用了const方式声明。比如在src/transition/transition.js中,对transition的动画类型的声明便采用了const命令。代码示例如下:

    const TYPE_TRANSITION='transition'
    const TYPE_ANIMATION='animation'


          再比如,很多正则检测用的变量,也都使用const声明,因为这些都是一经声明就不再更改的常量。代码示例如下:

    // src/compiler/compile.js
    const bindRE=/^v-bind:|^:/
    
    // src/filters/index.js
    const digitsRE=/(d{3})(?=d)/g


    参考:https://blog.csdn.net/bluedandelion/article/details/80625961 

  • 相关阅读:
    R语言 逐步回归分析
    R语言 一元线性回归
    基于Qt的信号分析简单应用软件的设计
    【图论 5】图的应用——拓扑排序和关键路径
    【图论 3】图的应用——最小生成树
    B+树
    大概是最简明的B树博客了
    KMP算法
    【内存管理篇】基本分页存储管理方式
    双向链表为何时间复杂度为O(1)?
  • 原文地址:https://www.cnblogs.com/panchanggui/p/10856225.html
Copyright © 2020-2023  润新知