前言
复习时使用,希望可以帮到自己,也可以帮到大家。
ECMA相关介绍
ECMA为欧洲计算机制造商协会,这个组织的目的是评估、开发和认可电信和计算机标准。1994年后该组织改名为Ecma国际。
1.1 什么是ECMAScript
ECMAScript是由Ecma国际通过ECMA-262标准化的脚本程序设计语言。
1.2 什么是ECMA-262
Ecma国际制定了许多标准,而ECMA只是其中的一个,所有标准列表有兴趣可以去查看https://www.ecma-international.org/publications/stands/Standard.htm,如下。
1.3 ES6相关历史
1.4 谁在维护ECMA-262
TC39是推进ECMAScript发展的委员会。其会员都是公司(主要是浏览器厂商,比如谷歌、苹果、微软、因特尔等)。TC39定期召开会议,会议由会员公司的代表与特邀专家出席。
1.5 为什么要学习ES6
- ES6版本变动内容最多,具有里程碑;
- 加入许多新语法特性,编程实现更简单、高效;
- 是前端发展趋势,就业必备技能;
二.let和const变量声明及相关特性
2.1 let变量及相关特性
2.1声明格式与var一样:
let a;
let b,c,d;
let e= 100;
let f = 521,g = 'love';
2.2特性
- 变量不能重复声明
let star = '吴亦凡';
let star = '加拿大电鳗';
会出现如下类型的错误:
- 块级作用域 全局,函数,eval
{
let girl="zhou";
}
console.log(girl);
//此时不能打印成功,因为girl这个变量只作用在花括号那一块,所以不能打印;
//即只在所属块的作用域里有效;
- 不存在变量提升
console.log(song);
let song = 'let me love you';
出现如下的错误:
表示不允许在声明之前去使用这个变量
- 不影响作用域链
{
let school = "xu";
function fn() {
console.log(school);
}
fn();
}
打印成功:
![在这里插入图片描述](https://img-blog.csdnimg.cn/93cd2d41a7b5443096f80ff6f646158d
const变量
2.1声明和var和let是一样的;
2.2相关特性
- 一定要初始化值;
const A;
出现如下错误:
- 一般常量使用大写(此处是潜规则,小写也不出错)
- 常量的值不能修改
const SCHOOL = 'sc';
SCHOOL = 'ATGUIGU';
会出现如下错误:
- 块级作用域;
- 对于数组和对象的元素修改,不算做对常量的修改,不会报错;
因为常量所指向的地址没有变化,所以不会报错
三.ES6解构赋值
ES6 允许按照一定模式从数组和对象 中提取,对变量进行赋值,这被称为解构解析。
3.1 数组的解构
cosnt f4 = ['刘德华','张学友','黎明','郭富城'];
let [l,z,li,g] = f4;
console.log(l);
console.log(z);
console.log(li);
console.log(g);
运行结果如下:
3.2 对象的解构(方法频繁调用时可使用)
const hu = {
name: '胡歌',
age: '四十大几',
yanxi: function() {
console.log('我可以演戏');
}
};
let {
name,
age,
yanxi
} = hu;
console.log(name);
console.log(age);
console.log(yanxi);
yanxi();
运行结果如下:
四.模板字符串及简化对象写法
4.1模板字符串
4.1.1 声明
let str = `字符串`;//不知道有没有人和我一样,不知道怎么打出反引号,是键盘数字1旁边的那个
console.log(str, typeof str);
运行结果:
4.1.2 特性
- 内容可以直接出现换行符
let str = `<ul>
<li>张</li>
<li>李</li>
</ul>`;
- 可在字符串进行换行或者拼接的地方使用
- 可以进行变量拼接
let lov = '贾玲';
let out = `${lov}是我喜欢的喜剧演员`;
console.log(out);
运行结果:
4.2简化对象写法
let name = 'zhoushen';
let sing = function() {
console.log('达拉崩吧!');
}
const jieshao = {
name,//简化属性的写法,之前为name:name,
sing,
//简化函数的写法
// improve:function() {
// cosnole.log('达拉崩吧斑得贝迪');
// }
improve() {
cosnole.log('达拉崩吧斑得贝迪')
}
}
console.log(jieshao);
运行结果如下:
五.箭头函数
5.1 声明
let fn = (a, b) => {
return a + b;
}
//调用函数
let result = fn(1, 2);
console.log(result);
5.2 声明特点
- this是静态的,this始终指向函数声明时所在作用域下的this值
function getName() {
console.log(this.name);
}
let getName2 = () => {
console.log(this.name);
}
// 设置window对象的name属性
window.name = 'www';
const school = {
name: 'AWWW',
}
// 直接调用
getName(); //this值指向window
getName2(); //在全局作用域下声明,this值也是指向window
// call调用
getName.call(school); //this所指发生了改变
getName2.call(school); //箭头函数依然指向window
运行结果如下:
可以看出使用call调用的时候,箭头函数的this并没有发生改变,无论使用什么方法去调用,this始终指向函数在声明时作用域下的this值
- 不能作为构造函数,实例化对象
let Person = (name,age) => {
this.name = name;
this.age = age;
}
let me = new Person ('xiao',30);
console.log(me);
运行结果如下:
- 不能使用arguments变量
let fn = () => {
console.log(arguments);
}
fn(1, 2, 3);
运行出现错误:
- 箭头函数的简写
// 当形参只有一个的时候,省略小括号
let add = n => {
return n + n;
//省略花括号。当代码体只有一条语句的时候,此时return必须省略,而且语句的执行结果就是函数的返回值
// let pow = (n) => {
// return n*n;
// }
let pow = n => n * n;
console.log(pow(9));
现在我们来举个栗子来更好的理解箭头函数:
<div id="ad"></div>
<script>
let ad = document.getElementById('ad');
//绑定事件
ad.addEventListener("click", function() {
//let _this = this;//一般函数时,如果没有这个值来保存this值,则会出错,
//this指向Window,而window没有style属性,所以出错
setTimeout(() => { //如果使用箭头函数,this此时是静态值,指向函数声明时所在作用域的this值
this.style.background = 'pink';
}, 2000);
});
</script>
数组的返回:
const arr = [1, 6, 9, 100, 10, 25];
//一般函数
const result = arr.filter(function(item) {
if (item % 2 === 0) {
return true;
} else {
return false;
}
});
//箭头函数
const result = arr.filter(item => item % 2 === 0);
console.log(result);
六.其他特性
6.1函数参数的默认值设置
ES6允许给函数参数赋值初始值
6.1.1 形参初始值 具有默认值得参数,一般位置要靠后(同样是潜规则啦)
function add(a, b, c = 10) {
return a + b + c;
}
let result = add(1, 2);
console.log(result); //13
6.1.2 与解构赋值结合使用
function connect({
host = '127.0.0.1',//如果connect传有 参数,则使用connect的参数,如果没有,则使用我们设置的默认值
username,
password,
port
}) {
console.log(host);
console.log(username);
console.log(password);
console.log(port);
}
connect({
host: 'localhost',
username: 'root',
password: 'root',
port: 3308
})
6.2 rest参数
引入rest参数,用于获取函数的实参,用来代替arguments
首先我们来看看ES5获取实参的方法
function date() {
console.log(arguments);
}
date('白芷', '胡歌', '周星星'); //Arguments(3)
返回结果:
返回的是一个对象
0: “白芷”
1: “胡歌”
2: “周星星”
callee: ƒ date()
length: 3
Symbol(Symbol.iterator): ƒ values()
proto: Object
ES6:
function date(...args) {//放在了形参里面,而下一个的扩展运算符则是放在了调用的实参里面
console.log(args);//filter some every map
}
date('白芷', '胡歌', '周星星');
返回的是一个数组:
[“白芷”, “胡歌”, “周星星”]
0: “白芷”
1: “胡歌”
2: “周星星”
length: 3
proto: Array(0)
rest参数必须要放到参数最后:
function fn(a,b,...args) {
console.log(a); //1
console.log(b); //2
console.log(args); //[3,4,5,6]
}
fn(1,2,3,4,5,6);
//如果写成function fn(a,...args,b){}
//则会出现错误如下:
//Uncaught SyntaxError: Rest parameter must be last formal parameter
6.3 扩展运算符
6.3.1 扩展运算符的介绍
扩展运算符能将数组转换为逗号分隔的参数序列
const tf = ['易烊千玺','王源','王俊凯'];
function chunwan() {
console.log(arguments);
}
chunwan(...tf);
//如果只写入tf
//chunwan(tf);
//返回结果是:
//0: (3) ["易烊千玺", "王源", "王俊凯"]
//callee: ƒ chunwan()
//length: 1
//Symbol(Symbol.iterator): ƒ values()
//__proto__: Object
结果如下:
Arguments(3)
0: “易烊千玺”
1: “王源”
2: “王俊凯”
callee: ƒ chunwan()
length: 3
Symbol(Symbol.iterator): ƒ values()
proto: Object
6.3.2 扩展运算符的应用
- 数组的合并
const kuaizi = ['王太利', '肖央'];
const fenghuang = ['曾毅', '玲花'];
const zuixuanxiaopg = [...kuaizi, ...fenghuang];
console.log(zuixuanxiaopg); //["王太利","肖央","曾毅","玲花"]
- 数组的克隆
const sanzhihua = ['E', 'G', 'M'];
const sanyecao = [...sanzhihua];
console.log(sanyecao); //(3) ["E", "G", "M"]
- 将伪数组转为真正的数组
const divs = document.querySelectorAll('div');
const divArr = [...divs];
console.log(divArr); //(3) [div, div, div],此时变成了一个真正的数组
6.4 Symbol
Symbol 是ES6引入的一种新的原始数据类型,表示独一无二的值。是一种类似于字符串的值
6.4.1 特点
1.Symbol的值是唯一的 ,用来解决命名冲突的问题
2.Symbol值不能与其他数据进行运算
3.Symbol定义的对象属性不能使用for…in 循环遍历,但是可以使用Reflect.ownKeys来获取对象的所有键名
6.4.2 Symbol的创建
- 创建Symbol:
let s = Symbol();
let s2 = Symbol("zs");
let s3 = Symbol("zs");
console.log(s2 === s3); //false
//false可以理解为s2和s3虽然值一样,但是他们的编号不同,所以错误
- Symbol.for创建:
let s4 = Symbol.for('sg');
let s5 = Symbol.for('sg');
console.log(s4 === s5); //true
6.4.3 Symbol的注意事项
- 不能与其他数据进行运算
let s = Symbol();
let result = s + 100;
结果出现如下错误:
Uncaught TypeError: Cannot convert a Symbol value to a number
- 对象添加Symbol类型的属性:
let game = {};
let methods = {
up: Symbol(),
down: Symbol()
};
game[methods.up] = function() {
console.log("下降");
}
game[methods.down] = function() {
console.log("上升");
}
console.log(game);
- Symbol内置值
Symbol内置值是Symbol的属性,而Symbol和它的内置值,可以作为对象和数组的属性来使用,具体如下:
//1.
class Person {
static[Symbol.hasInstance](param) {
console.log(param);
console.log("wobeiyonglaijiance ");
}
}
let o = {};
console.log(o instanceof Person); //检测这个值是否是该对象的实例
//2.
const arr = [1, 2, 3];
const arr2 = [4, 5, 6];
arr2[Symbol.isConcatSpreadable] = false; //控制数组在进行合并时,是否可以展开
console.log(arr.concat(arr2));
6.5 迭代器
迭代器是一种接口,为各种不同的数据结构提供统一的访问机制,任何数据只要部署Iterator接口,就可以完成遍历操作。
ES6创造了一种新的遍历命令for…of循环,Iterator接口主要供for…of消费
原生具备Iterator接口的数据有:Array、Arguments、Set、Map、String、TypeArray、NodeList
工作原理:
1.创建一个指针对象,指向当前数据结构的起始位置;
2.第一次调用对象的next方法,指针自动指向数据结构的第一个成员
3.接下来不断调用next方法,指针一直在往后移动,一直到指向最后一个成员
4.每调用方法返回一个包含value和done属性的对象
const xiyou = ['唐僧', '孙悟空', '猪八戒', '沙僧'];
let iterator = xiyou[Symbol.iterator]();
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
自定义遍历数据:
//使用for...of来遍历banji里stus的值
const banji = {
name: "zjyb",
stus: [
'xiaoming',
'xiaoning',
'xiaotian',
'night'
],
[Symbol.iterator]() {
let index = 0;
let _this = this;
return {
next: function() {
if (index < _this.stus.length) {
const result = {
value: _this.stus[index],
done: false
};
index++;
return result;
} else {
return {
value: undefined,
done: true
}
}
}
};
}
}
for (let v of banji) {
console.log(v);
}
结果:
6.6生成器函数
生成器函数是ES6提供的一种异步编程解决方案,语言行为与传统函数完全不同
异步编程:文件操作、网络操作(AJAX,request)、数据库操作
6.6.1生成器函数声明及调用:
function* gen() {
console.log('hello ');
}
let iterator = gen();
// console.log(iterator);直接调用并不能成功,而需要使用next方法调用
iterator.next(); //hello
// yield:
function* gen() {
console.log(111);
yield 'meiyouerduo';//函数代码的分隔符,即分段的作用
console.log(222);
yield 'meiyouweiba';
console.log(333);
yield 'zhenqiguai';
console.log(444);
}
let iterator = gen();
iterator.next(); //111
//若只调用一次next,则只打印111,而不是像传统函数一样全部打印
//遍历
for (let v of gen()) {
console.log(v);
}
6.6.2生成函数参数
function* gen(arg) {
console.log(arg); //AAA
let one = yield 111;
console.log(one); //BBB
let two = yield 222;
console.log(two); //CCC
let three = yield 333;
console.log(three); //DDD
}
let iterator = gen('AAA');
console.log(iterator.next()); //next方法可以传入实参,传入的实参就是yield语句的返回结果
//第一次调用返回传入函数的实参
console.log(iterator.next('BBB')); //第二次传入的实参会作为第一个yield语句的整个返回结果
console.log(iterator.next('CCC'));//第三次传入的实参会作为第二个yield语句的整个返回结果
console.log(iterator.next('DDD'));//即next传入的实参会作为上一个yield语句的返回结果
6.6.3实例
1.获取数据
//2模拟获取 用户数据 订单数据 商品数据
function getUsers() {
setTimeout(() => {
let data = '用户数据';
iterator.next(data);
}, 1000);
}
function getOrders() {
setTimeout(() => {
let data = '订单数据';
iterator.next(data);
}, 1000);
}
function getGoods() {
setTimeout(() => {
let data = '商品数据';
iterator.next(data);
}, 1000);
}
function* gen() {
let users = yield getUsers();
console.log(users);
let orders = yield getOrders();
console.log(orders);
let goods = yield getGoods();
console.log(goods);
}
let iterator = gen();
iterator.next();
结果:
2.解决回调地狱
// 1s后控制台输出 111 2s后输出222 3s后输出333
// 回调地狱:不停回调
function one() {
setTimeout(()=>{
console.log(111); //111
iterator.next();
},1000);
}
function two() {
setTimeout(()=>{
console.log(222); //222
iterator.next();
},2000);
}
function three() {
setTimeout(()=>{
console.log(333); //333
iterator.next();
},3000);
}
function * gen() {
yield one();
yield two();
yield three();
}
let iterator = gen();
iterator.next();
总结
这是第一部分,后面的知识会在几天后发出,我们一起探讨学习啊,如果有错误,也请多多指出啦~