ECMAScript 6 Section 1

大家好,本人名叫苏日俪格,大家叫我 (格格) 就好,最近我一直在研究ES6,在研究的过程中并记录了下来,给大家分享下,有什么问题或者建议可以在评论区给出,望路过的大佬们不喜勿喷,本文仅供初入ES6江湖的人士(小白)专用,下面就让我们来聊一聊ECMAScript:

ECMAScript是一种由Ecma国际(前身为欧洲计算机制造商协会,英文名称是European Computer Manufacturers Association)通过ECMA-262标准化的脚本程序设计语言。这种语言在万维网上应用广泛,它往往被称为JavaScriptJScript,但实际上后两者是ECMA-262标准的实现和扩展。

综上所述我们可以把ECMAScript当成是一个标准,而实现者是:JavaScript、typescript和actionscript;如果理解不了,就可以这么理解,比如HTML也是一个标准,而实现者是浏览器;

小白:之前有看到过ES2015,它又是什么意思呢?
格格:其实我们通常所说的ES6也就是ES2015,意思就是在2015年发布的ECMAScript 6.0版本,而之后的ES2016和ES2017也都是ES6里面的,因此两者是一样的,只不过ES2015是官方的名称,

下面让我们来聊一聊ES6中的新特性吧:

1. let const

let和const都是定义(声明)用的,let是声明变量,而const是声明常量的;
变量:定义完了可以改变
常量:定义完了无法改变

var虽然也是声明变量的,不过var声明有很多潜在的问题,至于是哪些问题,让我们来看一个例子:

for (var i=0; i<10; i++) {
	//coding
}
alert(i);  // i=10

小白:⊙▽⊙这不科学啊,在外面还能访问?
格格:这个时候有的朋友看了就感觉很神奇,尤其是学Java的,不应该是这样的对吧,但事实如此,接着往下看你就明白了

如果非得说到作用域的问题的话,那么有两种作用域,一个是全局作用域,另一个就是函数作用域(局部作用域),在这个例子里面声明的i就是一个全局的变量,所以下面是可以访问到的,如果下文继续使用i的话,那么就要从i=10开始,后果不堪设想。

下面我们再来看一个例子:

var a = 1;
function test(){
	alert(a);  // a = undefined
	var a = 2;
}
test();

这个例子暴露了一个问题,其实也不算是问题,就是因为JavaScript具有自己的特性:变量提升的问题(也可以叫做预解析),这到底是个什么东西呢?上面的例子可以也看成是下面的例子:

var a = 1;
function test(){
	var a;
	alert(a);
	a = 2;
}
test();

相信大家已经看懂了,在代码执行的过程中,事先定义了一个a,这时并没有赋值,a当然就是undefined;

由此我们给出一个定义:变量提升意思就是在js执行之前,会把变量提到顶部,而且不会突破作用域;再看一下预解析的例子:

<script type="text/javascript">
	var a = 1;
</script>
<script type="text/javascript">
	alert(a);  // a = 1
</script>

JavaScript虽然是一个脚本语言,无需解析,但是它还是有一个小小的预解析的过程:
读取一个script标签 ==> 预解析 ==> 执行代码 ==> 再读取下一个script标签 ==> ...依次循环

下面让我们回到let和const:

for (let i=0; i<10; i++) {
	//coding...
}

alert(i);	// i is not defined

大家可以看到,同样的例子使用let定义i的话,外面调用就会报错,那么这又是因为什么呢?

这就是ES6中引入的新特性:块级作用域
块级作用域就是{ coding... } 只要是带有{}的都是一个块级作用域,下面到了考察大家的时刻了:

let a = 1;
function test(){
	alert(a);
	let a = 2;
}
test();

和之前的例子一样,只不过将var换成了let,这个时候的结果就是a is not defined,因为let只在块级作用域中起作用,所以a不可能是1,由于let不能提升,所以a就是未定义。
综上所述:let的第一个特性就是没有预解析,也不存在变量提升

