let
/*let 声明的变量有几个特点:1. 不允许重复声明*///2. 块儿级作用域 全局, 函数, eval// if else while for 里边声明在外部无法访问{var boy = '罗志祥'; //{}没有块级作用于,var的变量会往全局的window中添加,所有外部能访问let girl = '周扬青'; //let只能在代码块中有效}console.log(girl); //罗志祥console.log(girl); //报错//3. 不存在变量提升console.log(song);var song = '时间管理'; //可以 输出undefinedlet song = '恋爱达人'; //报错//4. 不影响作用域链{let school = '尚硅谷';function fn(){console.log(school); //虽然是块级作用于 但不影响作用域链,这里依然可以输出}fn();}
const
//1. 一定要赋初始值const A;//2. 一般常量使用大写(潜规则)const a = 100;//3. 常量的值不能修改SCHOOL = 'ATGUIGU';//4. 块儿级作用域{const PLAYER = 'UZI';}console.log(PLAYER);//5. 对于数组和对象的元素修改, 不算做对常量的修改, 不会报错// 常量指向的地址没有改变 所有不会报错const TEAM = ['UZI','MXLG','Ming','Letme'];TEAM.push('Meiko');
箭头函数
//1. this 是静态的. this 始终指向函数声明时所在作用域下的 this 的值//而非箭头函数则指向调用它的对象所在作用域function getName(){console.log(this.name);}let getName2 = () => {console.log(this.name);}//设置 window 对象的 name 属性window.name = '尚硅谷';const school = {name: "ATGUIGU"}//直接调用getName(); //尚硅谷getName2(); //尚硅谷 getName2当前所在作用域是window (this 始终指向函数声明时所在作用域下的 this 的值)//call 方法调用getName.call(school); //ATGUIGU(指向调用它的作用域)getName2.call(school); //尚硅谷(始终指向声明时)//2. 不能作为构造实例化对象let Person = (name, age) => {this.name = name;this.age = age;}//let me = new Person('xiao',30); //报错//3. 不能使用 arguments 变量let fn = () => {console.log(arguments); //arguments is not defined}fn(1,2,3);
箭头函数实践
this指向 :
- 箭头函数适合与 this 无关的回调. 定时器, 数组的方法回调
- 箭头函数不适合与 this 有关的回调. 事件回调, 对象的方法
箭头函数的注意点:
- 如果形参只有一个,则小括号可以省略
- 函数体如果只有一条语句,则花括号可以省略,函数的返回值为该条语句的 执行结果
- 箭头函数 this 指向声明时所在作用域下 this 的值,如果this为undefined 则往上级找
- 箭头函数不能作为构造函数实例化
不能使用 arguments
<body><div id="ad"></div><script>//需求-1 点击 div 2s 后颜色变成『粉色』//获取元素let ad = document.getElementById('ad');//绑定事件ad.addEventListener("click", function(){//不使用箭头函数时 保存 this 的值// let _this = this;//定时器setTimeout(() => {//修改背景颜色 this// console.log(this);//不使用箭头函数->window// _this.style.background = 'pink';this.style.background = 'pink';}, 2000);});//需求-2 从数组中返回偶数的元素const arr = [1,6,9,10,100,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);// 箭头函数适合与 this 无关的回调. 定时器, 数组的方法回调// 箭头函数不适合与 this 有关的回调. 事件回调, 对象的方法{name:'123',show:function(){console.log(this.name) //此时this指向该对象},show:()=>{console.log(this.name) //因为{}不能产生作用域, 此时this指向window}}</script></body>
函数参数默认值
//ES6 允许给函数参数赋值初始值
//1. 形参初始值 具有默认值的参数, 一般位置要靠后(潜规则)
// function add(a,b,c=10) {
// 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: 'atguigu.com',
username: 'root',
password: 'root',
port: 3306
})
rest参数(剩余参数) ES6+ES9
ES6
- 用于获取函数的实参,用来代替 arguments
- 作为参数数组 可用数组方法filter some every map ```javascript // 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); // 1 console.log(b); // 2 console.log(args); // [3,4,5,6] } fn(1,2,3,4,5,6);
<a name="LK9PM"></a>
## ES9
为对象提供了像数组一样的 rest 参数
```javascript
//rest 参数
function connect({host, port, ...user}){
console.log(host); // 127.0.0.1
console.log(port); // 3306
console.log(user); //{username: "root", password: "root", type: "master"}
}
connect({
host: '127.0.0.1',
port: 3306,
username: 'root',
password: 'root',
type: 'master'
});
spread 扩展运算符(…) ES6+ES9
spread 译 = 扩展
扩展运算符(spread)也是三个点(…)。它好比 rest 参数的逆运算,将个数组转为用逗号分隔的参数序列,对数组进行解包。
ES6 - 数组合并/克隆
- 数组合并
- 数组克隆
- 伪数组转真数组 ```javascript //1. 数组的合并 情圣 误杀 唐探 const kuaizi = [‘王太利’,’肖央’]; const fenghuang = [‘曾毅’,’玲花’]; // const zuixuanxiaopingguo = kuaizi.concat(fenghuang); const zuixuanxiaopingguo = […kuaizi, …fenghuang]; console.log(zuixuanxiaopingguo);
//2. 数组的克隆(浅拷贝) const sanzhihua = [‘E’,’G’,’M’]; const sanyecao = […sanzhihua];// [‘E’,’G’,’M’] console.log(sanyecao);
//3. 将伪数组转为真正的数组 const divs = document.querySelectorAll(‘div’); const divArr = […divs]; console.log(divArr);//
<a name="ya4r8"></a>
## ES9 - 对象合并/克隆
1. 对象合并
1. 对象克隆
```javascript
//对象合并
const nameOne = {
q: 'ivy'
}
const nameTwo = {
w: 'Amanda'
}
const nameAll = {...nameOne, ...nameTwo};
//{q: "ivy", w: "Amanda"}
console.log(nameAll)
//对象克隆
const nameThree = {
q: 'ivy'
}
console.log({...nameThree})
symbol
ES6 引入了一种新的原始数据类型 Symbol,表示独一无二的值。它是 JavaScript 语言的第七种数据类型,是一种类似于字符串的数据类型。
Symbol 特点
- Symbol 的值是唯一的,用来解决命名冲突的问题
- Symbol 值不能与其他数据进行运算
- Symbol 定义 的 对象属 性 不能 使 用 for…in 循 环遍 历 ,但 是可 以 使 用 Reflect.ownKeys 来获取对象的所有键名
基本用法
```javascript //创建Symbol let s = Symbol(); console.log(s, typeof s); //Symbol() “symbol” let s2 = Symbol(‘尚硅谷’); let s3 = Symbol(‘尚硅谷’); console.log(s2===s3); //false //Symbol.for 创建 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;
//七种数据类型 // USONB you are so niubility // u undefined // s string symbol // o object // n null number // b boolean
<a name="bKr6f"></a>
## 向对象中添加方法
```javascript
//1.向对象中添加方法
//方式一
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("我可以快速下降!!");
}
console.log(game);
//方式二
let youxi = {
name:"狼人杀",
[Symbol('say')]: function(){
console.log("我可以发言")
},
[Symbol('zibao')]: function(){
console.log('我可以自爆');
}
}
console.log(youxi)
内置属性
这里只介绍几种用法,详细参考阮一峰
//1.hasInstance当其他对象使用 instanceof 运算符,判断是否为该对
象的实例时,会调用这个方法
class Person{
static [Symbol.hasInstance](param){
console.log(param);
console.log("我被用来检测类型了");
return false;
}
}
let o = {};
console.log(o instanceof Person);
//2.对象的 Symbol.isConcatSpreadable 属性等于的是一个
布尔值,表示该对象用于 Array.prototype.concat()时,
是否可以展开。
const arr = [1,2,3];
const arr2 = [4,5,6];
arr2[Symbol.isConcatSpreadable] = false;
console.log(arr.concat(arr2));
迭代器(遍历)iterator
遍历器(Iterator)就是一种机制。它是一种接口,为各种不同的数据结构提 供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作。
基本原理和适用对象
- ES6 创造了一种新的遍历命令 for…of 循环,Iterator 接口主要供 for…of 消费
- 原生具备 iterator 接口的数据(可用 for of 遍历)
- Array
- Arguments
- Set
- Map
- String
- TypedArray
- NodeList
- 工作原理
- 创建一个指针对象,指向当前数据结构的起始位置
- 第一次调用对象的 next 方法,指针自动指向数据结构的第一个成员
- 接下来不断调用 next 方法,指针一直往后移动,直到指向最后一个成员
- 每调用 next 方法返回一个包含 value 和 done 属性的对象
迭代器自定义遍历对象
//声明一个对象
const banji = {
name: "终极一班",
stus: [
'xiaoming',
'xiaoning',
'xiaotian',
'knight'
],
[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);
}
entrise()
生成器 function * fnName()
生成器函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同
基本原理和使用
代码说明:
- 的位置没有限制
- 生成器函数返回的结果是迭代器对象,调用迭代器对象的 next 方法可以得到 yield 语句后的值
- yield 相当于函数的暂停标记,也可以认为是函数的分隔符,每调用一次 next 方法,执行一段代码
- next 方法可以传递实参,作为 yield 语句的返回值
```javascript //生成器其实就是一个特殊的函数 //异步编程 纯回调函数 node fs ajax mongodb //函数代码的分隔符 function * gen(){ // console.log(111); yield ‘一只没有耳朵’; // console.log(222); yield ‘一只没有尾部’; // console.log(333); yield ‘真奇怪’; // console.log(444); }
let iterator = gen(); console.log(iterator.next()); //{value: “一只没有耳朵”, done: false} console.log(iterator.next()); console.log(iterator.next()); console.log(iterator.next());//{value: undefined, done: true}
//遍历 for(let v of gen()){ console.log(v); }
<a name="xqi0j"></a>
## 参数
next 方法可以传递实参,作为 yield 语句的返回值<br />
<a name="XxjIt"></a>
## 案例一 : 解决回调地狱
```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();
案例二 : 异步获取数据(模拟获取 -> 用户数据 -> 订单数据 -> 商品数据)
利用next 方法可以传递实参,作为 yield 语句的返回值, 将数据传递给下一个next实现模拟过程
//模拟获取 用户数据 订单数据 商品数据
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();
集合Set()
ES6 提供了新的数据结构 Set(集合)。它类似于数组,但成员的值都是唯 一的,集合实现了 iterator 接口,所以可以使用『扩展运算符』和『for…of…』进 行遍历
集合的属性和方法:
- size 返回集合的元素个数
- add 增加一个新元素,返回当前集合
- delete 删除元素,返回 boolean 值
- has 检测集合中是否包含某个元素,返回 boolean 值 5) clear 清空集合,返回 undefined
基本使用
```javascript //声明一个 set let s = new Set(); let s2 = new Set([‘大事儿’,’小事儿’,’好事儿’,’坏事儿’,’小事儿’]);
//元素个数 // console.log(s2.size); //添加新的元素 // s2.add(‘喜事儿’); //删除元素 // s2.delete(‘坏事儿’); //检测 // console.log(s2.has(‘糟心事’)); //清空 // s2.clear(); // console.log(s2);
// for(let v of s2){ console.log(v); }
<a name="wcOYP"></a>
## 案例 去重/交集/并集/差集
```javascript
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
```javascript //声明 Map let m = new Map();
//添加元素 m.set(‘name’,’尚硅谷’); m.set(‘change’, function(){ console.log(“我们可以改变你!!”); }); let key = { school : ‘ATGUIGU’ }; m.set(key, [‘北京’,’上海’,’深圳’]);
//size // console.log(m.size);
//删除 // m.delete(‘name’);
//获取 // console.log(m.get(‘change’)); // console.log(m.get(key));
//清空 // m.clear();
//遍历 for(let v of m){ console.log(v); }

<a name="KGfoy"></a>
# 对象拓展方法
<a name="bGj2P"></a>
## Object.is判断两个值是否完全相等
```javascript
console.log(Object.is(120, 120));// true
console.log(Object.is(-0, 0));// false
console.log(Object.is(NaN, NaN));// true
console.log(NaN === NaN);// false
Object.assign 对象的合并
const config1 = {
name: 'Dan',
age: '20',
hobby:'sing'
};
const config2 = {
name: 'Amanda',
age: '25'
}
//{name: "Amanda", age: "25", hobby: "sing"}
console.log(Object.assign(config1, config2));
ES8 - Object.keys和Object.values 和 Object.entries
- Object.keys()方法会返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和使用 for…in 循环遍历该对象时返回的顺序一致

