2.1. let关键字
let关键字用来声明变量,使用 let声明的变量有几个特点:
-
不允许重复声明
-
块儿级作用域
-
不存在变量提升
-
不影响作用域链
应用场景:以后声明变量使用let就对了
案例:点击切换颜色
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style type="text/css">
.container {
width: 500px;
margin: 0 auto;
}
.box {
display: flex;
}
.item {
width: 100px;
height: 45px;
border: 1px solid deepskyblue;
margin-right: 10px;
}
</style>
</head>
<body>
<div class="container">
<h2>点击切换颜色</h2>
<div class="box">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
</div>
<script type="text/javascript">
// 获取div元素对象
let items = document.getElementsByClassName('item')
// 遍历并绑定点击事件
for(let i = 0; i < items.length; i++) {
items[i].onclick = function() {
// 修改当前被点击方块的背景颜色
// this.style.backgroundColor = 'pink'
items[i].style.backgroundColor = 'pink'
}
}
console.log(window.i)
</script>
</body>
</html>
2.2. const关键字
const 关键字用来声明常量, const声明有以下特点
-
声明必须赋初始值
-
标识符一般为大写
-
不允许重复声明
-
值不允许修改
-
块级作用域
注意: 对象属性修改和数组元素变化不会出发 const错误
应用场景:声明对象类型使用const,非对象类型声明选择 let
2.3. 变量的解构赋值
ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构 赋值。
//数组的解构赋值
const arr = ['张学友', '刘德华', '黎明', '郭富城'];
let [zhang, liu, li, guo] = arr;
//对象的解构赋值
const lin = {
name: '林志颖',
tags: ['车手', '歌手', '小旋风', '演员']
};
let {
name,
tags
} = lin;
//复杂解构
let wangfei = {
name: '王菲',
age: 18,
songs: ['红豆', '流年', '暧昧', '传奇'],
history: [{
name: '窦唯'
}, {
name: '李亚鹏'
}, {
name: '谢霆锋'
}]
};
let {
songs: [one, two, three],
history: [first, second, third]
} = wangfei;
注意:频繁使用对象方法、数组元素,就可以使用解构赋值形式
2.4. 模板字符串
模板字符串(template string)是增强版的字符串 用 反引号(`)标识 ,特点
- 字符串中可以出现换行符
// 定义字符串
let str = `<ul>
<li>沈腾</li>
<li>玛丽</li>
<li>魏翔</li>
<li>艾伦</li>
</ul>`;
// 变量拼接
let star = '王宁';
let result = `${
star}在前几年离开了开心麻花`;
注意:当遇到字符串与变量拼接的情况使用模板字符串
2) 可以使用 ${xxx} 形式输出变量
2.5. 简化对象写法
ES6 允许在大括号里面,直接写入变量和函数,作为对象的属性和方法。这样的书写更加简洁。
let name = 'zep';
let slogon = '永远追求行业更高标准';
let improve = function() {
console.log('可以提高你的技能');
}
//属性和方法简写
let atguigu = {
name,
slogon,
improve,
change() {
console.log('可以改变你')
}
};
注意:对象简写形式简化了代码,所以以后用简写就对了
2.6. 箭头函数
ES6 允许使用 「 箭头 」 (=>)定义函数 。
/** * 1. 通用写法 */
let fn = (arg1, arg2, arg3) => {
return arg1 + arg2 + arg3;
}
箭头函数的注意点
:
-
如果形参只有一个,则小括号可以省略
-
函数体如果只有一条语句,则花括号可以省略,函数的返回值为该条语句的执行结果
-
箭头函数 this指向声明时所在作用域下 this 的值
-
箭头函数不能作为构造函数实例化
-
不能使用 arguments
/** * 2. 省略小括号的情况 */
let fn2 = num => {
return num * 10;
};
/** * 3. 省略花括号的情况 */
let fn3 = score => score * 20;
/** * 4. this指向声明时所在作用域中 this 的值 */
let fn4 = () => {
console.log(this);
}
let school = {
name: '尚硅谷',
getName() {
let fn5 = () => {
console.log(this);
}
fn5();
}
};
注意:箭头函数不会更改this指向,用来指定回调函数会非常合适
案例1:点击div 2s 后颜色变成 粉色
案例2:从数组中返回偶数的元素
注意:
箭头函数适合与this无关的回调。定时器,数组的方法回调
箭头函数不适合与this有关的回调。事件回调,对象的方法
2.6 函数参数默认值
- 形参初始值, 具有默认值的参数,一般位置要靠后放(潜规则)
- 与解构赋值结合
2.7. rest参数
ES6引入 rest参数,用于获取 函数的实参,用来代替 arguments
/** * 作用与 arguments 类似 */
function add(...args) {
console.log(args);
}
add(1, 2, 3, 4, 5);
/** * rest 参数必须是最后一个形参 */
function minus(a, b, ...args) {
console.log(a, b, args);
}
minus(100, 1, 2, 3, 4, 5, 19);
注意:
rest参数非常适合不定个数参数函数的场景
2.8. spread扩展运算符
扩展运算符(spread)也是三个点 (…)。它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列,对数组进行解包。
/** * 展开数组 */
let tfboys = ['德玛西亚之力', '德玛西亚之翼', '德玛西亚皇子'];
function fn() {
console.log(arguments);
}
fn(...tfboys)
/** * 展开对象 */
let skillOne = {
q: '致命打击',
};
let skillTwo = {
w: '勇气'
};
let skillThree = {
e: '审判'
};
let skillFour = {
r: '德玛西亚正义'
};
let gailun = {
...skillOne,
...skillTwo,
...skillThree,
...skillFour
};
- 数组的合并
- 数组的克隆
- 将伪数组转为真正的数组
2.9. Symbol
2.9.1. Symbol基本使用
ES6 引入了一种新的原始数据类型 Symbol,表示独一无二的值。它是JavaScript 语言的第七种数据类型,是一种类似于字符串的数据类型。
Symbol特点:
-
Symbol的值是唯一的,用来解决命名冲突的问题
-
Symbol值不能与其他数据进行运算
-
Symbol定义的对象属性不能使用 for…in循环遍历,但是可以使用Reflect.ownKeys来获取对象的所有键名
//创建 Symbol
let s1 = Symbol();
console.log(s1, typeof s1);
//添加标识的 Symbol
let s2 = Symbol('尚硅谷');
let s2_2 = Symbol('尚硅谷');
console.log(s2 === s2_2);
//使用 Symbol for 定义
let s3 = Symbol.for('尚硅谷');
let s3_2 = Symbol.for('尚硅谷');
console.log(s3 === s3_2);
-
注意:
- 遇到唯一性的场景时要想到 Symbol
总结:js数据类型如下(7种)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<script type="text/javascript">
// 向对象中添加方法 up down
let game = {
up: function() {
console.log('game对象本来存在的up方法')
}
}
// 声明一个对象
let methods = {
up: Symbol(),
down: Symbol()
}
game[methods.up] = function() {
console.log('我可以改变形状')
}
game[methods.down] = function() {
console.log('我可以快速下降')
}
console.log(game)
console.log('---------')
let youxi = {
name: '狼人杀',
[Symbol('say')]: function() {
console.log('我可以发言')
},
[Symbol('zibao')]: function() {
console.log('我可以自爆')
}
}
console.log(youxi)
</script>
</body>
</html>
2.9.2. Symbol内置值
除了定义自己使用的Symbol 值以外, ES6 还提供了 11个内置的 Symbol值,指向语言内部使用的方法。
可以称这些方法为魔术方法,因为它们会在特定的场景下自动执行。
2.10. 迭代器
遍历器(Iterator)就是一种机制。它是一种接口,为各种不同的数据结构提
供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作 。
- ES6创造了一种新的遍历命令 for…of循环, Iterator接口主要供 for…of消费
- 原生具备 iterator接口的数据 (可用 for of遍历 )
a) Array
b) Arguments
c) Set
d) Map
e) String
f) TypedArray
g) NodeList - 工作原理
a) 创建一个指针对象,指向当前数据结构的起始位置
b) 第一次调用对象的 next方法,指针自动指向数据结构的第一个成员
c) 接下来不断调用 next方法,指针一直往后移动,直到指向最后一个成员
d) 每调用 next方法返回一个包含 value和 done属性的对象
注:需要自定义遍历数据的时候,要想到迭代器
。
2.11. 生成器
生成器函数是 ES6提供的一种异步编程解决方案,语法行为与传统函数完全不同
function * gen(){
yield '一只没有耳朵';
yield '一只没有尾巴';
return '真奇怪';
}
let iterator = gen();
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
代码说明:
*
的位置没有限制- 生成器函数返回的结果是迭代器对象,
调用迭代器对象的 next方法可以得到yield语句后的值
- yield相当于函数的
暂停标记
,也可以认为是函数的分隔符,
每调用一次 next方法,执行一段代码
- next方法可以传递实参,作为 yield语句的返回值
案例1:// 1s 后控制台输出 111
// 2s 后控制台输出 222
// 3s 后控制台输出 333
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<script type="text/javascript">
// 异步编程: 文件操作,网络操作之(ajax, request) 数据库操作
// 1s 后控制台输出 111
// 2s 后控制台输出 222
// 3s 后控制台输出 333
// 回调地狱
/* setTimeout(() => {
console.log(111)
setTimeout(() => {
console.log(222)
setTimeout(() => {
console.log(333)
}, 3000)
}, 2000)
}, 1000) */
function one() {
setTimeout(() => {
console.log(111)
iterator.next()
}, 1000)
}
function two() {
setTimeout(() => {
console.log(222)
iterator.next()
}, 2000)
}
function three() {
setTimeout(() => {
console.log(333)
iterator.next()
}, 3000)
}
function * gen() {
yield one()
yield two()
yield three()
}
// 调用生成器函数
let iterator = gen()
iterator.next()
</script>
</body>
</html>
案例2:模拟按如下顺序获取: 用户数据 订单数据 商品数据
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<script type="text/javascript">
// 模拟获取 用户数据 订单数据 商品数据
function getUsers() {
setTimeout(() => {
let data = '用户数据'
// 调用next 方法,并且将数据传入
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()
</script>
</body>
</html>
2.12. Promise
Promise是 ES6引入的异步编程的 新解决方案 。语法上 Promise是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果。
- Promise构造函数 : Promise (excutor) {}
- Promise.prototype.then方法
promise.then()的返回值:
- 没有返回值
- 返回值为非Promise对象:
- 返回值为一个Promise对象:
- 返回值为抛出错误:
案例:读取多个文件
- Promise.prototype.catch方法
// 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/为学.mds', (err, data) => {
// 如果失败,则抛出错误
if (err) {
return reject(err)
}
// 如果成功
resolve(data)
})
})
p.then(function(value) {
console.log(value.toString())
}, function(error) {
console.log('读取失败~~~', error)
})
2.13. Set
ES6 提供了新的数据结构 Set(集合 。它类似于数组,但成员的值都是唯一的 ,集合实现了 iterator接口,所以可以使用『扩展运算符』和『 for…of…』进行遍历,集合的属性和方法:
- size 返回集合的元素个数
- add 增加一个新元素,返回当前集合
- delete 删除元素,返回 boolean 值
- has 检测集合中是否包含某个元素,返回 boolean值
- clear 清空集合,返回 undefined
//创建一个空集合
let s = new Set();
//创建一个非空集合
let s1 = new Set([1,2,3,1,2,3]);
//集合属性与方法
//返回集合的元素个数
console.log(s1.size);
//添加新元素
console.log(s1.add(4));
//删除元素
console.log(s1.delete(1));
//检测是否存在某个值
console.log(s1.has(2));
//清空集合
console.log(s1.clear());
2.14. Map
ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合。 但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。 Map也实现了iterator接口,所以可以使用『扩展运算符』和『 for…of…』进行遍历。
Map的属性和方法:
- size 返回 Map的元素个数
- set 增加一个新元素,返回当前 Map
- get 返回键名对象的键值
- has 检测 Map中是否包含某个元素,返回 boolean值
- clear 清空集合,返回 undefined
//创建一个空 map
let m = new Map();
//创建一个非空 map
let m2 = new Map([
['name','尚硅谷'],
['slogon','不断提高行业标准']
]);
//属性和方法
//获取映射元素的个数
console.log(m2.size);
//添加映射值
console.log(m2.set('age', 6));
//获取映射值
console.log(m2.get('age'));
//检测是否有该映射
console.log(m2.has('age'));
//清除
console.log(m2.clear());
2.15. class 类
ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过 class关键字,可以定义类。基本上, ES6 的 class可以看作只是一个语法糖,它的绝大部分功能, ES5 都可以做到,新的 class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。
- 使用ES5语法来实现类
- 使用ES6写法
静态成员和实例成员:
function Phone(price) {
this.price = price
}
// 在构造函数本身上添加的属性为 静态属性,
// 只能由构造函数对象来调用它们
Phone.name = '手机'
Phone.change = function() {
console.log('我可以改变世界')
}
// prototype原型对象上的属性为实例属性
// 构造函数内部通过this添加的成员 price也是实例属性
//,只能由实例对象来调用它
Phone.prototype.size = '5.5英寸'
let nokia = new Phone(9999)
console.log(nokia.name) // undefined
console.log(Phone.name) // Phone
// nokia.change()
console.log(nokia.price) // 9999
console.log(Phone.price) // undefined
console.log(nokia.size) // 5.5英寸
console.log(Phone.size) // undefined
ES5 中实现类的继承:
ES6 中实现类的继承:
class Phone {
// 构造方法
constructor(brand, price) {
this.brand = brand
this.price = price
}
// 父类的成员属性
callyou() {
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('打游戏')
}
}
const xiaomi = new SmartPhone('小米', 999, '黑色', '4.7英寸')
console.log(xiaomi)
xiaomi.callyou()
xiaomi.photo()
xiaomi.playGame()
知识点:
- class声明类
- constructor定义构造函数初始化
- extends继承父类
- super调用父级构造方法
- static定义静态方法和属性
- 父类方法可以重写
//父类
class Phone {
//构造方法
constructor(brand, color, price) {
this.brand = brand;
this.color = color;
this.price = price;
}
//对象方法
call() {
console.log('我可以打电话!!!')
}
}
//子类
class SmartPhone extends Phone {
constructor(brand, color, price, screen, pixel) {
super(brand, color, price);
this.screen = screen;
this.pixel = pixel;
}
//子类方法
photo() {
console.log('我可以拍照!!');
}
playGame() {
console.log('我可以玩游戏!!');
}
//方法重写
call() {
console.log('我可以进行视频通话!!');
}
//静态方法
static run() {
console.log('我可以运行程序')
}
static connect() {
console.log('我可以建立连接')
}
}
//实例化对象
const Nokia = new Phone('诺基亚', '灰色', 230);
const iPhone6s = new SmartPhone('苹果', '白色', 6088, '4.7inch', '500w');
//调用子类方法
iPhone6s.playGame();
//调用重写方法
iPhone6s.call();
//调用静态方法
SmartPhone.run();
2.16. 数值扩展
- Number.EPSILON是Javascript表示的最小精度
EPSILON 属性的值接近于2.2204468492503138808472633361816E-16
因为浮点数计算是不精确的, 引入一个这么小的量的目的,在于为浮点数计算,设置一个误差范围。
Number.EPSILON可以用来设置“能够接受的误差范围”。比如,误差范围设为 2 的-50 次方(即Number.EPSILON * Math.pow(2, 2)),即如果两个浮点数的差小于这个值,我们就认为这两个浮点数相等。
2.16.1. 二进制和八进制
ES6 提供了二进制和八进制数值的新的写法,分别用前缀 0b和 0o表示。
2.16.2. Number.isFinite() 与 Number.isNaN()
Number.isFinite() 用来检查一个数值是否为有限的
Number.isNaN() 用来检查一个值是否为 NaN
2.16.3. Number.parseInt() 与 Number.parseFloat()
ES6 将全局方法 parseInt和 parseFloat,移植到 Number对象上面,使用不变。
2.16.4. Math.trunc
用于去除一个数的小数部分,返回整数部分。
2.16.5. Number.isInteger
Number.isInteger() 用来判断一个数值是否为整数
2.16.6. Math.sign
Math.sign 判断一个数字是正数负数还是0
2.17. 对象扩展
ES6新增了一些 Object对象的方法
-
Object.is 比较两个值是否严格相等,与『 ===』行为基本一致(+0 与 NaN)
-
Object.assign 对象的合并,将源对象的所有可枚举属性,复制到目标对象
-
__proto__
、 setPrototypeOf、 setPrototypeOf可以直接设置对象的原型
2.18. 模块化
模块化是指将一个大的程序文件,拆分成
许多小的文件,然后将小文件组合起来。
2.18.1. 模块化的好处
模块化的优势有以下几点:
- 防止命名冲突
- 代码复用
- 高维护性
2.18.2. 模块化规范 产品
ES6之前的模块化规范有
- CommonJS => NodeJS、 Browserify
- AMD => requireJS
- CMD => seaJS
2.18.3. ES6模块化语法
模块功能主要由两个命令构成:
export和 import。
- export命令用于规定模块的对外接口
- import命令用于输入其他模块提供的功能
- 分别暴露 export xxx
- 统一暴露 export {school, findJob}
- 默认暴露 export default:
2.18.4 ES6引入模块语法汇总
2.18.5. 浏览器使用模块化的方式:
2.18.6. babel
- 安装工具 babel-cli babel-preset-env browserify(webpack)
- npx babel ./js -d dist/js --presets=babel-preset-env
- 打包 npx browserify dist/js/app.js -o dist/bundle.js
- 使用babel-cli babel-preset-env 将ES6语法转成ES5语法,来解决低版本浏览器不识别ES6语法的问题
- 使用browserify(webpack)将转换好的ES5语法文件进行打包,生成浏览器可以运行的代码
2.18.7. ES6模块化引入npm 包