小白:什么鬼?什么叫做第一个特性,难道还有第二个特性不成◔ ‸◔?
格格:那么我要在这里恭喜你中了大奖了,回家准备买彩票吧,它确实有第二个特性<( ̄ˇ ̄)/

下面在让我们一起看一个例子:

let a = 1;
let a = 2;
alert(a);

这个时候你会发现,它和var是有着非常大的区别的,正常使用var的时候大家都知道,a肯定是等于2的,那么在这里Identifier 'a' has already been declared,这句话的意思是a已经被定义了,也就是说let不允许重复定义同一个变量

格格:这就是它的第二个特性了,接来下我们要讲的就是let的第三个特性ʅ(´◔౪◔)ʃ
小白:什么?o( ̄ヘ ̄o#) 还有第三个?
格格:其实第三个即是第二个,第二个即是第三个つ﹏⊂

下面我们来看一个例子:

for (let i=0; i<10; i++) {
	let i = 2;
	console.log(i);
}

小白:so easy!i已经被定义了呗
格格:嘿嘿,被忽悠了吧,答案是输出了10个2
小白:(・∀・*) 为啥子嘛

刚才说到,不允许重复定义一个变量,但它的条件肯定是建立在块级作用域下的呀,这个循环中的i是作用域里面的i的父级,所以在里面还是可以定义的,第三个特性就算是给第二个加个补充:在不同作用域下,可以重复定义

小白:噢噢,刚才好像被晃了一下子→_→
格格:ㄟ( ▔, ▔ )ㄏ

const的特性和let是一模一样的,不同的就只是常量而已,即为定义完了不能修改,否则报错

下面又到了考察大家的时刻了:

const arr = ['aaa','bbb','ccc'];
arr.push('ddd');
console.log(arr);  // ["aaa", "bbb", "ccc", "ddd"]

小白:说好的不能修改了?你在逗我。。。
格格:哈哈,你又不懂了吧

这个arr是一个数组,即是一个对象,对象本身是存在引用的,如果想让数组无法修改的话,也有办法的,可以用Object.freeze(对象)

格格:所以呀,var就当做是你的前任,忘了吧...
小白:哪能说忘就忘,相信自己会慢慢接受现任的

2. 解构赋值

当我第一次听到这个东西的时候,心里冒出了无数的疑问,这个名字太奇怪了,但是我想说的是解构赋值非常有用

当我们定义多个变量的时候还要一个一个去命名和赋值,非常麻烦,如果用了解构赋值,像这样:

let [a,b,c] = [1,2,3];
console.log(a,b,c);  // 1,2,3

正如你所看到的,它默认的把你右边赋的值都解出来分配给左边的变量,一一对应进行赋值

小白:这个看起来很好用,可是如果两侧不对称了呢?
格格解构赋值意思就是说两侧的结构和格式都必须一模一样,再举个例子:

let [a,b,c] = [1,[2,3]];
console.log(a,b,c);	// 1 [2, 3] undefined

两侧不一致就会导致像上面这样的结果,解决方式就是:

let [a,[b,c]] = [1,[2,3]];
console.log(a,b,c);	// 1 2 3

数组还有一种玩法就是:

let [a,b,c='暂无数据'] = [1,2];
console.log(a,b,c);  // 1 2 暂无数据

当然上面这种写法用处不大,但是在交换两个变量的值的时候,正常是还得找第三个变量打配合就行转换,现在不需要了:

let a = 1;
let b = 2;
[a,b] = [b,a];
console.log(a,b);  // 2 1

以上这是数组的解构赋值,下面看一下json的解构赋值是怎样的:

let {name,age,job} = {
    name: '苏日俪格',
    age: 24,
    job: 'web前端开发'
}

解构赋值一般用在和后台进行数据交互的时候,后台数据大多都是json形式的传递的,数据多的时候都是json嵌套json,以至于有很多,这时就可以用解构赋值全都解出来就可以了,不要谢我,记住我是雷锋~( ̄▽ ̄~)(~ ̄▽ ̄)~

let json = {
    name: '苏日俪格',
    age: '24',
    job: 'web前端开发'
}
let {name,age,job} = json;
console.log(name,age,job);  // 苏日俪格 24 web前端开发

还有第二种写法:

let json = {
    name: '苏日俪格',
    age: '24',
    job: 'web前端开发'
}
let {name:a,age:b,job:c} = json;
console.log(a,b,c);  // 苏日俪格 24 web前端开发

从字面就能够理解,上面这种写法只是给每一个变量起了一个名字,但是如果起了名字之后,下面调用的时候里面的参数还是写的以前名字,那么就会报错is not defined

接下来给大家讲一个关于解构赋值的小小的应用:

function getPos(){
	return {
		l: 10,
		t: 20
	}
}
let {l, t} = getPos();
console.log(l,t);  // 10 20

当然解构赋值也可以作为参数进行传递,用法都是一样的,保持一一对应即可。

讲到这里,给大家插一个小tip,在ES2017 6月发布的版本中新增了一个小可爱:

function show(a,b,c){
	console.log(a,b,c);	// 1 2 3
}
show(1,2,3,);

仔细看会发现我们在传值的时候,多传了一个逗号(,),但是数据依然能够显示出来,这个看似没用,但是在与后台交互的时候,往往会因为多了个逗号而导致程序报错;不知道大家有没有做过微信小程序,里面有个配置文件app.json,是用来配置整个小程序所有的页面的,当我们想把另一个作为首页访问的话,还要特意去删掉那个多余的逗号,这个解决了我们遇到的问题。

3. 字符串模板

字符串模板其实就是为了降低字符串拼接难度而生的,在拼接一些数据量大的时候,这个可真的是让人头疼的要死,比如说:

let name = '苏日俪格';
let age = 24;
let str = '我的名字叫'+name+',今年'+age+'岁';
console.log(str);  // 我的名字叫苏日俪格,今年24岁

拼接起来很麻烦,数据多的话就容易乱,ES6提出了这个字符串模板中有一个(``)

小白:这个字符是怎么打出来的呢?
格格:切换成英文输入法,找到键盘上的数字1键前面的那个按键,记住不是小键盘数字1哦

使用反引号(``)拼接是这样的:

let name = '苏日俪格';
let age = 24;
let str = `我的名字叫${name},今年${age}岁`;
console.log(str);  // 我的名字叫苏日俪格,今年24岁

格格:这样看起来是不是清晰的不要不要的?

还有字符串新增的方法,比如说str.startsWith(要检测的东西);这个一般用来检测协议(http/https),返回布尔值;既然有以谁开头了那么就有以谁结尾:str.endsWith(要检测的东西);这个一般用来检测文件类型(jpg);重复字符串方法:str.repeat(次数);这个方法可以将一个字符串重复输出,一般不会用到,造假数据可能会用到吧

4. 箭头函数

在箭头函数之前,需要看一个例子:

function show(a=1){
	let a = 2;
	console.log(a);	// Identifier 'a' has already been declared
}
show();

上面的代码告诉我们函数的参数默认已经被定义了,一经声明,就不能再用let或者const进行声明了,只能用var;这个有点跑题了,算是送大家的一个小tip吧,下面让我们一起来看箭头函数吧:

//普通函数的写法:
function show(){
	return 1;
}
show();
//上面的函数的箭头函数写法:
let show = () => 1;  // 箭头的左边是参数右边是返回值
console.log(show());

如果要想在函数里面写语句的时候,写法是这样的:

let show = (a=1,b=2) => {
	console.log(a,b);  // 1 2
}
show();

箭头函数和普通函数除了写法不同之外,还有三点不同,请看下面的例子:

let json = {
	name: '苏日俪格',
	show: function(){
		setTimeout(function(){
			console.log(this.name);	// 控制台什么都没有输出
		},1000);
	}
}
json.show();

这个例子大多都是在vue等框架下开发遇到的问题,因为this指向的是当前的函数,先要让它指向外面的json对象,就还要在外面进行转换,太麻烦,而箭头函数则不同:

let json = {
	name: '苏日俪格',
	show: function(){
		setTimeout(() => {
			console.log(this.name);	// 苏日俪格
		},1000);
	}
}
json.show();

综上所述,第一个不同之处就是箭头函数里的this指向的是定义函数所在的对象,而不是运行时所在的对象

小白:那第二个不同之处呢?
格格:第二个就是箭头函数里面不能使用arguments,如果用了就是is not defined

解决办法:就是...扩展运算符(在本章的第五小节)

let show = (...a) => {
	console.log(a);  // [1, 2, 3, 4, 5]
};
show(1,2,3,4,5);

第三个就是箭头函数不能当做构造函数来用

let Show = ()=>{
	this.name = '苏日俪格';
}
let a = new Show();
console.log(a.name);	// Show is not a constructor

5. 扩展运算符

... 代表着扩展运算符或Rest(剩余)运算符
废话不多说,直接带大家看几个例子:

// 当传入的参数不确定或者多个的时候,就可以当做arguments来使用
function show(...a){
	console.log(a);	// [14, 12, 54, 33, 22]
}
show(14,12,54,33,22);

此外扩展运算符还可以解决数组的引用的问题:

let a = [14,12,54,33,22];
let b = a;  // 相当于copy
a.push(44);
console.log(a);	// [14, 12, 54, 33, 22, 44]
console.log(b);	// [14, 12, 54, 33, 22, 44]

上面这个例子说明了b是a的一个引用,也就是说二者所在的内存是同一个,要想改变a不影响b的话,就要开辟一个新内存,解决方式:

let a = [14,12,54,33,22];
let b = [...a];
a.push(44);
console.log(a);	// [14, 12, 54, 33, 22, 44]
console.log(b);	// [14, 12, 54, 33, 22]

扩展运算符还可以用来数组的排序,此排序并不是什么大小排序,而是按照每一位的首位数字进行排序的,第一位相同就看第二位,依次排列,和字典式排序相似,看下面的例子:

function orderBy(...a){
	return a.sort();
}
console.log(orderBy(51,12,7,34,3));	// [12, 3, 34, 51, 7]
let arr = ['aaa','bbb','ccc'];
let arr2 = "aabbcc";
console.log(arr);	// ["aaa", "bbb", "ccc"]
console.log(...arr);	// aaa bbb ccc
console.log(arr2);	// aabbcc
console.log(...arr2);	// a a b b c c

综上所述,...可以完成字符串和数组之间的转换

小白:那个Rest运算符又是什么呢?

请看下面的这个例子:

function show(a,...b){
	console.log(a);	// 51
	console.log(b);	// [12, 7, 34, 3]
}
show(51,12,7,34,3);

看完了这个例子懂了吧,就是说前面的参数一一对应,后面的那个...b就代表剩下的参数,因为是剩余参数所以这个剩余运算符要放在最后的位置,因此有的人又称为剩余运算符

本文的所有内容均是一字一字敲上去的,希望大家阅读完本文可以有所收获,因为能力有限,掌握的知识也是不够全面,欢迎大家提出来一起分享!谢谢O(∩_∩)O~

github个人主页:https://github.com/YuFy1314
我的简书:https://www.jianshu.com/u/72f239ec5d03
Resume:https://yufy1314.github.io/
等一下( •́ .̫ •̀ ),我还有最后一句话:
这里虽然没有都市的繁华,
也没有山林的鸟语花香,
只有一片如水的宁静,
古人云:
既来之则安之,
既然来到了这里,
就可以静心休憩你的灵魂,
调养你疲惫的心,
再见...

posted @ 2018-06-01 16:39  苏日俪格  阅读(167)  评论(0编辑  收藏  举报