一、let
let 关键字用来声明变量,使用 let 声明的变量有几个特点:
- 不允许重复声明
- 块儿级作用域
- 不存在变量提升(不允许在声明变量前使用)
- 不影响作用域链
应用场景:以后声明变量使用 let 就对了
二、const
const 关键字用来声明常量,const 声明有以下特点:
- 必须要赋初始值
- 一般常量使用大写(潜规则)
- 不允许重复声明
- 常量的值不能修改
- 块儿级作用域
ps:对于对象属性和数组元素的修改, 不算做对常量的修改, 不会报错
应用场景:声明对象或数组类型使用 const,非对象数组类型声明选择 let
三、变量的解构赋值
ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,称为解构赋值。
// 数组的解构赋值
const xhd = ['苏有朋', '吴奇隆', '陈志朋'];
let [ su, wu, chen ] = xhd;
// 对象的解构赋值
const guo = {
name: '郭德纲',
age: '47',
xiangsheng: function () {
console.log("我可以说相声");
}
};
let { name, age, xiangsheng } = guo;
xiaopin();
ps:频繁使用对象方法、数组元素,可以使用解构赋值
四、模板字符串
模板字符串是增强版的字符串,用反引号(`)标识,特点有:
- 字符串中可以出现换行符
// 定义字符串
let str = `
- 沈腾
- 玛丽
- 魏翔
- 艾伦
`;
- 变量拼接
let lovest = '无情';
let out = `${lovest}哈拉少!!`;
ps:当遇到字符串与变量拼接的情况使用模板字符串
五、简化对象写法
ES6 允许在大括号里面,直接写入变量和函数,作为对象的属性和方法。这样的书写更加简洁。
let name = '腾讯游戏';
let change = function(){
console.log('没钱玩个锤子!!');
}
const school = {
name,
change,
pay(){
console.log("充钱使你更强");
}
}
总之,简写就对了
六、箭头函数
ES6 允许使用 箭头(=>)定义函数
// 格式
let fn = (a,b) => {
return a + b;
}
// 调用函数
let result = fn(1, 2);
注意点:
- this 是静态的. this 始终指向函数声明时所在作用域下的 this 的值
- 不能作为构造实例化对象
- 不能使用 arguments 变量
- 如果形参只有一个,则小括号可以省略
let fn2 = num => {
return num * 10;
};
- 代码体如果只有一条语句,则大括号可以省略,return 必须省略,函数的返回值为该条语句的执行结果
let pow = n => n * n;
ps:箭头函数不会更改this指向,用来指定回调函数会非常合适
七、rest 参数
ES6 引入 rest 参数,用于获取函数的实参,用来代替 arguments
// ES5 获取实参的方式
function date(){
console.log(arguments);
}
date('giao','嗷力给','淦');
// rest 参数
function date2(...args){
console.log(args);// filter some every map
}
date2('giao','嗷力给','淦');
// rest 参数必须要放到参数最后
function fn(a,b,...args){
console.log(a);
console.log(b);
console.log(args);
}
fn(1,2,3,4,5,6);
ps:rest参数非常适合不定个数参数函数的场景
八、扩展运算符
『...』 扩展运算符能将数组转换为逗号分隔的参数序列,对数组进行解包,好比 rest 参数的逆运算
// 展开数组
const she = ['Selina','Hebe','Ella'];
function superstar(){
console.log(arguments);
}
superstar(...she);// chunwan('Selina','Hebe','Ella')
// 1. 数组的合并
const kuaizi = ['王太利','肖央'];
const fenghuang = ['曾毅','玲花'];
// ES5数组合并
// const zuixuanxiaopingguo = kuaizi.concat(fenghuang);
const zuixuanxiaopingguo = [...kuaizi, ...fenghuang];
// 2. 数组的克隆
const tuhai = ['8','5','7'];
const sanyecao = [...tuhai];// ['8','5','7']
//3. 将伪数组转为真正的数组
const divs = document.querySelectorAll('div');
const divArr = [...divs];
九、Symbol
- 基本使用
ES6 引入了一种新的原始数据类型 Symbol,表示独一无二的值。
它是JavaScript 语言的第七种数据类型,是一种类似于字符串的数据类型。
特点:
(1)Symbol的值是唯一的,用来解决命名冲突的问题
(2)Symbol值不能与其他数据进行运算
(3)Symbol定义的对象属性不能使用for…in循环遍历,但是可以使用Reflect.ownKeys 来获取对象的所有键名
// 创建Symbol
let s = Symbol();
// console.log(s, typeof s);
// 添加标识的Symbol
let s2 = Symbol('嘿嘿嘿');
let s3 = Symbol('嘿嘿嘿');
// Symbol.for创建
let s4 = Symbol.for('啦啦啦');
let s5 = Symbol.for('啦啦啦');
ps:遇到唯一性的场景时要想到 Symbol
Symbol向对象中添加属性和方法的方式
// 向对象中添加方法 up down
let game = {
name:'俄罗斯方块',
up: function(){},
down: function(){}
};
// 声明一个对象
let methods = {
up: Symbol(),
down: Symbol()
};
game[methods.up] = function(){
console.log("我可以改变形状");
}
game[methods.down] = function(){
console.log("我可以快速下降!!");
}
// 调用
game[methods.up]();
game[methods.down]();
let youxi = {
name:"狼人杀",
[Symbol('say')]: function(){
console.log("我可以发言")
},
[Symbol('zibao')]: function(){
console.log('我可以自爆');
}
}
-
Symbol 内置值
除了定义自己使用的 Symbol 值以外,ES6 还提供了 11 个内置的 Symbol 值,指向语言内部使用的方法,它们会在特定的场景下自动执行。
Symbol值 | 介绍 | |||
---|---|---|---|---|
Symbol.hasInstance | 当其他对象使用 instanceof 运算符,判断是否为该对象的实例时,会调用这个方法 | |||
Symbol.isConcatSpreadable | 对象的 Symbol.isConcatSpreadable 属性等于的是一个布尔值,表示该对象用于 Array.prototype.concat()时,是否可以展开。 | |||
Symbol.species | 创建衍生对象时,会使用该属性 | |||
Symbol.match | 当执行 str.match(myObject) 时,如果该属性存在,会调用它,返回该方法的返回值 | |||
Symbol.replace | 当该对象被 str.replace(myObject)方法调用时,会返回该方法的返回值 | |||
Symbol.search | 当该对象被 str.search (myObject)方法调用时,会返回该方法的返回值 | |||
Symbol.split | 当该对象被 str.split(myObject)方法调用时,会返回该方法的返回值 | |||
Symbol.iterator | 对象进行 for...of 循环时,会调用 Symbol.iterator 方法,返回该对象的默认遍历器 | |||
Symbol.toPrimitive | 该对象被转为原始类型的值时,会调用这个方法,返回该对象对应的原始类型值 | |||
Symbol. toStringTag | 在该对象上面调用 toString 方法时,返回该方法的返回值 | |||
Symbol. unscopables | 该对象指定了使用 with 关键字时,哪些属性会被 with环境排除 |
十、迭代器
迭代器就是一种机制。它是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作。
(1)ES6 创造了一种新的遍历命令 for...of 循环,Iterator 接口主要供 for...of 消费
(for..in遍历保存键名,for..of遍历保存键值)
(2)原生具备 iterator 接口的数据(可用 for of 遍历)
- . Array
- Arguments
- Set
- Map
- String
- TypedArray
- NodeList
(3)工作原理
1. 创建一个指针对象,指向当前数据结构的起始位置
2. 第一次调用对象的 next 方法,指针自动指向数据结构的第一个成员
3. 接下来不断调用 next 方法,指针一直往后移动,直到指向最后一个成员
4.每调用 next 方法返回一个包含 value 和 done 属性的对象
// 声明一个数组
const xiyou = ['唐僧','孙悟空','猪八戒','沙僧'];
// 创建一个指针对象
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());
自定义遍历数据
//声明一个对象
const banji = {
name: "giao",
stus: [
'yahou',
'zmsn',
'huohua',
'nosmoking'
],
[Symbol.iterator]() {
//索引变量
let index = 0;
return {
next: () => {
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);
}
十一、生成器
生成器函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同,是一种特殊的函数。
function * gen(){
// console.log(111);
yield '一只没有耳朵';
// console.log(222);
yield '一只没有尾部';
// console.log(333);
yield '真奇怪';
// console.log(444);
}
let iterator = gen();
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
//遍历
// for(let v of gen()){
// console.log(v);
// }
说明:
- ** 的位置没有限制
- 生成器函数返回的结果是迭代器对象,调用迭代器对象的 next 方法可以得到 yield 语句后的值
- yield 相当于函数的暂停标记,也可以认为是函数的分隔符,每调用一次 next方法,执行一段代码
- next 方法可以传递实参,作为 yield 语句的返回值
// 生成器函数参数
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方法可以传入实参
console.log(iterator.next('BBB'));
console.log(iterator.next('CCC'));
console.log(iterator.next('DDD'));
十 二、Promise
Promise 是 ES6 引入的异步编程的新解决方案。语法上 Promise 是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果,解决回调地狱。
//实例化 Promise 对象
const p = new Promise(function(resolve, reject){
setTimeout(function(){
//
let data = '数据库中的用户数据';
resolve(data);
// let err = '数据读取失败';
// reject(err);
}, 1000);
});
//调用 promise 对象的 then 方法
p.then(function(value){
console.log(value);
}, function(reason){
console.error(reason);
})
Promise封装读取文件
//1. 引入 fs 模块
const fs = require('fs');
//2. 调用方法读取文件
// fs.readFile('./resources/为学.md', (err, data)=>{
// //如果失败, 则抛出错误
// if(err) throw err;
// //如果没有出错, 则输出内容
// console.log(data.toString());
// });
//3. 使用 Promise 封装
const p = new Promise(function(resolve, reject){
fs.readFile("./resources/为学.md", (err, data)=>{
//判断如果失败
if(err) reject(err);
//如果成功
resolve(data);
});
});
p.then(function(value){
console.log(value.toString());
}, function(reason){
console.log("读取失败!!");
});
Promise.prototype.then 方法
then方法的返回结果是 Promise 对象, 对象状态由回调函数的执行结果决定
//创建 promise 对象
const p = new Promise((resolve, reject)=>{
// 异步任务
setTimeout(()=>{
resolve('用户数据');
// reject('出错啦');
}, 1000)
});
// 调用 then 方法
const result = p.then(value => {
console.log(value);
//1. 非 promise 类型的属性, 状态为成功, 返回值为对象的成功的值
return 'iloveyou';
//2. promise 对象
return new Promise((resolve, reject)=>{
// resolve('ok');
reject('error');
});
//3. 抛错
// throw new Error('fuck!');
throw '出错啦!';
}, reason=>{
console.warn(reason);
});
链式调用
p.then(value=>{
}).then(value=>{
});
案例-读取多个文件
//引入 fs 模块
const fs = require("fs");
// 回调地狱
// fs.readFile('./resources/为学.md', (err, data1)=>{
// fs.readFile('./resources/插秧诗.md', (err, data2)=>{
// fs.readFile('./resources/观书有感.md', (err, data3)=>{
// let result = data1 + '\r\n' +data2 +'\r\n'+ data3;
// console.log(result);
// });
// });
// });
// Promise
const p = new Promise((resolve, reject) => {
fs.readFile("./resources/为学.md", (err, data) => {
resolve(data);
});
});
p.then(value => {
return new Promise((resolve, reject) => {
fs.readFile("./resources/七步诗.md", (err, data) => {
resolve([value, data]);
});
});
}).then(value => {
return new Promise((resolve, reject) => {
fs.readFile("./resources/游园不值.md", (err, data) => {
//压入
value.push(data);
resolve(value);
});
})
}).then(value => {
console.log(value.join('\r\n'));
});
Promise.prototype.catch 方法
catch方法指定的回调函数捕获promise抛出的错误
const p = new Promise((resolve, reject)=>{
setTimeout(()=>{
//设置 p 对象的状态为失败, 并设置失败的值
reject("怎么搞的!");
}, 1000)
});
// p.then(function(value){}, function(reason){
// console.error(reason);
// });
p.catch(function(reason){
console.warn(reason);
});
十三、Set
ES6 提供了新的数据结构 Set(集合)。它类似于数组,但成员的值都是唯一的,集合实现了 iterator 接口,所以可以使用『扩展运算符』和『for…of…』进行遍历,集合的属性和方法:
- size 返回集合的元素个数
- add 增加一个新元素,返回当前集合
- delete 删除元素,返回 boolean 值
- has 检测集合中是否包含某个元素,返回 boolean 值
- clear 清空集合,返回 undefined
//声明一个 set
let s = new Set();
let s2 = new Set(['1','2','3','4','2']);
// 元素个数
// console.log(s2.size);
// 添加新的元素
// s2.add('5');
// 删除元素
// s2.delete('4');
// 检测
// console.log(s2.has('6'));
// 清空
// s2.clear();
// console.log(s2);
for(let v of s2){
console.log(v);
}
当然,集合还可以数组去重、交集、并集、差集
let arr = [1,2,3,4,5,4,3,2,1];
//1. 数组去重
// let result = [...new Set(arr)];
// console.log(result);
//2. 交集
let arr2 = [4,5,6,5,6];
// let result = [...new Set(arr)].filter(item => new Set(arr2).has(item));
// console.log(result);
//3. 并集
// let union = [...new Set([...arr, ...arr2])];
// console.log(union);
//4. 差集
let diff = [...new Set(arr)].filter(item => !(new Set(arr2).has(item)));
console.log(diff);
十四、Map
ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合。但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。Map 也实现了iterator 接口,所以可以使用『扩展运算符』和『for…of…』进行遍历。Map 的属性和方法:
- size 返回 Map 的元素个数
- set 增加一个新元素,返回当前 Map
- get 返回键名对象的键值
- has 检测 Map 中是否包含某个元素,返回 boolean 值
- clear 清空集合,返回 undefined
// 声明 Map
let m = new Map();
// 添加元素
m.set('name','怪鸽');
m.set('say', function(){
console.log("我们遇到什么困难,都不要怕");
});
let key = {
hobby : '冬泳'
};
m.set(key, ['加油','奥力给','干就完了']);
// size
// console.log(m.size);
// 删除
// m.delete('name');
// 获取
// console.log(m.get('hobby'));
// console.log(m.get(key));
// 清空
// m.clear();
// 遍历
for(let v of m){
console.log(v);
}
十五、class 类
ES6 提供了更接近传统语言的写法,引入了 Class这个概念,作为对象的模板。通过 class 关键字,可以定义类。基本上,ES6 的 class 可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的 class 写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。
//手机
function Phone(brand, price){
this.brand = brand;
this.price = price;
}
//添加方法
Phone.prototype.call = function(){
console.log("我可以打电话!!");
}
//实例化对象
let Huawei = new Phone('华为', 5999);
Huawei.call();
console.log(Huawei);
//class
class Shouji{
//构造方法 名字不能修改
constructor(brand, price){
this.brand = brand;
this.price = price;
}
//方法必须使用该语法, 不能使用 ES5 的对象完整形式
call(){
console.log("我可以打电话!!");
}
}
let onePlus = new Shouji("1+", 1999);
console.log(onePlus);
静态成员
1.实例对象没有构造函数对象的属性和方法,两者之间是不通的,和构造函数的原型对象是相通的
2.函数对象里的属性是属于函数对象的,并不属于实例对象,对于这样的属性称之为静态成员
// 构造函数对象
function Phone(){
}
// 静态成员
Phone.name = '手机';
Phone.change = function(){
console.log("我可以改变世界");
}
// 原型对象属性
Phone.prototype.size = '5.5inch';
// 实例对象
let nokia = new Phone();
console.log(nokia.name); // undefinded
// nokia.change(); // not a function
console.log(nokia.size); // 5.5inch
class
// 类
class Phone{
//静态属性
static name = '手机';
static change(){
console.log("我可以改变世界");
}
}
// 实例对象
let nokia = new Phone();
console.log(nokia.name); // undefined
console.log(Phone.name); // 手机
static标注的属性和方法属于类,不属于实例对象
类继承
// ES5
function Phone(brand, price){
this.brand = brand;
this.price = price;
}
Phone.prototype.call = function(){
console.log("我可以打电话");
}
// 智能手机
function SmartPhone(brand, price, color, size){
// 继承父类
Phone.call(this, brand, price);
this.color = color;
this.size = size;
}
//设置子级构造函数的原型
SmartPhone.prototype = new Phone;
SmartPhone.prototype.constructor = SmartPhone;
// 声明子类的方法
SmartPhone.prototype.photo = function(){
console.log("我可以拍照")
}
SmartPhone.prototype.playGame = function(){
console.log("我可以玩游戏");
}
const huawei = new SmartPhone('华为',2499,'黑色','5.5inch');
console.log(huawei);
class继承和方法重写
// ES6
class Phone{
// 构造方法
constructor(brand, price){
this.brand = brand;
this.price = price;
}
// 父类的成员属性
call(){
console.log("我可以打电话!!");
}
}
class SmartPhone extends Phone {
// 构造方法
constructor(brand, price, color, size){
super(brand, price);// 相当于Phone.call(this, brand, price)
this.color = color;
this.size = size;
}
photo(){
console.log("拍照");
}
playGame(){
console.log("玩游戏");
}
// 方法的重写
call(){
console.log('我可以进行视频通话');
}
}
const xiaomi = new SmartPhone('小米',1999,'黑色','4.7inch');
// console.log(xiaomi);
xiaomi.call();
xiaomi.photo();
xiaomi.playGame();
get和set
get通常对对象的动态属性进行封装,set可以进行控制和判断是否合法
// get 和 set
class Phone{
get price(){
console.log("价格属性被读取了");
return 'iloveyou';
}
set price(newVal){
console.log('价格属性被修改了');
}
}
//实例化对象
let s = new Phone();
// console.log(s.price);
s.price = 'free';
十六、数值扩展
- Number.EPSILON 是 JavaScript 表示的最小精度
//EPSILON 属性的值接近于 2.2204460492503130808472633361816E-16
function equal(a, b){
if(Math.abs(a-b) < Number.EPSILON){
return true;
}else{
return false;
}
}
// console.log(0.1 + 0.2 === 0.3);
console.log(equal(0.1 + 0.2, 0.3))
- 二进制和八进制
ES6 提供了二进制和八进制数值的新的写法,分别用前缀 0b 和 0o 表示。
let b = 0b1010;
let o = 0o777;
let d = 100;
let x = 0xff;
console.log(x);
- Number.isFinite 检测一个数值是否为有限数
- Number.isNaN 检测一个数值是否为 NaN
- Number.parseInt Number.parseFloat字符串转整数
- Number.isInteger 判断一个数是否为整数
- Math.trunc 将数字的小数部分抹掉
- Math.sign 判断一个数到底为正数 负数 还是零
正数返回1,负数返回-1,零返回0
十七、对象扩展
- Object.is 比较两个值是否严格相等,与『===』行为基本一致(+0 与 NaN)
console.log(Object.is(120, 120));// true
console.log(Object.is(NaN, NaN));// true
console.log(NaN === NaN);// false
- Object.assign 对象的合并,将源对象的所有可枚举属性,复制到目标对象
const config1 = {
host: 'localhost',
port: 3306,
name: 'root',
pass: 'root',
test: 'test'
};
const config2 = {
host: 'http://baidu.com',
port: 33060,
name: 'baidu.com',
pass: 'iloveyou',
test2: 'test2'
}
console.log(Object.assign(config1, config2)); // config2覆盖config1
- Object.setPrototypeOf 设置原型对象 Object.getPrototypeof 获取原型对象
const school = {
name: '蓝翔'
}
const cities = {
xiaoqu: ['北京','山东','深圳']
}
Object.setPrototypeOf(school, cities); // 将cities设成school的原型对象
console.log(Object.getPrototypeOf(school)); // 获取school的原型对象
十八、模块化
模块化是指将一个大的程序文件,拆分成许多小的文件,然后将小文件组合起来。
好处:
防止命名冲突、代码复用、高维护性
语法:
模块功能主要由两个命令构成:export 和 import。
export 命令用于规定模块的对外接口, import 命令用于输入其他模块提供的功能.
有什么问题欢迎大家在评论区讨论o~♥
- 作者:风时摩羯
- 出处/源自:风时摩羯的《普歌-飞灵团队-ES6汇总》
- 本文版权归作者和共有,欢迎转载,且在文章页面明显位置给出原文链接,未经作者同意必须保留此段声明,否则保留追究法律责任的权利。