1.3.1 通过
与大多数的前端框架库一样,在 HTML 页面中,可以通过
<script src="https://unpkg.com/vue@next"></script>
当然,可以将这个链接指向的 JavaScript 文件下载到本地计算机中,再从本地计算机导入。需要说明的是,Vue.js 3 有多个版本,例如 Vue.js 3.0.0、Vue.js 3.1.0等,同时也在不断更新中,通过上面配置的链接可以获取到最新的 Vue 3版本。当然,如果想固定使用某个版本,也可以将链接修改为 https://umpkg.com/vue@3.2.28/dist/vue.global.prod.js,本书中与Vue.js 相关的内容都基于 3.2.28 版本。
1.3.2 通过 npm 导入
在使用 Vue.js开发大型项目时,推荐使用 npm工具来安装 Vue.js。 npm 可以很好地和诸如Webpack 或 Rollup 等模块打包工具配合使用,如示例代码所示。
npm install vue@next
1.3.3 通过 Vue Cli 和 Vite 导入
对于真实的生产项目而言,笔者更推荐采用 Vue Cli 或者 Vite 的方式来创建Vue项目,这更符合前端工程化的思想。
Vue Cli 是一个官方的脚手架工具,基于 Webpack,提供页面应用的快速搭建,并为现代前端工作流提供了功能齐备的构建设置。只需要几分钟的时间就可以运行起来,并带有热重载、保存时 lint 校验以及生产环境可用的构建版本。
Vite是一个Web开发构建工具,基于Rollup,伴随着 Vue 3 而来,由于其原生的 ES6 模块导入方式,可以实现闪电般的冷服务器启动。我们将会在后面的章节深入讲解这两个工具的使用。
1.4 Vue 3 新特性概览
截至目前,Vue.js 的新版本是 3.2。据 Vue.js 的作者表示,新的 Vue3 编写的应用程序性能和运行效果非常好,相较于 Vue2.x 版本,Vue 3 主要有以下几个方面大的改动以及提升:
- 更快
- 更小
- 更易于维护
本节主要对这些新的改动来做一下简单的概述,可能涉及 Vue 3 的新语法,各位读者如果看不懂,我们还会在后面的章节深入讲解的。
1.4.1 更快、更小、更易于维护
- 更快
更快主要体现在Vue3在性能方面的提升,以及在源码层面的改动,主要包括以下方面:
+ 重构虚拟DOM。
+ 事件缓存。
+ 基于Proxy的响应式对象。
1. 重构虚拟 DOM
Vue 3 重写了虚拟 DOM 的实现方法,使得初始渲染/更新可以提速达100%,对于 Vue 2.x 版本的虚拟 DOM 来说,Vue 会遍历 <template> 模板中的所有内容,并根据这些标签生成对应的虚拟 DOM (虚拟 DOM 一般指采用 key/value 对象来保存标签元素的属性和内容),当有内容改变时,遍历虚拟 DOM 来找到变化前后不同的内容,我们称这个过程叫作 diff(different) ,并找到针对这些变化的内容所对应的DOM节点,并改变其内部属性。例如下面这段代码:
当触发响应式时,遍历所有的 <div> 标签和 <p> 标签,找到 {{count}} 变量对应的 <p> 标签的 DOM 节点,并改变其内容。对于那些纯静态 <p> 标签的节点进行 diff 其实是比较浪费资源的,当节点的数量很少时,表现并不明显,但是一旦节点的数量过大,在性能上就会慢很多。对此,Vue 3 在此基础上进行了优化,主要有:
+ 标记静态内容,并区分动态内容(静态提升)。
+ 更新时只 diff 动态的部分。针对上面的代码,Vue 3 中首先会区分出 {{count}} 这部分动态的节点,在进行 diff 时,只针对这些节点进行,从而减少资源浪费,提升性能。
2. 事件缓存
我们知道在 Vue 2.x 中,在绑定 DOM 事件时,例如@click,这些事件被认为是动态变量,所以每次更新视图的时候都会追踪它的变化,然后每次触发都要重新生成全新的函数。在 Vue 3中,提供了事件缓存对象 cacheHandlers,当 cacheHandlers 开启的时候,@click绑定的事件会被标记成静态节点,被放入 cacheHandlers 中,这样在视图更新时也不会追踪,当事件再次触发时,就无须重新生成函数,直接调用缓存的事件回调方法即可,在事件处理方面提升了 Vue 的性能。未开启 cacheHandlers 编译后的代码如下:
```
<div @click="hi">Hello World</div>
//编译后
export function render(\_ctx, \_cache, $props, $setup, Sdata, $options){
return (\_openBlock(),\_createElementBlock("div", {onClick:_ctx.hi},"Hello World1",/\*PROPS\*/,["onClick"]))
}
```
开启cacheHandlers编译后的代码如下:
```
<div @click="hi">Hello World</div>
// 编译后
export function render(\_ctx, \_cache, Sprops, $setup, Sdata, $options) {
return (\_openBlock(),\_createElementBlock("div",{onClick:_cache[0] || (_cache[0]=(...args) => (_ctx.hi && _ctx.hi(...args)))},"Hello World1"))
}
```
可以看到主要区别在于onClick那一行,直接从缓存中读取了回调函数。
3. 基于 Proxy 的响应式对象
在 Vue2.x 中,使用 Object.defineProperty)来实现响应式对象,对于一些复杂的对象,需要循环递归地给每个属性增加 getter/setter 监听器,这使得组件的初始化非常耗时,而 Vue 3中,引入了一种新的创建响应式对象的方法 reactive,其内部就是利用 ES6 的 Proxy API 来实现的,这样可以不用的为每个属性来一一进行添加,以减少开销,提升性能,我们会在后续章节具体讲解 Vue 3 的响应式 和 Proxy API。
- 更小
更小主要体现在包所占容量的大小,我们知道,前端资源一般都属于静态资源,例如JavaSript 文件、HTML 文件等,这些资源都托管在服务器上,用户在使用浏览器访问时,会将这些资源下载下来,所以精简文件包大小是提升页面性能的重要因素。Vue 3 在这方面可以让开发者打包构建出来的资源更小,从而提升性能。
Tree Shaking 是一个术语,通常用于描述移除 JavaScript 上下文中的未引用代码(dead-code),就像一棵大树,将那些无用的叶子都剪掉。它依赖于 ES6 模块语法的静态结构特性,例如 import 和 export ,这个术语和概念在打包工具 Rollup 和 Webpack 中普及开来。例如下面这段ES6代码:
import {get} from'./api.js'
let doSome () =>{
get ()
}
doSome ()
// api.js
let post =()=>{
console.log('post')
}
export post
let get = () =>{
console.log('get')
}
export get
上面的代码中,api.js代码中的 post 方法相关内容是没有被引入和使用的,有了 Tree Shaking 之后,这部分内容是不会被打包的,这就在一定程度上减少了资源的大小。使用Tree Shaking 的原理是引入了 ES6 的模块静态分析,这就可以在编译时正确判断到底加载了什么代码,但是要注意 import 和 export 是 ES6 原生的,而不是通过 Babel 或者 Webpack 转化的。
在 Vue 3中,对代码结构进行了优化,让其更加符合 Tree Shaking 的结构,这样使用相关的 API 时,就不会把所有的都打包进来,只会打包用户用到的API,例如:
<!-- vue 2.x-->
import Vue from 'vue'
new Vue()
Vue.nextTick(()=>())
const obj = Vue.observable(())
<1-- vue 3.x -->
import ( nextTick, observable,createApp ) from 'vue'
nextTick(()=>())
const obj = observable(1))
createApp(())
同理,例如 、 和 等内置组件,如果没有使用,也不会被打包到资源中。
- 更易于维护
- 从Flow迁移到TypeScript
TypeScript 是微软开发的一个开源的编程语言,通过在 JavaScript 的基础上添加静态类型定义构建而成,其通过 TypeScript 编译器或 Babel 转译为 JavaScript 代码,可运行在任何浏览器和操作系统上。TypeScript 引入了很多新的特性,例如类型监测、接口等,这些特性在框架源码的维护上有很大的提升。
在Vue 3的源码结构层面,从 Flow 改成了 TypeScript 来编写,Flow 是一个静态类型检测器,有了它就可以在 JavaScript 运行前找出常见的变量类型的 bug,类似于Java语言中给变量强制指定类型,它的功能主要包括:
+ 自动类型转换。
+ null引用。
+ 处理 undefined is not a function。例如:
// @flow
function foo(x: number): number {
return x + 10
}
foo('hi') //参数x须为number类型,否则会报错
错误信息:
'[flow] string (This type is incompatible with number See also: function call)'
上面这段代码采用了Flow后,如果类型不对就会报错。一般来说,对于 JavaScript 源码框架,引入类型检测是非常重要的,不仅可以减少 bug 的产生,还可以规范一些接口的定义,这些特性和 TypeScript 非常吻合,所以在 Vue 3 中直接采用了 TypeScript 来进行重写,从源码层面来提升项目的可维护性。
2. 源代码目录结构遵循 Monorepo
Monorepo 是一种管理代码的方式,它的核心观点是所有的项目在一个代码仓库中,但是代码分割到一个个小的模块中,而不是都放在 src 这个目录下。这样的分割,使得每个开发者大部分时间只是工作在少数的几个文件夹内,并且也只会编译自己负责的模块,不会导致一个 IDE 打不开太大的项目之类的事情,这样很多事情就简单了很多。
目前很多大型的框架(例如 Babel、React、Angular、Ember、Meteor、Jest等) 都采用了 Monorepo 这种方式来进行源码的管理,当然在自己的业务项目中,也可以使用 Monorepo 来管理代码。
1.4.2 新特性初体验
- 组合式API
在 Vue 2.x 中,组件的主要逻辑是通过一些配置项来编写,包括一些内置的生命周期方法或者组件方法,例如下面的代码:
export default{
name: 'test',
components:{},
Props:{},
data(){
return {}
},
created(){},
mounted(){},
watch:{},
methods:{}
}
上面的代码中,这些基于配置的组件写法称为 Options API (配置式API),Vue 3 的一大核心新特性是引入了 Composition API(组合式API),这使得组件的大部分内容都可以通过 setup方法进行配置。将上述代码改造成组合式 API,代码如下:
import{onMounted, reactive,watch} from 'vue'
export default{
props:{
name:String,
},
name: 'test',
components:{},
setup (props,ctx){
console.log(props.name)
console.log('created')
const data = reactive({
a:1
})
watch{
() => data.a,
(val, oldVal) => {
console.log(val)
}
}
onMounted(()=>{
})
const myMethod = (obj) =>{
}
retrun{
data,
myMethod
}
}
}
上面的代码采用了ES6的语法,并且使用了 Vue3 的 Composition API 中的 setup 方法,可能读者有些看不懂,没关系,我们会在后续章节中具体讲解。
- 内置组件 Teleport、Suspense 和 Fragments 片段
和 都是 Vue 3里面新增的内置组件,这里把内置组件称作可以直接写在里面,而不需要格外引入的组件,例如 就是一个内置组件。而 Fragments 是一种新的特性,让开发者可以不用在 中强制包裹一个根元素,关于 和 的内容会在第3章深入讲解。
- 服务端渲染
在服务端渲染方面,Vue 3 优化了返回 HTML 字符串的逻辑。在 Vue2.x 中,所有的节点(包括一些静态节点)在服务端返回时都会转换为虚拟 DOM,再转换成 HTML 字符串返回给浏览器;Vue 3 则将静态节点剥离成字符串,这部分内容不会转换成虚拟 DOM,而是直接拼接返回,在效率上进行了提升。
Vue 2.x 的服务端渲染代码如下:
<div>
<div>abc</div>
<div>abc</div>
<div>abc</div>
<div>{{msgl}}</div>
</div>
//编译后
function anonymous(){
var _vm = this;
var _h = _vm.$createElement;
var _c = _vm._self._c || _h;
return \_c('div', [_vm.\_ssrNode("<div>abc</div> <div>abc</div> <div>abc</div> <div>" + _vm.\_ssrEscape(_vm.\_s(_vm.msg))+"</div>")])
}
Vue 3 的服务端渲染代码如下:
<div>
<div>abc</div>
<div>abc</div>
<div>abc</div>
<div>{{msg}}</div>
</div>
// 编译后
export function ssrRender(\_ctx, \_push, \_parent, attrs, $props, $setup, $data, $options){
const _cssVars= { style: { color: _ctx.color }}
\_push('<div${ \_ssrRenderAttrs(\_mergeProps(_attrs, _cssVars))}>xdiv>abc</div><div>abc</div><div>abc</div><div>${\_ssrInterpolate(_ctx.msg)}</div></div>`)
}
- Vite
伴随着 Vue 3,Vue 团队也推出了自己的开发构建工具 Vite,可以在一定程度上取代 Vue Cli 和 webpack-dev-server 的功能。基于此,Vite 主要有以下特性:
* 快速的冷启动
* 即时的模块热更新
* 真正的按需编译Vite 在开发环境下基于浏览器原生 ES6 Modules 开发,在生产环境下基于 Rollup 打包,我们会在后续章节深入讲解 Vite 的相关使用。
第 2 章 ES 6 语言基础
ES 6 是一次重大的版本升级,与此同时,由于 ES 6 秉承着最大化兼容已有代码的设计理念,过去编写的 JS 代码还能正常运行。事实上,许多浏览器已经支持部分 ES 6 特性,并继续努力实现其余特性。这意味着,在一些已经实现部分特性的浏览器中,开发者符合标准的 JavaScript 代码已经可以正常运行,可以更加方便地实现很多复杂的操作,提高开发人员的工作效率。
由于移动端操作系统和浏览器兼容性问题的限制,虽然大部分机型原生就支持 ES 6语法的JavaScript,但是仍有一部分市场占有率较低的机型无法支持 ES 6 语法,例如 Android 系统 4.4 及以下版本和 iOS 系统 8.4 及以下版本。因此,为了项目的健壮性和更强的适配性,会采用 Node.js的 Babel 工具来将 ES 6 代码转换成兼容性更强的 ES 5 代码。
以下是 ES 6 排名前10位的最佳特性列表(排名不分先后):
- Default Parameters(默认参数)
- Template Literals(模板文本)
- Multi-line Strings(多行字符串)
- Destructuring Assignment(解构赋值)
- Enhanced Object Literals(增强的对象文本)
- Arrow Functions(箭头函数)
- Promises
- Block-Scoped Constructs Let and Const (块作用域构造 Let 和 Const )
- Classes(类)
- Modules(模块)
1. 块作用域构造 Let 和 Const
在 ES 6 语法中,新增了 let 和 const 来声明变量,在 ES 6 之前,ES 5 中只有全局作用域和函数作用域,代码如下:
if(true){
var a ='Tom'
}
console.log('a',a) // Tom
作用域是一个独立的地盘,让变量不外泄出去,但是上面的代码中的变量 a 就作为全局作用域外泄了出去,所以此时 JavaScript 没有区块作用域(或称为块级作用域)的概念。
在 ES 6 中加入区块作用域之后,代码如下:
if(true){
let a ='Tom'
}
console.log('a',a)// Uncaught ReferenceError: a s not defined
let 和 var 都可以用来声明变量,但是在 ES 6 中,有下面一些区别:
- 使用 var 声明的变量没有区块的概念,可以跨块访问
- 使用 let 声明的变量只能在区块作用域中访问,不能跨块访问
在相同的作用域下,使用 var 和 let 具有相同的效果,建议在 ES 6 语法中使用 let 来声明变量,这样可以更加明确该变量所处的作用域。
const 表示声明常量,一般用于一旦声明就不再修改的值,并且const 声明的常量必须经过初始化,代码如下:
const a=1
a =2 // Uncaught TypeError: Assignment to constant variable
const b // Uncaught SyntaxError: Missing initializer in const declaration
总结一下,如果在 ES 5 中习惯了使用 var 来声明变量,在切换到 ES 6 时,就需要思考一下变量的用途和类型,选择合适的 let 和 const 来使代码更加规范和语义化。
2. 模板字面量
ES 6 引入了模板字面量(Template Literals),主要通过多行字符串(Multi-line Strings)和字符串占位符对字符串的操作进行增强。
多行字符串
在 ES 5 中,如果一个字符串面量要分为多行,那么可以采用以下两种方法来实现。
(1)、在一行的结尾添加反斜杠表示承接上一行的代码。这种方式是利用JavaScript的语法Bug来实现的:
//多行字符串
var roadPoem = "江南好,\
风景旧曾谙。";
(2)、使用加号来拼接字符串。
//多行字符串
var roadPoem = "江南好,风景旧曾谙。"
+ "日出江花红胜火,春来江水绿如蓝。"
+ "能不忆江南?";
在 ES 6 的多行字符串是一个非常实用的功能。模板字面量的基础语法就是使用反引号替换字符串的单、双引号。例如:
let roadpoem = `江南好,风景旧曾谙。`;
如果需要在字符串中使用反引号,可以使用反斜杠将它转义。
let roadPoem = `江南好,\`风景旧曾谙。`;
在 ES 6 中,使用模板字面量语法可以非常方便地创建多行字符串。
//多行字符串
let roadPoem = `江南好,风景旧曾谙。
日出江花红胜火,春来江水绿如蓝。`;
console.log(roadPoem);
输出结果为:
江南好,风景旧曾谙。
日出江花红胜火,春来江水绿如蓝。
字符串占位符
在一个模板字面量中,可以将 JavaScript 变量或 JavaScript 表达式嵌入占位符并将其作为字符的一部分输出到结果中。
在 ES 6 中,占位符是使用语法 ${NAME} 的,并将包含的NAME变量或者表达式放在反号中:
let name = "xiaoming";
let names = `zhang ${name}`;
let price = 18.8;
let num = 8;
let total = `商品的总价是:${price \* num}`;
由于模板字面量本身也是 JavaScript 表达式,因此也可以在一个模板字面量中嵌入另一个模字面量。
let price = 10;
let num = 8;
let total = `经过计算,${
`商品的总价是:${price ★ num}`
}`;
console.log(total);
输出结果为:
经过计算,商品的总价是:80
3. 默认参数和 rest 参数
在 ES 5 中,JavaScript 定义默认参数的方式如下:
//以前的 JavaScript 定义默认参数的方式
function funl(height, color, url){
var height = height || 150;
var color = color || "red";
var url = url || "http://www.baidu.com";
...
}
在 ES 6 中,可以直接把默认值放在函数声明中:
//新的 JavaScript 定义方式
function fun2(height = 50, color = "red", url = "http://www.baidu.com"){
...
}
在 ES 6 中,声明函数时,可以为任意参数指定默认值,在已指定默认值的参数后还可以继续声明无默认值的参数。
function fun3(height = 50, color = "red", ur1){}
在这种情况下,只有在没有为 height 和 color 传值,或者主动为它们传入 undefined 时才会使用它们的默认值。
在 ES 5 中,无论在函数定义中声明了多少形参,都可以传入任意数量的参数,在函数内部可以通过 arguments 对象接收传入的参数。
function data(){
console.log(arguments);
}
data("li","cc";
在 ES 6 中引入了 rest 参数,在函数的命名参数前添加了3个点,用于获取函数的实参。rest 参数是一个数组,包含自它之后传入的所有参数,通过这个数组名就可以逐一访问里面的参数。
function data(...args){
console.log(args);
}
data("苹果","香蕉","橘子");
rest参数必须放到参数最后位置
function fn(a, b,...args){
console.log(a);
console.log(b);
console.log(args);
}
fn(100, 200, 300, 400, 500, 600);
4. 解构赋值
在 ES 5 中,如果需要从某个对象或者数组中提取需要的数据赋给变量,可以采用如下方式:
let goods = {
name : "苹果",
city : "烟台",
price : "烟台"
}
//提取对象中的数据赋给变量
let name = goods.name;
let city = goods.city;
let price = goods.price;
//提取数组中的数据赋给变量
let arr= [100, 200, 300, 400];
let a1 = arr[0], a2 = arr[1], a3 = arr[2], a4 =arr[3];
在 ES 6 中,通过使用解构赋值的功能,可以从对象和数组中提取数值,并对变量进行赋值数
对象解构
对象解构的方法是在一个赋值操作符的左边放置一个对象字面量。
let goods = {
name : "苹果",
city : "烟台",
price : "烟台"
}
//使用解构赋值的功能
let {name,city,price} = goods;
如果变量已经声明了,之后想要用解构语法给变量赋值,则需要把整个解构赋值语句放到圆括号中。
let goods = {
name : "苹果",
city : "烟台",
price : "烟台"
}
//先声明变量,然后解构赋值
let name,city,price;
({name,city,pzice}= goods) ;
数组解构
因为没有对象属性名的问题,所以数组解构相对比较简单,使用方括号即可。
let arr = [100,200, 300, 400];
let [a1,a2,a3,a4] = arr;
由于变量值是根据数组中元素的顺序进行选取的,因此,如果需要获取指定位置的元素值,可以只为该位置的元素提供变量名。
let arr = [100,200,300,400];
//获取第 4 个位置的元素
let [,,,a4] = arr;
console.log(a4); //输出 400
和对象解构不同,如果为已经声明过的变量进行数组解构赋值,不需要把整个解构赋值语句到一个圆括号中。
let arr =[100,200,300,400];
let a1, a2, a3, a4;
[a1, a2, a3, a4] = arr;
5. 展开运算符
展开运算符(Spread Operator)也是3个点,允许一个表达式在某处展开。展开运算符在多个参数(用于函数调用)、多个元素(用于数组字面量)或者多个变量(用于解构赋值)的地方可以使用。
在函数调用中使用展开运算符
在 ES 5 中可以使用 apply 方法将一个数组展开成多个参数:
function test(a, b,c) {}
var args = [100, 200, 300};
test.apply(null, args);
上面的代码中,把args数组当作实参传递给了a、b和c。
在 ES 6 中可以更加简洁地来传递数组参数:
function test(a,b,c) {}
var args = [100, 200, 300];
test(...args) ;
这里使用展开运算符把 args 直接传递给 test 函数。
在数组字面量中使用展开运算符
在 ES 6 中,可以直接加一个数组并合并到另一个数组中:
var arr1 = ['a', 'b', 'c'];
var arr2 = [...arr1, 'd', 'e']; //['a','b','c','d','e']
展开运算符也可以用在 push 函数中,可以不需要再使用 apply 函数来合并两个数组:
var arr1 = ['a', 'b', 'c'];
var arr2 = ['d', 'e'];
arrl.push(...arr2); //['a','b','c','d','e']
用于解构赋值
解构赋值也是 ES 6 中新添加的一个特性,这个展开运算符可以用于部分情景:
let [argl,arg2,...,arg3]=[1, 2, 3, 4];
argl //1
arg2 //2
arg3 //['3', '4']
展开运算符在解构赋值中的作用跟之前的作用看上去是相反的,它将多个数组项组合成了一个新数组。
不过要注意,解构赋值中的展开运算符只能用在最后。
let [arg1,...,arg2,arg3] = [1, 2, 3, 4]; //报错
类数组对象变成数组
展开运算符可以将一个类数组对象变成一个真正的数组对象:
var list = document.getElementsByTagName('div');
var arr = [...list];
list 是类数组对象,这里通过使用展开运算符使其变成了数组。
6. 增强的对象文本
ES 6 添加了一系列功能来增强对象文本,从而使得处理对象更加轻松。
通过变量进行对象初始化
在 ES 5 中,对象的属性通常是由具有相同名称的变量创建的。例如:
var
a = 100,b = 200, c = 300;
obj = {
a : a,
b : b,
c : c
};
// obj.a = 100, obj.b = 200, obj.c = 300
在 ES 6 中,简化如下:
const
a = 100, b = 200, c = 300;
obj = {
a
b
c
};
简化定义对象方法
在 ES 5 中,定义对象的方法需要 function 语句。例如:
var lib = {
sum : function(a, b) { return a + b;},
mult : function(a, b) { return a \* b;}
};
console.log( lib.sum(100, 200)); // 300
console.log( lib.mult(100, 200)); // 20000
在 ES 6 中,定义对象的方法简化如下:
const lib = {
sum(a, b) { return a + b; },
mult(a, b) { return a \* b; }
};
console.log( lib.sum(100,200));// 300
console.log( lib.mult(100, 200));//20000
这里不能使用 ES 6 的箭头函数(=>),因为该方法需要一个名称。如果直接命名每个方法,则可以使用箭头函数(=>)。例如:
const lib = {
sum : (a, b) => a + b,
mult : (a, b)=> a \* b
};
console.log( lib.sum(100,200));// 300
console.log( lib.mult(100, 200)); //20000
动态属性键
在 ES 5 中,虽然可以在创建对象之后添加变量,但是不能使用变量作为键名称。例如
var
key1 = 'one',
obj = {
two : 200,
three : 300
};
obj[key1] = 100;
//表示obj.one = 100,obj.two = 200, obj.three = 300
通过在方括号(Ⅱ)内放置表达式,可以在ES6中动态分配对象键。例如:
const
key1 = 'one',
obj = {
[key1]: 100,
two : 200,
three : 300
}
//表示obj.one = 100, obj.two = 200, obj.three = 300
解构对象属性中的变量
在 ES 5 中,可以将对象的属性值提取到另一个变量中。例如:
紧跟潮流
大前端和全栈是以后前端的一个趋势,懂后端的前端,懂各端的前端更加具有竞争力,以后可以往这个方向靠拢。