- Object.values()方法返回一个给定对象自身的所有可枚举属性值的数组,值的顺序与使用for…in循环的顺序相同 ( 区别在于 for-in 循环枚举原型链中的属性 )。

- Object.entries()方法返回一个给定对象自身可遍历属性 [key,value] 的数组
ES8 - Object.getOwnPropertyDescriptors
该方法返回指定对象所有自身属性的描述对象
const school = {
name:"尚硅谷",
cities:['北京','上海','深圳'],
xueke: ['前端','Java','大数据','运维']
};
//对象属性的描述对象
console.log(Object.getOwnPropertyDescriptors(school));
//上边方法返回如下创建对象时设置属性特性,用于深拷贝
const obj = Object.create(null, {
name: {
//设置值
value: '尚硅谷',
//属性特性
writable: true,
configurable: true,
enumerable: true
}
});
console.log(obj)
Object.setPrototypeOf 设置原型对象 Object.getPrototypeof
const school = {
name: '尚硅谷'
}
const cities = {
xiaoqu: ['北京','上海','深圳']
}
Object.setPrototypeOf(school, cities);
console.log(Object.getPrototypeOf(school));
console.log(school);
数值扩展
二进制和八进制
ES6 提供了二进制和八进制数值的新的写法,分别用前缀 0b 和 0o 表示。
//1. 二进制和八进制
let b = 0b1010; //2 - 10
let o = 0o777; //8 - 511
let x = 0xff; //16 - 255
Number.isFinite() 与 Number.isNaN()
Number.isFinite() 用来检查一个数值是否为有限的
Number.isNaN() 用来检查一个值是否为 NaN
//isFinite
console.log(Number.isFinite(100)); //true
console.log(Number.isFinite(100/0)); //false
console.log(Number.isFinite(Infinity)); //false Infinity无穷数
//NaN
console.log(Number.isNaN(123)); //false
console.log(Number.isNaN(1/'我')); //true
Number.parseInt() 与 Number.parseFloat()
ES6 将全局方法 parseInt 和 parseFloat,移植到 Number 对象上面,使用不变。
console.log(Number.parseInt('5211314love')); //5211314
console.log(Number.parseFloat('3.1415926神奇')); //3.1415926
Math.trunc
用于去除一个数的小数部分,返回整数部分。
console.log(Math.trunc(3.5)); //3
Number.isInteger()
用来判断一个数值是否为整数
console.log(Number.isInteger(5)); //true
console.log(Number.isInteger(2.5)); //false
Number.sing()
用来判断一个数到底是 正数 负数 还是零
console.log(Math.sign(100)); //1
console.log(Math.sign(0)); //0
console.log(Math.sign(-20000)); //-1
Number.EPSILON
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); //false
console.log(equal(0.1 + 0.2, 0.3)); //true


