ES6能够说是一个泛指,指5.1版本之后的JavaScript
的下一代标准,涵盖了ES2015,ES2016,ES2017
等;亦指下一代JavaScript语言。javascript
嗯~ES6的语法有什么好谈的,无聊了吧?java
确实,语法糖的东西真的是学起来如嚼蜡 -- 淡无味;可是要用别人的东西来开发的,你学仍是学呢?git
因此,仍是简单谈下吧...es6
本次的ES6语法的汇总总共分为上、中、下三篇,本篇文章为上篇。github
var
是以前就有的了,在这里提出来主要是为了比较其和let与const
。数组
1. 块级做用域函数
for(var i = 0; i < 3; i++) {
setTimeout(() => {
console.log(i); // 输出3个3
}, 0)
}
复制代码
解析:变量i是var
声明的,在全局范围内是都有效,全局只有一个变量i。每次循环,变量的值会发生改变。循环内的i是指向全局的i。优化
for(let i = 0; i < 3; i++) {
setTimeout(() => {
console.log(i); // 输出0, 1, 2
}, 0)
}
复制代码
解析:变量i是let
声明的,当前的i只在本轮循环有效,因此每次循环的i其实都是一个新变量。JavaScript引擎内部会记住上一轮的值,初始化本轮的变量i时,就在上一轮循环的基础上进行计算。ui
2. 不存在变量提高this
console.log(a); // undefined
var a = 100;
复制代码
var
命令会发生变量提高现象,即变量能够在声明以前使用,值为undefined
;而let
纠正了这种行为,不能产生变量提高。
console.log(a); // 报错
let a = 100;
复制代码
3. 暂时性死区
只要块级做用域内,存在let
命令,它所声明的变量就绑定(binding)在这个区域,再也不受外部影响。
如:
var temp = 123;
if(true) {
temp = 'abc'; // 引入错误
let temp;
}
复制代码
在上面中,if后面的大括号内容就造成了一个区域。而temp此时是找不到外层的,由于内部有个temp
且你在内部let temp
声明前赋值了。
在看一个隐晦的例子:
function bar(x = y, y = 2) {
return [x, y]
}
bar(); // 报错
复制代码
在上面的例子中bar里面进行赋值操做的时候,就产生了一个封闭的区域了,能够认为x 和 y经过let声明
,但是上面的问题是,x = y
的引用在y = 2
的声明以前。
能够修正以下:
function bar(y = 2, x = y) {
return [x, y];
}
bar(); // [2, 2]
复制代码
4. 不可重复声明
var a = 100;
var a = 1000;
console.log(a); // 1000
复制代码
let a = 100;
let a = 1000; // 报重复声明错误
复制代码
5. ES6声明的变量不会挂在顶层对象
嗯~ES6变量的声明是指哪些声明呢?
指let, const, import, class
声明。
而var, function
声明是ES6以前的。
因此目前JavaScript
有六种声明变量的方式了~
var job = 'teacher';
console.log(window.job); // teacher
复制代码
let job = 'teacher';
console.log(window.job); // undefined
复制代码
let
能够先声明稍后赋值;而const
声明以后必须立马赋值,不然会报错let a;
a = 100; // this is ok
复制代码
const a; // 报没初始化数据的错误
复制代码
const
声明了简单的数据类型就不能更改了;声明了引用类型(数组,对象等),指针指向的地址不能更改,可是内部的数据能够更改的const str = 'this is a string';
str = 'this is another string'; // 报了个“给不变的变量分配值”的错误
复制代码
const obj = {
name: 'jia'
}
obj.name = 'ming'; // this is ok
obj = {}; // 报了个“给不变的变量分配值”的错误
复制代码
let
使用场景:变量,用以代替var
const
使用场景:常量、声明匿名函数、箭头函数的时候。
// 常量
const PI = 3.14;
// 匿名函数
const fn1 = function() {
// do something
}
// 箭头函数
const fn2 = () => {
// do something
}
复制代码
解构能够理解就是一个做用:简化你变量赋值的操做。
let [name, job] = ['jiaming', 'teacher'];
console.log(name); // jiaming
复制代码
本质上,这种写法属于模式匹配,只要等号两边的模式相同(重点),左边的变量就会被赋予对应的值。再好比:
let [ , , third] = ["foo", "bar", "baz"];
console.log(third); // "baz"
let [head, body, ...tail] = [1, 2, 3, 4, 5];
console.log(tail); // [3, 4, 5]
复制代码
也可使用默认值。可是默认值生效的前提是:ES6内部使用严格相等运算符(===),判断一个位置是否有值。因此,只有当一个数组成员严格等于undefined,默认值才会生效。
let [x, y = 'b'] = ['a']; // x='a', y='b'
let [z = 1] = [undefined];
console.log(z); // 1
let [k = 1] = [null];
console.log(k); // null
复制代码
const state = {
name: 'jiaming',
job: 'teacher'
};
let {
name,
job
} = state;
// 上面的场景很熟悉吧
console.log(job); // teacher
复制代码
上面的例子若是写具体的话,是这样的:
const state = {
name: 'jiaming',
job: 'teacher'
};
let {
name: name, // 第一个name是匹配模式,第二个name才是变量,二者同名简化成一个便可
job: job
} = state;
复制代码
咱们来改写下:
const state = {
name: 'jiaming',
job: 'teacher'
};
let {
name: job,
job: name
} = state;
console.log(job); // jiaming
复制代码
对象也可使用默认值,可是前提是:对象的属性值严格等于undefined
。
以下:
var {x = 3} = {x: undefined};
console.log(x); // 3
var {y = 3} = {y: null};
console.log(y); // null
复制代码
字符串之因此可以被解构赋值,是由于此时字符串被转换成了一个相似数组的对象。
const [a, b, ...arr] = 'hello';
console.log(arr); // ["l", "l", "o"]
复制代码
let {length: len} = 'hello';
console.log(len); // 5
复制代码
解构赋值时,若是等号右边是数值和布尔值,则会先转换为对象(分别是基本包装类型Number和基本包装类型Boolean)。不过这种场景用得很少~
let {toString: s} = 123;
console.log(s); // function toString() { [native code] }
console.log(s === Number.prototype.toString); // true
复制代码
let {toString: s} = true;
console.log(s === Boolean.prototype.toString); // true
复制代码
解构赋值的规则是,只要等号右边的值不是对象或数组,就先将其转为对象。因为undefined和null没法转为对象,因此对它们进行解构赋值,都会报错
。
1. 交换两变量值
let [a, b] = ['reng', 'jia'];
[a, b] = [b, a];
console.log(b); // 'reng'
复制代码
2. 将字符串转换为数组
let [...arr] = 'reng';
console.log(arr); // ["r", "e", "n", "g"]
console.log(arr.splice(0, 2)); // ["r", "e"] 返回删除的数组(能使用数组的方法了)
复制代码
针对字符串扩展这个,我的感受模版字符串使用的频率比较高。模版字符串解放了拼接字符串带来的繁琐操做的体力劳动。
let name = 'jiaming';
let str = 'Hello! My name is '+ name + '. Nice to meet you!';
let strTemp = `Hello! My name is ${ name }. Nice to meet you!`
复制代码
对于新增的字符串方法,能够记下下面这几个:
留意下在Number
对象上提供的新方法:
Number.isNaN(NaN) // true
Number.isNaN(15) // false
复制代码
关于Math
对象上的方法,遇到要用到时候,查API吧,否则记太多,脑瓜子会疼~
ES6引入rest参数(形式是...变量名
),用于获取多余的参数,这样就不须要使用arguments
对象了。rest参数搭配的变量是一个数组(arguments是一个类数组来的),该变量将多余的参数放入数组中。
arguments对象是一个类数组,还得经过Array.prototype.slice.call(arguments)
将其转换为真数组;而rest参数直接就可使用数组的方法了。
function add(...arr) {
console.log(arr); // [2, 5, 3]
let sum = 0;
for(var val of arr) {
sum += val;
}
return sum;
}
console.log(add(2, 5, 3)); // 10
复制代码
ES6容许使用“箭头”(=>
)定义函数。
const f = v => v; // 注意是有返回值return的啊
// 等同于
const f = function (v) {
return v;
}
复制代码
若是箭头函数的代码块部分多于一条语句,就要使用大括号将它们括起来,而且使用return
语句返回结果。
const sum = (num1, num2) => num1 + num2;
// 等价于,使用了大括号,那箭头函数里面就要使用return了
const sum = (num1, num2) => { return num1 + num2 }
// 等价于
const sum = function(num1, num2) {
return num1 + num2
}
复制代码
使用箭头函数注意点:
this
对象,就是定义所在的对象,而不是使用时所在的对象。new
命令,不然会抛出一个错误。arguments
对象,该对象在函数体内不存在的,若是要用,能够用rest参数代替。yield
命令,所以箭头函数不能用做Generator函数。function foo() {
setTimeout(() => {
console.log('id:', this.id); // id: 42
}, 100);
}
var id = 21;
foo.call({ id: 42 });
复制代码
// 错误使用箭头函数的例子
const cat = {
lives: 9,
jumps: () => { // 箭头函数的错误使用,由于对象不构成单独的做用域
this.lives--; // this 指向window
}
}
var button = document.getElementById('press'); // 一个节点对象
button.addEventListener('click', () => { // 箭头函数的this指向window
this.classList.toggle('on');
});
// 箭头函数改为`function`匿名函数指向就正确了。
复制代码
箭头函数适合处理简单的计算,若是有复杂的函数体或读写操纵不建议使用,这样能够提升代码的可读性。
关于尾递归和其优化能够直接看阮先生的文档
假设有这么一个需求,须要对二维数组的元素进行反转并被1减。咱们来看下下面代码,哪一个能实现此需求呢?
// 代码一
const A = [[0,1,1],[1,0,1],[0,0,0]];
const flipAndInvertArr = function(A) {
A.map(item=>{
item.reverse().map(r=>1-r)
})
}
复制代码
// 代码二
const A = [[0,1,1],[1,0,1],[0,0,0]];
const flipAndInvertArr = A=> A.map(res =>res.reverse().map(r => 1 - r));
复制代码
运行以后,发现代码二是能实现需求的:
let resultArr = flipAndInvertArr(A);
console.log(resultArr); // [[0, 0, 1], [0, 1, 0], [1, 1, 1]]
复制代码
嗯~上面已经提到过,箭头函数体加上大括号后,是须要本身手动return的~
咱们来改写下代码一,以便符合需求:
const A = [[0,1,1],[1,0,1],[0,0,0]];
const flipAndInvertArr = function(A) {
return (A.map(item=>{
return item.reverse().map(r=>1-r)
}))
}
let result = flipAndInvertArr(A);
console.log(result); // [[0, 0, 1], [0, 1, 0], [1, 1, 1]]
复制代码
惊喜不,意外不~
本次的ES6语法的汇总总共分为上、中、下三篇,本篇文章为上篇。
文章首发在github上--谈谈ES6语法(汇总上篇)。更多的内容,请戳个人博客进行了解,能留个star就更好了💨