1.什么是ECMA
1.1 什么是ECMA
ECMA(European Computer Manufacturers Association)中文名称为欧洲计算机制造商协会,这个组织的目标是评估、开发和认可电信和计算机标准。1994 年后该组织改名为 Ecma 国际。
1.2 什么是ECMAScript
ECMAScript 是由 Ecma 国际通过 ECMA-262 标准化的脚本程序设计语言。
1.3 为什么要学习ES6
-
ES6 的版本变动内容最多,具有里程碑意义
-
ES6 加入许多新的语法特性,编程实现更简单、高效
-
ES6 是前端发展趋势,就业必备技能
1.4 兼容性
可查看兼容性:http://kangax.github.io/compat-table/es6/
2.ECMAScript6新特性
2.1 let关键字
let 关键字用来声明变量,使用 let 声明的变量有几个特点:
-
不允许重复声明
-
块级作用域
-
不存在变量提升
-
不影响作用域链
代码演示:
//声明变量
let a;
let b,c,d;
let e = 100;
let f = 521, g = 'iloveyou', h = [];
//1. 变量不能重复声明
let star = '罗志祥';
let star = '小猪';
//2. 块级作用域 (if else while for)
{
let girl = '周扬青';
}
console.log(girl);
//3. 不存在变量提升
console.log(song);
let song = '恋爱达人';
//4. 不影响作用域链
{
let school = '清华大学';
function fn(){
console.log(school);
}
fn();
}
实践案例:
//获取div元素对象
let items = document.getElementsByClassName('item');
//遍历并绑定事件
for(let i = 0;i<items.length;i++){
items[i].onclick = function(){
//修改当前元素的背景颜色
// this.style.background = 'pink';
items[i].style.background = 'pink';
}
}
当我们使用var变量声明i
时,由于变量是全局的,当循环执行完毕后,i
的值已经变为items.length了,使用items[i]将选不中任何标签。而let声明的变量只在对应的代码块生效,互不影响。
应用场景:以后声明变量使用 let 就对了
2.2 const关键字
const 关键字用来声明常量,const 声明有以下特点:
-
声明必须赋初始值
-
标识符一般为大写
-
不允许重复声明
-
值不允许修改
-
块级作用域
代码演示:
//声明常量
const SCHOOL = '清华大学';
//1. 一定要赋初始值
const A;
//2. 一般常量使用大写(潜规则)
const a = 100;
//3. 常量的值不能修改
SCHOOL = '北京大学';
//4. 块儿级作用域
{
const PLAYER = 'UZI';
}
console.log(PLAYER);
//5. 对于数组和对象的元素修改, 不算做对常量的修改, 不会报错
const TEAM = ['UZI','MLXG','Ming','Letme','XiaoHu'];
// TEAM.push('Meiko');
注意: 对象属性修改和数组元素变化不会触发const错误
应用场景:声明对象类型使用 const,非对象类型声明选择let
2.3 变量的解构赋值
ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构赋值。
// 1. 数组的解构
const F4 = ['小沈阳','刘能','赵四','宋小宝'];
let [xiao, liu, zhao, song] = F4;
console.log(xiao);
console.log(liu);
console.log(zhao);
console.log(song);
//2. 对象的解构
const zhao = {
name: '赵本山',
age: '不详',
xiaopin: function(){
console.log("我可以演小品");
}
};
let {name, age, xiaopin} = zhao;
console.log(name);
console.log(age);
console.log(xiaopin);
xiaopin();
let {xiaopin} = zhao;
xiaopin();
注意:频繁使用对象方法、数组元素,就可以使用解构赋值形式
2.4 模板字符串
模板字符串(template string)是增强版的字符串,用反引号(`)标识,特点:
1) 字符串中可以出现换行符
2) 可以使用 ${xxx} 形式输出变量
代码演示:
//2. 内容中可以直接出现换行符
let str = `<ul>
<li>艾伦</li>
<li>三笠</li>
<li>阿尔敏</li>
<li>利威尔</li>
</ul>`;
//3. 变量拼接
let lovest = '周星驰';
let out = `${lovest}是我心目中最搞笑的演员!!`;
console.log(out);
2.5 简化对象写法
ES6 允许在大括号里面,直接写入变量和函数,作为对象的属性和方法。这样的书写更加简洁。
let name = '调查兵团';
let change = function(){
console.log('为人类献出心脏!!');
}
const school = {
name,
change,
improve(){
console.log("我们可以提高你的技能");
}
}
console.log(school);
2.6 箭头函数
ES6 允许使用「箭头」(=>)定义函数。
let fn = (a,b) => {
return a + b;
}
//调用函数
let result = fn(1, 2);
console.log(result);
箭头函数的注意点:
-
如果形参只有一个,则小括号可以省略
-
函数体如果只有一条语句,则花括号可以省略,函数的返回值为该条语句的执行结果
-
箭头函数 this 指向声明时所在作用域下 this 的值
-
箭头函数不能作为构造函数实例化
-
不能使用 arguments
代码演示:
//1. this 是静态的. this 始终指向函数声明时所在作用域下的 this 的值
function getName(){
console.log(this.name);
}
let getName2 = () => {
console.log(this.name);
}
//设置 window 对象的 name 属性
window.name = '美职篮';
const school = {
name: "NBA"
}
//直接调用
getName();
getName2();
//call 方法调用
getName.call(school);
getName2.call(school);
//2. 不能作为构造实例化对象
let Person = (name, age) => {
this.name = name;
this.age = age;
}
let me = new Person('xiao',30);
console.log(me);
//3. 不能使用 arguments 变量
let fn = () => {
console.log(arguments);
}
fn(1,2,3);
//4. 箭头函数的简写
//1) 省略小括号, 当形参有且只有一个的时候
let add = n => {
return n + n;
}
console.log(add(9));
//2) 省略花括号, 当代码体只有一条语句的时候, 此时 return 必须省略
// 而且语句的执行结果就是函数的返回值
let pow = n => n * n;
console.log(pow(8));
2.6 函数初始值
ES6 允许给函数参数赋值初始值
//1. 形参初始值 具有默认值的参数, 一般位置要靠后(潜规则)
function add(a,c=10,b) {
return a + b + c;
}
let result = add(1,2);
console.log(result);
//2. 与解构赋值结合
function connect({host="127.0.0.1", username,password, port}){
console.log(host)
console.log(username)
console.log(password)
console.log(port)
}
connect({
host: '182.127.71.134',
username: 'root',
password: 'root',
port: 3306
})
2.7 rest参数
ES6 引入 rest 参数,用于获取函数的实参,用来代替 arguments
// ES5 获取实参的方式
function date(){
console.log(arguments);
}
date('白芷','阿娇','思慧');
// rest 参数
function date(...args){
console.log(args);// filter some every map
}
date('阿娇','柏芝','思慧');
// rest 参数必须要放到参数最后
function fn(a,b,...args){
console.log(a);
console.log(b);
console.log(args);
}
fn(1,2,3,4,5,6);
2.8 spread 扩展运算符
扩展运算符(spread)也是三个点(...)。它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列,对数组进行解包。
// 『...』 扩展运算符能将『数组』转换为逗号分隔的『参数序列』
//声明一个数组 ...
const tfboys = ['易烊千玺','王源','王俊凯'];
// => '易烊千玺','王源','王俊凯'
// 声明一个函数
function chunwan(){
console.log(arguments);
}
chunwan(...tfboys);// chunwan('易烊千玺','王源','王俊凯')
2.9 Symbol
2.9.1 基本使用
ES6 引入了一种新的原始数据类型 Symbol,表示独一无二的值。它是JavaScript 语言的第七种数据类型,是一种类似于字符串的数据类型。
Symbol 特点
-
Symbol 的值是唯一的,用来解决命名冲突的问题
-
Symbol 值不能与其他数据进行运算
-
Symbol 定义的对象属性不能使用 for…in 循环遍历 ,但是可以使用Reflect.ownKeys 来获取对象的所有键名
代码演示:
//创建Symbol
let s = Symbol();
console.log(s, typeof s);
let s2 = Symbol('海贼王');
let s3 = Symbol('海贼王');
console.log(s2===s3); //false
//Symbol.for 创建
// 通过 Symbol.for() 方法创建可共享的 Symbol
let s4 = Symbol.for('柯南');
let s5 = Symbol.for('柯南');
console.log(s4===s5); //true
//不能与其他数据进行运算
let result = s + 100; //报错
let result = s > 100; //报错
let result = s + s; //报错
2.9.2 内置值
除了定义自己使用的 Symbol 值以外,ES6 还提供了 11 个内置的 Symbol 值,指向语言内部使用的方法。可以称这些方法为魔术方法,因为它们会在特定的场景下自动执行。
Symbol.hasInstance
:一个在执行 instanceof
时调用的内部方法,用于检测对象的继承信息。
Symbol.isConcatSpreadable
:一个布尔值,用于表示当传递一个集合作为 Array.prototype.concat()
方法的参数时,是否应该将集合内的元素规整到同一层级。
Symbol.iterator()
:检查指定对象中是否存在默认的函数类型迭代器。
Symbol.match(regex)
:一个在调用 String.prototype.match()
方法时调用的方法,用于比较字符串。
Symbol.replace(regex, replacement)
:一个在调用 String.prototype.replace()
方法时调用的方法,用于替换字符串的子串。
Symbol.search(regex)
:一个在调用 String.prototype.search()
方法时调用的方法,用于在字符串中定位子串。
Symbol.species(regex)
:用于创建派生对象的构造函数。
Symbol.split
:一个在调用 String.prototype.split()
方法时调用的方法,用于分割字符串。
Symbol.toPrimitive
:一个返回对象原始值的方法。
Symbol.toStringTag
:一个在调用 String.prototype.toString()
方法时使用的字符串,用于创建对象描述。
Symbol.unscopables
:一个定义了一些不可被 with 语句引用的对象属性名称的对象集合。
代码演示:
class Person{
static [Symbol.hasInstance](param){
console.log(param);
console.log("我被用来检测类型了");
return false;
}
}
let o = {};
console.log(o instanceof Person);
const arr = [1,2,3];
const arr2 = [4,5,6];
arr2[Symbol.isConcatSpreadable] = false;
//false则为不展开 concat后为[1,2,3,[4,5,6]] true为展开,concat后为[1,2,3,4,5,6]
console.log(arr.concat(arr2));
2.10 迭代器
遍历器(Iterator)就是一种机制。它是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作。
1) ES6 创造了一种新的遍历命令 for...of 循环,Iterator 接口主要供 for...of 消费
2) 原生具备 iterator 接口的数据(可用 for of 遍历):Array、Arguments、Set、Map、String、TypedArray、NodeList
3) 工作原理
a) 创建一个指针对象,指向当前数据结构的起始位置
b) 第一次调用对象的 next 方法,指针自动指向数据结构的第一个成员
c) 接下来不断调用 next 方法,指针一直往后移动,直到指向最后一个成员
d) 每调用 next 方法返回一个包含 value 和 done 属性的对象
代码演示:
//声明一个数组
const xiyou = ['唐僧','孙悟空','猪八戒','沙僧'];
//使用 for...of 遍历数组
for(let v of xiyou){
console.log(v);
}
let iterator = xiyou[Symbol.iterator]();
//调用对象的next方法
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());