ES6
ES6 语法基础
let 命令
-
基本语法
ES6 新增了
let
命令,用来声明变量。它的用法类似于var
,区别在于let
命令声明的变量只在let
命令所在的代码块内有效。 -
不存在变量提升
let
不像var
那样,会发生“变量提升”现象。 -
暂时性死区
只要块级作用域内存在
let
命令,它所声明的变量就 ”绑定(binding)” 这个区域,不再受外部的影响。 -
不允许重复声明
let
不允许在相同作用域内,重复声明同一个变量。
块级作用域
-
为什么需要块级作用域?
ES5 只有全局作用域和函数作用域,没有块级作用域,这带来很多不合理的场景。
第一种场景:内层变量可能会覆盖外层变量。
第二种场景:用来计数的循环变量泄露为全局变量。
-
ES6 的块级作用域
let
实际上为 JavaScript 新增了块级作用域。
立即执行函数
(function () {}());
const 命令
const
也用来声明变量,但是声明的是常量。一旦声明,常量的值就不能改变。const
声明的常量只在当前代码块有效。
声明冻结对象(也就是说对象的成员变量的值也不可以改变)
const person = Object.freeze({
name: "zhangsan",
age: 20
});
彻底冻结对象的函数
freeze.js
var constantize = (obj) => {
Object.freeze(obj);
Object.keys(obj).forEach((key, value) => {
if(typeof obj[key] === 'object') {
constantize(obj[key]);
}
})
};
跨模块常量
moduleA.js
export const HOST = "http://www.xxx.com";
export const PORT = 8080;
export const NAME = "Lark";
在 moduleB.js 中要如何使用 moduleA.js 中的 HOST 常量呢?
moduleB.js
// * 表示全部引入
import * as ma from "./moduleA";
// 这样使用moduleA中的变量
console.log(ma.HOST);
// 部分引入
import { HOST, PORT } as ma from "./moduleA";
console.log(ma.HOST, ma.PORT);
// 只引入一个
import NAME as ma from "./moduleA";
console.log(ma.NAME);
全局对象的属性
全局对象是最顶层的对象,在浏览器环境指的是 window
对象,在 node.js 中指的是 global
对象,在 JavaScript 语言中,所有全局变量都是全局对象的属性。(node 的情况比较特殊,这一条只对 REPL 环境适用,模块环境必须显式声明成 global 的属性)
ES6 规定,var
和 function
命令声明的全局变量,属于全局对象的属性;let
、const
、class
命令声明的全局变量,不属于全局对象的属性。
例如:
var varName = "varValue";
// 浏览器环境下
console.log(window.varName);
// node.js环境下
console.log(global.varName);
// 通用环境下
console.log(this.varName);
结构赋值
数组的结构赋值
-
Destructuring
ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)。
-
不完全解构
等号左边的模式,只匹配一部分的等号右边的数组。
-
指定默认值
注意:ES6内部使用严格相等运算符(===)判断一个位置是否有值。所以,如果一个数组成员不严格等于
undefined
,默认值是不会生效的。 -
let
和const
命令只要某种数据结构具有
iterator
接口,都可以采用数组形式的解构赋值。
// Destructuring
// ES6
var [a, b, c] = [1, 2, 3];
console.log(a, b, c);// 1 2 3
//不完全解构
var [first, second] = [1];
console.log(first); //1
console.log(second); //undifined
//指定默认值
var [one = "One", two] = [];
console.log(one); // One
console.log(two); // undefined
var [x = "abc", y] = [undefined, "xyz"];
console.log(x); //abc 因为undefined表示没有值,所以并不会覆盖abc
console.log(y); //xyz
// iterator 接口
let [a, b, c] = new Set(["a", "b", "c"]);
console.log(a); //a
console.log(b); //b
console.log(c); //c
function* fibs() {
let a = 0;
let b = 1;
while(true) {
yield a;
[a, b] = [b, a + b];
};
var [first, second, third, fourth, fifth, sixth] = fibs();
console.log(sixth); //5
}
对象的解构赋值
-
解构不仅可以用于数组,还可以用于对象
对象的属性没有次序,变量必须于属性同名,才能取到正确的值。
-
指定默认值
默认值生效的条件是:对象的属性值严格等于
undefined
(也就是说如果有值的话,默认值就不会生效)。 -
现有对象的方法
对象的解构赋值,可以很方便地将现有对象的方法赋值到某个变量。
var {name, age} = {name: "Lark", age: 30};
console.log(name, age); // Lark 30
如果变量名和属性名不一致,该如何调用?
var {name: pName, age: pAge} = {name: "Lark", age: 30};
console.log(pName, pAge); // Lark 30
指定默认值
var { x = 3 } = {};
console.log(x); // 3
var { y = 4 } = { y = undefined };
console.log(y); // 4
var { z = 5 } = { z = null };
console.log(z); // null
对已声明变量的解构赋值
var x;
{ x } = { x: 1 };
console.log(x); // 报错 语法错误,编译不通过
var y;
({ y } = { y: 1 });
console.log(y); // 1
现有对象的方法(使用现有对象的方法,就不用每次对象.方法
方式调用了)
let { sin, cos, tan, PI } = Math;
console.log(sin(PI / 6)); // 0.49999999
字符串的解构赋值
-
字符串也可以解构赋值
字符串被转换成了一个类似于数组的对象
-
属性解构赋值
类似数组的对象都有一个
length
属性,因此还可以对这个属性解构赋值。
var { a, b, c, d, e } = "hello";
console.log(a, b, c, d, e); // h e l l o
字符串的属性解构
const { length: len } = "hello";
console.log(len); // 5
函数参数的解构赋值
- 函数的参数也可以使用解构
- 函数参数的解构也可以使用默认值
函数参数的解构赋值
function sum([x, y]) {
return x + y;
}
console.log(sum([1, 3])); // 4
函数参数解构赋值的默认值
function sum({x = 0, y = 0} = {}) {
return [x, y];
}
console.log(sum({x: 100, y: 200})); // [100, 200]
console.log(sum({x: 100})); // [100, 0]
console.log(sum({})); // [0, 0]
console.log(sum()); //[0, 0]
function sum({x, y} = {x: 0, y: 0}) {
return [x, y];
}
console.log(sum({x: 100, y: 200})); // [100, 200]
console.log(sum({x: 100})); // [100, undefined]
console.log(sum({})); // [undefined, undefined]
console.log(sum()); //[0, 0] 没有传参数,它做的不是函数参数解构赋值,而是对象解构赋值,{x, y} = {x: 0, y: 0} 会在函数运行。
解构赋值的用途
- 交换变量的值
- 从函数返回多个值
- 函数参数的定义
- 提取json数据
- 函数参数的默认值
- 遍历map解构
- 输入模块的指定方法
交换变量的值
var x = 100;
var y = 200;
[x, y] = [y, x];
console.log(x, y); // 200 100
从函数返回多个值
function fun() {
return [1, 2, 3];
}
var [x, y, z] = fun();
console.log(x, y, z); // 1 2 3
function fun() {
return {
id: "001",
name: "Lark",
age: 30
};
}
var { id, name, age } = fun();
console.log(id, name, age); // 001 Lark 30
函数参数的定义
// 参数是一组有次序的值
function fun([x, y, z]) {
// x=100 y=200 z=300
}
fun([100, 200, 300]);
// 参数是一组无次序的值
function fun2({id, name, age}) {
// id="001" name="Lark" age=30
}
fun2({id: "001", name: "Lark", age: 30});
提取json数据
var jsonData = {
id: "001",
name: "Lark",
age: 30,
score: {
Chinese: 100,
English: 90
}
};
let { id, name, age, score } = jsonData;
console.log(id, name, age, score);// 001 Lark 30
函数参数的默认值
jQuery.ajax({
url: '/path/to/file',
type: 'POST',
dataType: 'xml/html/script/json/jsonp',
data: {param1: 'value1'},
complete: function(xhr, textStatus) {
},
success: function(data, textStatus, xhr) {
},
error: function(xhr, textStatus, errorThrown) {
}
});
jQuery.ajax = function(url, {
async = true,
beforeSend = function() {},
cache = true,
complete = function() {},
crossDomain = false,
global = true
}){
// do something
};
遍历map解构
var map = new Map();
map.set("id", "001");
map.set("name", "Lark");
map.set("age", 30);
// 获取键名和键值
for(let [key, value] of map) {
console.log(key, value);
}
// id 001
// name Lark
// age 30
// 获取键名
for(let [key] of map) {
console.log(key);
}
// id
// name
// age
// 获取键值
for(let [, value] of map) {
console.log(value);
}
// 001
// Lark
// 30
输入模块的指定方法
const { SourceMapConsumer, SourceNode } = require("source-map");
后面会持续更新请继续关注,再会......