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)); //
console.log(diag(4,3));//
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);//
}
(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//
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
Vue.js源码中大量采用的ES6新特性介绍:模块、let、const的更多相关文章
- 从template到DOM(Vue.js源码角度看内部运行机制)
写在前面 这篇文章算是对最近写的一系列Vue.js源码的文章(https://github.com/answershuto/learnVue)的总结吧,在阅读源码的过程中也确实受益匪浅,希望自己的这些 ...
- vue.js源码精析
MVVM大比拼之vue.js源码精析 VUE 源码分析 简介 Vue 是 MVVM 框架中的新贵,如果我没记错的话作者应该毕业不久,现在在google.vue 如作者自己所说,在api设计上受到了很多 ...
- Vue.js源码——事件机制
写在前面 因为对Vue.js很感兴趣,而且平时工作的技术栈也是Vue.js,这几个月花了些时间研究学习了一下Vue.js源码,并做了总结与输出.文章的原地址:https://github.com/an ...
- 从Vue.js源码角度再看数据绑定
写在前面 因为对Vue.js很感兴趣,而且平时工作的技术栈也是Vue.js,这几个月花了些时间研究学习了一下Vue.js源码,并做了总结与输出.文章的原地址:https://github.com/an ...
- vue源码分析—Vue.js 源码构建
Vue.js 源码是基于 Rollup 构建的,它的构建相关配置都在 scripts 目录下.(Rollup 中文网和英文网) 构建脚本 通常一个基于 NPM 托管的项目都会有一个 package.j ...
- 2018-11-23 手工翻译Vue.js源码:尝试重命名标识符与文本
续前文: 手工翻译Vue.js源码第一步:14个文件重命名 对core/instance/索引中的变量, 方法进行重命名如下(题图): import { 混入初始化 } from './初始化' im ...
- 【转】从Vue.js源码看异步更新DOM策略及nextTick
在使用vue.js的时候,有时候因为一些特定的业务场景,不得不去操作DOM,比如这样: <template> <div> <div ref="test" ...
- vue.js源码学习分享(一)
今天看了vue.js源码 发现非常不错,想一边看一遍写博客和大家分享 /** * Convert a value to a string that is actually rendered. *转换 ...
- Vue.js 源码分析(一) 代码结构
关于Vue vue是一个兴起的前端js库,是一个精简的MVVM.MVVM模式是由经典的软件架构MVC衍生来的,当View(视图层)变化时,会自动更新到ViewModel(视图模型),反之亦然,View ...
随机推荐
- Oracle系列六 分组函数
分组函数作用于一组数据,并对一组数据返回一个值. 组函数类型 AVG COUNT MAX MIN STDDEV SUM 组函数语法 SELECT [column,] group_function(co ...
- sass、less和stylus 相同与不同
sass.less和stylus的安装使用和入门实践 https://www.jianshu.com/p/1eaf366814e2 stylus 基础教程 https://blog.csdn.net/ ...
- linux中环境变量和系统加载环境变量的顺序
一.系统环境变量: /etc/profile :这个文件预设了几个重要的变量,例如PATH, USER, LOGNAME, MAIL, INPUTRC, HOSTNAME, HISTSIZE, uma ...
- Arduino硬件之NCF技术(近场通信技术)
Arduino硬件之NCF技术(近场通信技术) 版权转载:https://blog.csdn.net/import_sadaharu/article/details/52437488 Android硬 ...
- phaser,开启三个线程分别搜索三个文件夹
Phaser表示“阶段器”,用来解决控制多个线程分阶段共同完成任务的情景问题 启动三个线程,分别对三个文件夹搜索,文件要以txt结尾,修改时间要在一天之内,并将文件路径打印在控制台 /** * 开启三 ...
- Linux学习-基本命令文件操作
终端 1.多个终端 连接linux的客户端可以理解为终端. 命令:tty查看终端 2.不同终端之间的通讯 [root@wyx wyx]# echo 123 > /dev/pts/1 把123发给 ...
- 安装donkeyid
cd /usr/local/php/include/php/ext sudo git clone https://github.com/osgochina/donkeyid.git cd /usr/l ...
- controller进行数据保存以及作用域
controller进行数据保存以及作用域 一.request域 1.ModelAndView 在ModelAndView中进行存键值对,也可以进行跳转的地址存储,但是返回类型必须是ModelAndV ...
- Django——用户认证
Django--用户认证 用户与Authentication(身份验证) Django 用户认证系统处理用户帐号,组,权限以及基于cookie的用户会话. 这个系统一般被称为 auth/auth (认 ...
- CORS和CSRF
CORS和CSRF 什么是CORS?CORS是一个W3C标准,全称是"跨域资源共享",他允许浏览器向夸源服务器,发出XMLHTTPRequest请求,从而克服了AJAX只能同源使用 ...