ES6语法(汇总上篇)

ES6可以说是一个泛指,指5.1版本以后的JavaScript的下一代标准,涵盖了ES2015,ES2016,ES2017等;亦指下一代JavaScript语言

背景

嗯~ES6的语法有什么好谈的,无聊了吧?

确实,语法糖的东西真的是学起来如嚼蜡 -- 淡无味;但是要用别人的东西来开发的,你学还是学呢?

所以,还是简单谈下吧...

本次的ES6语法的汇总总共分为上、中、下三篇,本篇文章为上篇。

var、let和const

var是之前就有的了,在这里提出来主要是为了比较其和let与const。

区别

1. 块级作用域

for(vari =0; i <3; i++) {setTimeout(()=>{console.log(i);// 输出3个3},0)}复制代码

解析:变量i是var声明的,在全局范围内是都有效,全局只有一个变量i。每次循环,变量的值会发生改变。循环内的i是指向全局的i。

for(leti =0; i <3; i++) {setTimeout(()=>{console.log(i);// 输出0, 1, 2},0)}复制代码

解析:变量i是let声明的,当前的i只在本轮循环有效,所以每次循环的i其实都是一个新变量。JavaScript引擎内部会记住上一轮的值,初始化本轮的变量i时,就在上一轮循环的基础上进行计算。

2. 不存在变量提升

console.log(a);// undefinedvara =100;复制代码

var命令会发生变量提升现象,即变量可以在声明之前使用,值为undefined;而let纠正了这种行为,不能产生变量提升。

console.log(a);// 报错leta =100;复制代码

3. 暂时性死区

只要块级作用域内,存在let命令,它所声明的变量就绑定(binding)在这个区域,不再受外部影响。

如:

vartemp =123;if(true) {temp ='abc';// 引入错误lettemp; }复制代码

在上面中,if后面的大括号内容就形成了一个区域。而temp此时是找不到外层的,因为内部有个temp且你在内部let temp声明前赋值了。

在看一个隐晦的例子:

functionbar(x = y, y =2){return[x, y]}bar();// 报错复制代码

在上面的例子中bar里面进行赋值操作的时候,就产生了一个封闭的区域了,可以认为x 和 y通过let声明,可是上面的问题是,x = y的引用在y = 2的声明之前。

可以修正如下:

functionbar(y =2, x = y){return[x, y];}bar();// [2, 2]复制代码

4. 不可重复声明

vara =100;vara =1000;console.log(a);// 1000复制代码

leta =100;leta =1000;// 报重复声明错误复制代码

5. ES6声明的变量不会挂在顶层对象

嗯~ES6变量的声明是指哪些声明呢?

指let, const, import, class声明。

而var, function声明是ES6之前的。

所以目前JavaScript有六种声明变量的方式了~

varjob ='teacher';console.log(window.job);// teacher复制代码

letjob ='teacher';console.log(window.job);// undefined复制代码

const命令注意点

let可以先声明稍后赋值;而const声明之后必须立马赋值,否则会报错

leta;a =100;// this is ok复制代码

const a; // 报没初始化数据的错误复制代码

const声明了简单的数据类型就不能更改了;声明了引用类型(数组,对象等),指针指向的地址不能更改,但是内部的数据可以更改的

conststr ='this is a string';str ='this is another string';// 报了个“给不变的变量分配值”的错误复制代码

constobj = {name:'jia'}obj.name ='ming';// this is okobj = {};// 报了个“给不变的变量分配值”的错误复制代码

let和const的使用场景

let使用场景:变量,用以代替var

const使用场景:常量、声明匿名函数、箭头函数的时候。

// 常量constPI =3.14;// 匿名函数constfn1 =function(){// do something}// 箭头函数constfn2 =()=>{// 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);// 1let[k =1] = [null];console.log(k);// null复制代码

对象场景

conststate = {name:'jiaming',job:'teacher'};let{name,job} = state;// 上面的场景很熟悉吧console.log(job);// teacher复制代码

上面的例子如果写具体的话,是这样的:

conststate = {name:'jiaming',job:'teacher'};let{name: name,// 第一个name是匹配模式,第二个name才是变量,两者同名简化成一个即可job: job} = state;复制代码

我们来改写下:

conststate = {name:'jiaming',job:'teacher'};let{name: job,job: name} = state;console.log(job);// jiaming复制代码

对象也可以使用默认值,但是前提是:对象的属性值严格等于undefined。

如下:

var{x =3} = {x:undefined};console.log(x);// 3var{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"] 返回删除的数组(能使用数组的方法了)复制代码

字符串扩展

针对字符串扩展这个,个人感觉模版字符串使用的频率比较高。模版字符串解放了拼接字符串带来的繁琐操作的体力劳动。

letname ='jiaming';letstr ='Hello! My name is '+ name +'. Nice to meet you!';letstrTemp =`Hello! My name is${ name }. Nice to meet you!`复制代码

对于新增的字符串方法,可以记下下面这几个:

includes(): 返回布尔值,表示是否找到了参数字符串

startWith(): 返回布尔值,表示参数字符串是否在原字符串的头部

endWith(): 返回布尔值,表示参数字符串是否在原字符串的尾部

trimStart(): 返回字符串,表示消除参数字符串开头的空格

trimEnd(): 返回字符串,表示消除参数字符串结尾的空格

数值扩展

留意下在Number对象上提供的新方法:

Number.isFinite(): 返回布尔值,表示参数值是否有限的

Number.isNaN(): 返回布尔值,用来检查一个值是否为NaN

Number.isNaN(NaN)// trueNumber.isNaN(15)// false复制代码

Number.isInteger(): 返回布尔值,用来判断一个数值是否为整数

关于Math对象上的方法,遇到要用到时候,查API吧,不然记太多,脑瓜子会疼~

函数扩展

rest参数

ES6引入rest参数(形式是...变量名),用于获取多余的参数,这样就不需要使用arguments对象了。rest参数搭配的变量是一个数组(arguments是一个类数组来的),该变量将多余的参数放入数组中。

arguments对象是一个类数组,还得通过Array.prototype.slice.call(arguments)将其转换为真数组;而rest参数直接就可以使用数组的方法了。

functionadd(...arr){console.log(arr);// [2, 5, 3]letsum =0;for(varvalofarr) {sum += val;}returnsum;}console.log(add(2,5,3));// 10复制代码

箭头函数

ES6允许使用“箭头”(=>)定义函数。

constf =v=>v;// 注意是有返回值return的啊// 等同于constf =function(v){returnv;}复制代码

如果箭头函数的代码块部分多于一条语句,就要使用大括号将它们括起来,并且使用return语句返回结果。

constsum =(num1, num2) =>num1 + num2;// 等价于,使用了大括号,那箭头函数里面就要使用return了constsum =(num1, num2) =>{returnnum1 + num2 }// 等价于constsum =function(num1, num2){returnnum1 + num2}复制代码

使用箭头函数注意点:

函数体内的this对象,就是定义所在的对象,而不是使用时所在的对象。

不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。

不可以使用arguments对象,该对象在函数体内不存在的,如果要用,可以用rest参数代替。

不可以使用yield命令,因此箭头函数不能用作Generator函数。

functionfoo(){setTimeout(()=>{console.log('id:',this.id);// id: 42},100);}varid =21;foo.call({id:42});复制代码

// 错误使用箭头函数的例子constcat = {lives:9,jumps:()=>{// 箭头函数的错误使用,因为对象不构成单独的作用域this.lives--;// this 指向window}}varbutton =document.getElementById('press');// 一个节点对象button.addEventListener('click', () => {// 箭头函数的this指向windowthis.classList.toggle('on');});// 箭头函数改成`function`匿名函数指向就正确了。复制代码

箭头函数适合处理简单的计算,如果有复杂的函数体或读写操纵不建议使用,这样可以提高代码的可读性。

关于尾递归和其优化可以直接看阮先生的文档

找下茬

假设有这么一个需求,需要对二维数组的元素进行反转并被1减。我们来看下下面代码,哪个能实现此需求呢?

// 代码一constA = [[0,1,1],[1,0,1],[0,0,0]];constflipAndInvertArr =function(A){    A.map(item=>{        item.reverse().map(r=>1-r)    })}复制代码

// 代码二constA = [[0,1,1],[1,0,1],[0,0,0]];constflipAndInvertArr =A=>A.map(res=>res.reverse().map(r=>1- r));复制代码

运行之后,发现代码二是能实现需求的:

letresultArr = flipAndInvertArr(A);console.log(resultArr);// [[0, 0, 1], [0, 1, 0], [1, 1, 1]]复制代码

嗯~上面已经提到过,箭头函数体加上大括号后,是需要自己手动return的~

我们来改写下代码一,以便符合需求:

constA = [[0,1,1],[1,0,1],[0,0,0]];constflipAndInvertArr =function(A){return(A.map(item=>{returnitem.reverse().map(r=>1-r)    }))}letresult = flipAndInvertArr(A);console.log(result);// [[0, 0, 1], [0, 1, 0], [1, 1, 1]]

转载自:

作者:call_me_R

链接:https://juejin.im/post/5d28422be51d457756536829

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343

推荐阅读更多精彩内容