前言
自从ES6标准发布之后,我还没怎么细看,所以关于js的知识总体还留在几年以前。虽然借着Vue,ElmentUI等前端框架能做出实用的界面来,但新瓶还是装着老酒。如果只有我自己,也足以应付很多事情,但涉及到和前端同事合作,有时他们写的新式语法不甚了解时不免略有尴尬。
借着大前端的红火,以及ES6及后期版本的某些语法接近于C#,熟悉起来相对简单。
let命令
众所周知,js的var是很灵活的,灵活到变量未声明前也可使用。
b="bb"
var b="cc"
输出:“bb”
C# var
在很早以前,C#是不支持var的。后来吸取了javascript的var,但也做了一些优化:
- 必须在变量声明时赋值。
可以写var a="1234";
不能写出 var a; a="1234"
- 必须是局部变量
//局部变量a可以用a声明,b必须指定类型
class Program
{
string b = "222";
static void Main(string[] args)
{
var a = "111";
}
}
- 变量声明后,类型确定,不能再改变类型
ES6 let
ES6针对var的优化方式就是新增了let和const,用来区分不同的应用场景
- var可以在未声明变量前使用,let会报错
a="12"
var a="3"
输出:“12”
b="bb"
let b="bb"
输出:Uncaught SyntaxError: Identifier ‘b’ has already been declared
at :1:1
- let声明的变量只在代码块有效
{
let a1="12"
var b2="3"
}
a1
输出:VM486:5 Uncaught ReferenceError: a1 is not defined
at :5:1
{
let a1="12"
var b2="3"
}
b2
输出:“3”
- 暂时性死区
只要块级作用域内存在let,它所声明的变量就“绑定"这个区域,不再受外部的影响。
var tmp = 123;
if (true) {
tmp = 'abc'; // ReferenceError
let tmp;
}
输出:VM566:4 Uncaught ReferenceError: tmp is not defined
at :4:7
(anonymous) @ VM566:4
ES6 明确规定,如果区块中存在let和const命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。
总之,在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。
Module
c#有using,java有import,但以前的javascript却没有相应的模块(module)体系,无法将一个大程序拆分成互相依赖的小文件,再用简单的方法拼装起来。这对开发大型的、复杂的项目形成了巨大障碍。
在 ES6 之前,社区制定了一些模块加载方案,最主要的有 CommonJS 和 AMD 两种。前者用于服务器,后者用于浏览器。ES6 在语言标准的层面上,实现了模块功能,而且实现得相当简单,完全可以取代 CommonJS 和 AMD 规范,成为浏览器和服务器通用的模块解决方案。
ES6 模块的设计思想是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。CommonJS 和 AMD 模块,都只能在运行时确定这些东西。比如,CommonJS 模块就是对象,输入时必须查找对象属性。
// CommonJS模块
let { stat, exists, readFile } = require('fs');
// 等同于
let _fs = require('fs');
let stat = _fs.stat;
let exists = _fs.exists;
let readfile = _fs.readfile;
面代码的实质是整体加载fs模块(即加载fs的所有方法),生成一个对象(_fs),然后再从这个对象上面读取 3 个方法。这种加载称为“运行时加载”,因为只有运行时才能得到这个对象,导致完全没办法在编译时做“静态优化”。
ES6 模块不是对象,而是通过export命令显式指定输出的代码,再通过import命令输入。
// ES6模块
import { stat, exists, readFile } from 'fs';
export 命令
模块功能主要由两个命令构成:export和import。export命令用于规定模块的对外接口,import命令用于输入其他模块提供的功能。
一个模块就是一个独立的文件。该文件内部的所有变量,外部无法获取。如果你希望外部能够读取模块内部的某个变量,就必须使用export关键字输出该变量。下面是一个 JS 文件,里面使用export命令输出变量。
// profile.js
export var firstName = 'Michael';
export var lastName = 'Jackson';
export var year = 1958;
上面代码是profile.js文件,保存了用户信息。ES6 将其视为一个模块,里面用export命令对外部输出了三个变量。
export的写法,除了像上面这样,还有另外一种。
// profile.js
var firstName = 'Michael';
var lastName = 'Jackson';
var year = 1958;
export {firstName, lastName, year};
Components组件
对我来说,了解Module如何应用最容易的办法,是翻看VUE或ElementUI的源码。
例如alert组件 elementpackagesalertsrcmain.Vue
<template>
//省略
.
.
.
</template>
<script type="text/babel">
const TYPE_CLASSES_MAP = {
'success': 'el-icon-success',
'warning': 'el-icon-warning',
'error': 'el-icon-error'
};
export default {
name: 'ElAlert',
props: {
title: {
type: String,
default: ''
},
type: {
type: String,
default: 'info'
},
//省略...
},
data() {
return {
visible: true
};
},
methods: {
close() {
//省略。
}
},
computed: {
typeClass() {
return `el-alert--${ this.type }`;
},
//省略
}
};
</script>
从这里我们可以看到几个关键点:
- export 用于输出
- props-父组件可以通过props将值传给子组件
总结
官方文档很详细。暂时不想写了。懒惰是罪人