We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ES6可以说是一个泛指,指5.1版本以后的JavaScript的下一代标准,涵盖了ES2015,ES2016,ES2017等;亦指下一代JavaScript语言。
JavaScript
ES2015,ES2016,ES2017
嗯~ES6的语法有什么好谈的,无聊了吧?
确实,语法糖的东西真的是学起来如嚼蜡 -- 淡无味;但是要用别人的东西来开发的,你学还是学呢?
所以,还是简单谈下吧...
本次的ES6语法的汇总总共分为上、中、下三篇,本篇文章为上篇。
var是之前就有的了,在这里提出来主要是为了比较其和let与const。
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时,就在上一轮循环的基础上进行计算。
let
2. 不存在变量提升
console.log(a); // undefined var a = 100;
var命令会发生变量提升现象,即变量可以在声明之前使用,值为undefined;而let纠正了这种行为,不能产生变量提升。
undefined
console.log(a); // 报错 let a = 100;
3. 暂时性死区
只要块级作用域内,存在let命令,它所声明的变量就绑定(binding)在这个区域,不再受外部影响。
如:
var temp = 123; if(true) { temp = 'abc'; // 引入错误 let temp; }
在上面中,if后面的大括号内容就形成了一个区域。而temp此时是找不到外层的,因为内部有个temp且你在内部let temp声明前赋值了。
temp
let temp
在看一个隐晦的例子:
function bar(x = y, y = 2) { return [x, y] } bar(); // 报错
在上面的例子中bar里面进行赋值操作的时候,就产生了一个封闭的区域了,可以认为x 和 y通过let声明,可是上面的问题是,x = y的引用在y = 2的声明之前。
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声明。
let, const, import, class
而var, function声明是ES6之前的。
var, function
所以目前JavaScript有六种声明变量的方式了~
var job = 'teacher'; console.log(window.job); // teacher
let job = 'teacher'; console.log(window.job); // undefined
const
let a; a = 100; // this is ok
const a; // 报没初始化数据的错误
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,默认值才会生效。
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。
对象的属性值严格等于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无法转为对象,所以对它们进行解构赋值,都会报错。
由于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
Number.isNaN(NaN) // true Number.isNaN(15) // false
关于Math对象上的方法,遇到要用到时候,查API吧,不然记太多,脑瓜子会疼~
Math
ES6引入rest参数(形式是...变量名),用于获取多余的参数,这样就不需要使用arguments对象了。rest参数搭配的变量是一个数组(arguments是一个类数组来的),该变量将多余的参数放入数组中。
...变量名
arguments
arguments对象是一个类数组,还得通过Array.prototype.slice.call(arguments)将其转换为真数组;而rest参数直接就可以使用数组的方法了。
Array.prototype.slice.call(arguments)
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语句返回结果。
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
yield
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]]
惊喜不,意外不~
更多的内容,请戳我的博客进行了解,能留个star就更好了💨
The text was updated successfully, but these errors were encountered:
No branches or pull requests
ES6可以说是一个泛指,指5.1版本以后的
JavaScript
的下一代标准,涵盖了ES2015,ES2016,ES2017
等;亦指下一代JavaScript语言。背景
嗯~ES6的语法有什么好谈的,无聊了吧?
确实,语法糖的东西真的是学起来如嚼蜡 -- 淡无味;但是要用别人的东西来开发的,你学还是学呢?
所以,还是简单谈下吧...
本次的ES6语法的汇总总共分为上、中、下三篇,本篇文章为上篇。
var、let和const
var
是之前就有的了,在这里提出来主要是为了比较其和let与const
。区别
1. 块级作用域
解析:变量i是
var
声明的,在全局范围内是都有效,全局只有一个变量i。每次循环,变量的值会发生改变。循环内的i是指向全局的i。解析:变量i是
let
声明的,当前的i只在本轮循环有效,所以每次循环的i其实都是一个新变量。JavaScript引擎内部会记住上一轮的值,初始化本轮的变量i时,就在上一轮循环的基础上进行计算。2. 不存在变量提升
var
命令会发生变量提升现象,即变量可以在声明之前使用,值为undefined
;而let
纠正了这种行为,不能产生变量提升。3. 暂时性死区
只要块级作用域内,存在
let
命令,它所声明的变量就绑定(binding)在这个区域,不再受外部影响。如:
在上面中,if后面的大括号内容就形成了一个区域。而temp此时是找不到外层的,因为内部有个
temp
且你在内部let temp
声明前赋值了。在看一个隐晦的例子:
在上面的例子中bar里面进行赋值操作的时候,就产生了一个封闭的区域了,可以认为
x 和 y通过let声明
,可是上面的问题是,x = y
的引用在y = 2
的声明之前。可以修正如下:
4. 不可重复声明
5. ES6声明的变量不会挂在顶层对象
嗯~ES6变量的声明是指哪些声明呢?
指
let, const, import, class
声明。而
var, function
声明是ES6之前的。所以目前
JavaScript
有六种声明变量的方式了~const命令注意点
let
可以先声明稍后赋值;而const
声明之后必须立马赋值,否则会报错const
声明了简单的数据类型就不能更改了;声明了引用类型(数组,对象等),指针指向的地址不能更改,但是内部的数据可以更改的let和const的使用场景
let
使用场景:变量,用以代替var
const
使用场景:常量、声明匿名函数、箭头函数的时候。变量的解构赋值
解构可以理解就是一个作用:简化你变量赋值的操作。
数组场景
本质上,这种写法属于模式匹配,只要等号两边的模式相同(重点),左边的变量就会被赋予对应的值。再比如:
也可以使用默认值。但是默认值生效的前提是:
ES6内部使用严格相等运算符(===),判断一个位置是否有值。所以,只有当一个数组成员严格等于undefined,默认值才会生效。
对象场景
上面的例子如果写具体的话,是这样的:
我们来改写下:
对象也可以使用默认值,但是前提是:
对象的属性值严格等于undefined
。如下:
字符串场景
字符串之所以能够被解构赋值,是因为此时字符串被转换成了一个类似数组的对象。
数值和布尔值场景
解构赋值时,如果等号右边是数值和布尔值,则会先转换为对象(分别是基本包装类型Number和基本包装类型Boolean)。不过这种场景用得不多~
解构赋值的规则是,只要等号右边的值不是对象或数组,就先将其转为对象。
由于undefined和null无法转为对象,所以对它们进行解构赋值,都会报错
。两种使用场景
1. 交换两变量值
2. 将字符串转换为数组
字符串扩展
针对字符串扩展这个,个人感觉模版字符串使用的频率比较高。模版字符串解放了拼接字符串带来的繁琐操作的体力劳动。
对于新增的字符串方法,可以记下下面这几个:
数值扩展
留意下在
Number
对象上提供的新方法:关于
Math
对象上的方法,遇到要用到时候,查API吧,不然记太多,脑瓜子会疼~函数扩展
rest参数
ES6引入rest参数(形式是
...变量名
),用于获取多余的参数,这样就不需要使用arguments
对象了。rest参数搭配的变量是一个数组(arguments是一个类数组来的),该变量将多余的参数放入数组中。arguments对象是一个类数组,还得通过
Array.prototype.slice.call(arguments)
将其转换为真数组;而rest参数直接就可以使用数组的方法了。箭头函数
ES6允许使用“箭头”(
=>
)定义函数。如果箭头函数的代码块部分多于一条语句,就要使用大括号将它们括起来,并且使用
return
语句返回结果。使用箭头函数注意点:
this
对象,就是定义所在的对象,而不是使用时所在的对象。new
命令,否则会抛出一个错误。arguments
对象,该对象在函数体内不存在的,如果要用,可以用rest参数代替。yield
命令,因此箭头函数不能用作Generator函数。箭头函数适合处理简单的计算,如果有复杂的函数体或读写操纵不建议使用,这样可以提高代码的可读性。
关于尾递归和其优化可以直接看阮先生的文档
找下茬
假设有这么一个需求,需要对二维数组的元素进行反转并被1减。我们来看下下面代码,哪个能实现此需求呢?
运行之后,发现代码二是能实现需求的:
嗯~上面已经提到过,箭头函数体加上大括号后,是需要自己手动return的~
我们来改写下代码一,以便符合需求:
惊喜不,意外不~
参考和后话
本次的ES6语法的汇总总共分为上、中、下三篇,本篇文章为上篇。
更多的内容,请戳我的博客进行了解,能留个star就更好了💨
The text was updated successfully, but these errors were encountered: