ECMAScript 相关介绍
ECMA : (European Computer Manufacturers Association) 欧洲计算机制造协会
ECMAScript : 是由ECMA国际通过 ECMA-262 标准化的脚本程序设计语言
学习ES6
变量
ES6新添加的两个定义变量的关键字 let const
let
// 声明变量
let a;
let b, c;
let e = 100;
let f = 123, g = 'yellowsea', h = [];
let特性
- 变量不能重复的声明
- 块级作用域 全局, 函数, eval
- 不存在变量提升
- 不影响作用域链
// let 特性
//1. 变量不能重复的声明
let star = 'yellowsea';
let star = 'test1'; //err 重复声明
//2. 块级作用域 全局, 函数, eval
// if else while for
{
let girl = 'newTest';
}
console.log(girl); // err : girl is not defined
//3. 不存在变量提升
console.log(song);
let song = 'test1'; // err: Cannot access 'song' before initialization
//4. 不影响作用域链
{
let school = 'test';
function test1() {
console.log(school);
}
test1(); // test
}
实例
const items = document.getElementsByClassName('item');
// 使用 var 定义变量时
for (var i = 0; i < items.length; i++) {
items[i].onclick = function() {
// 修改点击item 的颜色
// this.style.backgroundColor = 'pink'; // 可以修改
items[i].style.backgroundColor = 'pink'; // Cannot read properties of undefined (reading 'style')
}
}
console.log(window.i); // 3
/**
* 因为使用了var, var i 进行3次循环, i变成了3;
* var 是全局作用域的, 会将var i = 3 绑定到 window 上;
* 点击 item 时,执行 回调函数,回调函数中的items[i], i 是没有在函数中定义的,所以它会去window 上去找i
* 此时的window.i = 3 ; items[3]没有; 所以会报错
*/
// 使用 let 时 , 没有发生报错, 因为let 具有块级作用域。声明的i是 互不影响的
for (let i = 0; i < items.length; i++) {
items[i].onclick = function() {
// 修改点击item 的颜色
// this.style.backgroundColor = 'pink'; // 可以修改
items[i].style.backgroundColor = 'pink';
}
}
const
const 常量 : 值不能修改的量 叫常量
// 常量 : 值不能修改的量 叫常量
const NAME = 'yellowsea'; // 定义常量一般要大写
const 特性
//1. 声明常量 一定要赋值
const A; // 报错
//2. 一般定义常量使用大写 (潜规则)
const a = 100 ; // 可以不用也不会报错, 书写标准
//3. 常量的值不能修改
NAME = 'YELLOWSEA'; // 报错
//4. const 具有块级作用域
{
const PLAYER_NAME = 'UZI';
}
console.log(PLAYER_NAME); // 报错
//5. 对于数组和对象的元素修改, 不算做对常量的修改, 不会报错
const TEAM = ['UZI', 'MLXG', 'Ming','Letme'];
// TEAM.push('Meiko'); // 没有报错, 因为这个常量所指向的地址没有发生改变,所以不会报错
// TEAM = 100; // 报错 , 常量所指向的地址值发生了改变
const PERSON = {
Id: 123,
Name: 'yellowsea',
}
PERSON.Name = 'Hidie'; // 修改对象数据
console.log(PERSON); // {Id: 123, Name: 'Hidie'}
对象的简化写法
ES6 允许在大括号里面,直接写入变量和函数, 作为对象的属性方法 , 这样书写更加简洁
// 同名在定义对象中可以简化
let name = 'Yellowsea';
let change = function() {
console.log('change 方法');
}
const school = {
// name: name, 可以简化
// 同名可以简化
name,
change,
// 写在对象中额方法 简化
// improve: function() {}
improve() {
console.log('这是简化后的方法');
}
}
console.log(school);
school.improve();
模板字符串
`` ES6 引入新的声明字符串方法
//1 声明
let str = `这是一个字符串`;
console.log(str, typeof str);
//2. 内容中可以直接出现换行符
let str = `<ul>
<li>test1</li>
<li>test2</li>
<li>test3</li>
</ul>`
// 3. 变量拼接 ${}
let test = 'Yellowsea';
let out = `Name is ${test}`;
console.log(out);
解构赋值
ES6 允许按照一定模式从数组和对象中提取值, 对变量进行赋值, 称为解构赋值
// 数组的解构赋值
const F4 = ['001', '002', '003'];
let [a,b,c] = F4; // 解构
console.log(a);
console.log(b);
console.log(c);
//2. 对象的解构
const zhao = {
name: '赵本山',
age: '不详',
xiaopin: function () {
console.log('演小品');
}
};
// 对象单独解构 解构时 变量名必须相同
let {xiaopin} = zhao;
xiaopin();
//
let {name, age, xiaopin} = zhao;
console.log(name);
console.log(age);
console.log(xiaopin);
xiaopin(); // 演小品
箭头函数
ES6 允许使用 箭头 => 定义函数
// 声明函数
let fn = function () { // 普通定义函数
}
// 使用箭头函数
let Fn = (a, b) => {
return a + b;
}
Fn(1,2); // 3
箭头函数的特性
- 箭头函数没有自己的this, 使用时, this是它的上一级(this指向它的上一级)
- 不能作为构造函数实例化对象
- 不能使用 arguments 变量
- 箭头函数的简写
// 1. this 是静态的, this 始终指向函数声明时在作用域下的this的值
function getName() {
console.log(this.name);
}
let getName2 = () =>{
console.log(this.name);
}
// 设置window 对象的 name 属性
window.name = 'yellowsea';
const hidie = {
name: 'YELLOWSEA'
}
// 直接调用 , 全局,window下的name
// getName();
// getName2();
//call 方法调用
getName.call(hidie); // YELLOWSEA
getName2.call(hidie); // yellowsea , 因为this没有改变,指向的全局作用域的window
//2. 不能作为构造函数实例化对象
let Person = (name,age) => {
this.name = name;
this.age = age;
}
let me = new Person('hidie', 123);
console.log(me); // 报错 : TypeError: Person is not a constructor
//3. 不能使用 arguments 变量
let newTest = () => {
console.log(arguments);
}
newTest(1,2,3); // ReferenceError: arguments is not defined at newTest
// 4. 箭头函数的简写
// 1) 省略小括号, 当形参有且只有一个的时候
// let add = (n) => {
// return n + n;
// }
let add = n => {
return n + n;
}
console.log(add(9));
// 2) 省略花括号, 当代码体只有一条语句的时候,省略花括号,此时 return 也必须要省略
// 而且语句的执行结果就是函数的返回值
// let pow = n => {
// return n * n;
// }
let pow = n => n*n;
console.log(pow(9));
// 实例
// 需求-1 点击div 2s 后颜色变为pink
// 获取元素
const ad = document.getElementById('ad');
// 绑定事件
ad.addEventListener('click', function() {
setTimeout(() => {
// 箭头函数没有自己的this,会向外一层边找, 知道找到 window 下为止
// 或者可以这样理解箭头函数下的this , this永远都是定义函数下作用域的 this (谁调用this就是谁)
this.style.backgroundColor = 'pink';
},2000)
})
// 需求2 从数组中返回偶数的元素
const arr = [1,6,12,45,100];
const result = arr.filter(value => value % 2 === 0 );
console.log(result);
// 箭头函数适合于 this 无关的回调 , 定时器, 数组的方法回调
// 箭头函数不适合与 this 有关的回调 , DOM事件的回调, 对象的方法
{
name: 'Yellowsea';
// getName: function() {
// this.name; // this.name 指向的是 该作用域的name
// }
getName: () => {
this.name; // 此时的this.name 指向的是window 下的name
}
}
函数参数设置默认值
ES6 允许给函数参数赋初始值
//1. 形参初始值 具有默认值的参数, 一般位置靠后(潜规则)
function add (a,b,c=10) { // 给c 设置默认值, 如果没有设置默认值,则为 undefined ;
return a + b + c;
}
console.log(add(1,2,));
//2. 与解构赋值结合
function connect({host, username, password, port}) {
// let {host, username, password,port} = options;
console.log(host);
console.log(username, password);
console.log(port);
}
connect({
host: '',
username: 'root',
password: 'root',
port: 3306,
})
rest参数
ES6 引入 rest 参数, 用于获取函数的实参, 用来代替 arguments(用来获取函数在调用时的实参)
function data() {
console.log(arguments); //此时的arguments 是一个对象
}
data('test1','test2','test3');
// rest 参数
function data(...args) {
console.log(args); // rest参数 返回的是一个数组,可以使用数组中的一系列方法
// 例如使用 数组返回的 forEach方法
args.forEach(value => console.log(value));
}
data('test1','test2','test3');
// 注意 ,如果你的参数由多个, rest 参数必须要放到最后
function fn(a,b, ...args) {
console.log(a,b,args);
}
fn(1,2,3,4,1);
扩展运算符
… 扩展运算符 , 能够将 数组 转换为逗号分隔的 参数序列
const Arr = ['test1', 'test2', 'test3']; // => test1, test2, test3
function Test() {
console.log(arguments);
}
Test(...Arr); // 相当于 Test('test1','test2','test3'); // 扩展运算符
// 扩展运算符 和 rest 参数 相比
// 扩展运算符 用来 调用函数的 实参里 进行对 数组 | 对象的 解构
// rest 用在调用函数的形参里, 用于对参数设置默认值
扩展运算符的应用
// 1. 数组的合并
let strArr1 = ['1','2','3','4'];
let strArr2 = ['a','b','c','d','e'];
// 默认方法
const result = strArr1.concat(strArr2);
// 使用扩展运算符 ... 方法
const newArr = [...strArr1, ...strArr2];
console.log(newArr);
//2. 数组的克隆
const kelongArr = ['A','B','C','D'];
const kelongNewArr = [...kelongArr];
console.log(kelongNewArr);
// 3. 将伪数组转为真正的数组
const divs = document.querySelectorAll('div'); // divs : NodeList 类型
const div = [...divs]; // div Array 类型
console.log(div);
Symbol
ES6 引入了一种新的原始类型 Symbol , 表示独一无二的值, 是JS语言的第七种类型
Symbol特点
/**
* 1. Symbol的值是唯一的,用来解决命名冲突问题
* 2. Symbol值不能与其他类型进行运算
* 3. Symbol定义的对象属性不能使用for...in 循环遍历,但是可以使用 Reflect.ownKeys来获取对象的所有键名
* @type {symbol}
*/
// 创建Symbol
let s = Symbol();
console.log(s, typeof s);
let s2 = Symbol('Yellowsea');
let s3 = Symbol('Yellowsea');
console.log(s2 === s3); // false
// 使用 Symbol.for 创建
let s4 = Symbol.for('yellowsea');
let s5 = Symbol.for('yellowsea');
console.log(s4 === s5); // true
// 不能与其他数据进行运算
// let result1 = s + s2;
// Symbol 内置属性
// 1. Symbol.hasInstance 检测类型 与 instanceof 配合使用
class Person {
static [Symbol.hasInstance](param) { // 自己去控制类型的检测
console.log(param); // param 表示正在检测的数据类型
console.log('被用来检测类型了')
// return false;
// return true;
}
}
let o = {};
console.log(o instanceof Person); // false
//2. Symbol.isConcatSpreadable 给一个布尔值
// 表示该对象使用 concat()时,是否可以展开
const arr1 = [1,2,3];
const arr2 = [4,5,6];
arr2[Symbol.isConcatSpreadable] = false; // arr2 不允许被展开
console.log(arr1.concat(arr2)); // [1, 2, 3, Array(3)]
// Symbol 创建对象属性
// Symbol 给对象添加一个独一无二的值
let game = {
name: "game1",
up: function() {},
down(){
},
};
// 声明一个对象
let methods = {
up: Symbol(),
down: Symbol()
}
// 给game 中添加方法 (安全添加方法 )
game[methods.up] = function() {
console.log('这是up 方法')
}
game[methods.down] = function() {
console.log('这是down 方法')
}
console.log(game);
// 方法二
let youxi = {
name: '三国杀',
[Symbol('sha')]() {
console.log('杀')
},
[Symbol('shan')]() {
console.log('闪')
}
}
console.log(youxi);
迭代器
迭代器(iterator)是一种接口,任何数据只要有了 iterator 接口, 就可以完成遍历操作
ES6 创造了一种新的遍历命令 for..of 循环, iterator 接口主要供for…of 消费 (for…of 直接遍历出值, 而for…in遍历得到的是下标)
原生就局具备 iterator 接口的数据 (可以使用for…of 遍历)
例如 : Array Arguments Set Map String TypedArray NodeList
* 工作原理
* 1. 创建一个指针对象,指向当前数据结构的起始位置
* 2. 第一次调用对象的next方法, 指针自动指向数据结构的第一个成员
* 3. 接下来不断调用 next() 方法, 指针一直往后移动, 知道指向最后一个成员
* 4. 每调用next方法返回一个包含 value 和 done 属性对象
迭代器的作用 : 需要自定义遍历数据的时候,要想到迭代器
// 例子 声明数组
let lizi = ['yellowsea','世利', 'Hidie'];
console.log(lizi);
// 在它的原型上具有 Symbol(Symbol.iterator): ƒ values() 方法
// 所以可以使用 for...of 进行遍历直接获取值
for ( let v of lizi) {
console.log(v);
}
//分析原理
//1. 创建对象
let iterator = lizi[Symbol.iterator](); //Symbol.iterator 是一个方法
// 查看
console.log(iterator); // 身上具有next() 方法
//2. 调用 next() 方法
console.log(iterator.next()); // 指针自动指向 数据结构的下一个成员
console.log(iterator.next());
console.log(iterator.next()); // {value: 'Hidie', done: false}
console.log(iterator.next());
//每次返回都包含value | done 属性, {value: undefined, done: true}
// 迭代器运用
迭代器自定义遍历数据
// 声明一个对象
const obj = {
name: '001',
arr: [
'test1','test2','test3','test4'
],
// 实现能够循环遍历 (根据原理实现)
// 定义 iterator 接口
[Symbol.iterator]() {
// 控制对 arr 的数据获取
let index = 0; // 设置索引值
let _this = this;
// 返回一个指针对象
return {
// 指针对象中具有一个next() 方法
next() {
// 返回一个具有 value 和 done 的属性对象
// 控制下标,返回结果
if ( index < _this.arr.length ) {
//返回数据
const result = {value: _this.arr[index], done: false}
index++; // 下标自增
return result; // 返回结果
}else {
return {value: undefined, done: true} // 遍历完成
}
}
}
}
}
// 需求,使用for...of 遍历, 每次循环返回arr数组中的属性值
// 使用for...of 遍历
// for (let v of obj) {
// console.log(v); // Uncaught TypeError: obj is not iterable
// // obj 没有 iterator 接口类型
// }
// 完成自定义遍历 , 完全按照我们的意愿进行遍历, 这就是迭代器的作用
for (let v of obj) console.log(v);
// 'test1','test2','test3','test4'
生成器
生成器函数 Es6 提供的一种异步编程的解决方案
// 生成器, 其实就是一个特殊的函数
// 异步编程 纯回调函数
// 定义函数
function * gen() { // 使用 function * 函数名 的语法定义生成器
// console.log('Hello generator');
// 里面可以定义 yield 语句
/* yield 算是函数代码分隔符 */
// console.log(111);
yield 'test1';
// console.log(222);
yield 'test2';
// console.log(333);
yield 'test3';
// console.log(444);
}
// 执行
let iterator = gen();
console.log(iterator); //输出的其实是一个 迭代器对象,原型中具有一个next() 方法
//运行
// iterator.next(); // Hello generator
// iterator.next();
// iterator.next();
// iterator.next();
// iterator.next();
// 循环输入
for (let v of gen()) {
console.log(v); // test1 test2 test3
// 所以循环遍历生成器, 输出(执行)的是 yield 语句的代码块
}
生成器函数参数
function * gen(args) {
console.log(args); // 可以进行传参
let one = yield 111;
console.log(one); // BBB, 第二个next的参数
let tow = yield 222;
console.log(tow) // CCC , 第三个next 的参数
let three = yield 333;
console.log(three) // DDD, 第四个 next方法 的参数
}
//执行获取迭代器对象
// 传参
let iterator = gen('AAA');
console.log(iterator.next());
// next 方法 可以传入实参
console.log(iterator.next("BBB")); // 第二次调用的next方法传入的参数, 会作为第一个yield语句返回的结果;
console.log(iterator.next("CCC")); // 第三次调用的next方法传入的参数, 会作为第二个yield语句返回的结果;
console.log(iterator.next("DDD"));
生成器实例
// 异步编程 文件操作 网络操作 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()
// 实例2
//模拟获取 用户数据 订单数据 商品数据 获取数据,进行操作
//异步获取
function getUsers () {
setTimeout(() => {
let data = "用户数据"
iterator.next(data); // 调用 next()方法时, 传入 data 数据, yield 接收到数据 ,进而操作数据
}, 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();
// 异步处理数据
Promise
Promise 是 ES6 引入的异步编程的新解决方案 , 语法上 Promise 是一个构造函数用来封装异步函并可以获取其成功或或者失败的结果
// 创建 Promise
// 实例化 Promise 对象
const p = new Promise(function(resolve,reject){
setTimeout(() => {
let data = '用户数据'
// 如果成功, 调用 resolve
// resolve(data);
//如果失败, 调用 reject
let err = '获取数据失败';
reject(err);
}, 1000)
});
// 调用 promise 对象的 then 方法
// p.then() 回调方法 , 给出两个参数, 一个是成功的函数, 一个是失败的函数
p.then(function(value){
// 第一个参数; 成功的回调 , value 异步请求成功后,获取的数据
console.log(value)
}, function(reason) {
// 第二个参数; 失败的回调
console.log(reason)
})
promise封装读取文件
// Promise封装读取文件
//1. 引入 fs 模块
const fs = require('fs');
//2. 使用 fs模块 调用方法 读取文件
// fs.readFile('./result/test.md', (err,data) => {
// // 如果失败, 抛出错误
// if (err) throw err;
//
// // 成功状态, 输入内容
// console.log(data.toString()); //<Buffer, 使用 toString() 方法进行转化
// });
//3. 使用 Promise 调用 fs 读取文件内容, 封装 (读取文件内容-> 异步操作)
const p = new Promise(function (resolve, reject) {
fs.readFile('./result/test.md', (err, data) => {
// 如果失败, 调用 reject 改变 p 的返回值
if (err) reject(err);
// 如果成功
resolve(data);
})
})
// 调用 Promise, 通过 p.then() 回调处理结果
p.then((value) => {console.log(value.toString())}, (reason) => {console.log('读取失败')})
Promise封装Ajax请求
// https://api.oick.cn/dutang/api.php
// 默认的 Ajax 发起请求
// //1. 创建对象
// const xhr = new XMLHttpRequest();
//
// //2 初始化
// xhr.open('GET', 'https://api.oick.cn/dutang/api.php');
//
// //3, 发送
// xhr.send();
//
// //4, 绑定事件,处理响应结果
// xhr.onreadystatechange = function () {
// // 判断
// if (xhr.readyState === 4) {
// // 判断响应码 200 ~ 299
// if ( xhr.status >= 200 && xhr.status < 300) {
// // 表示成功
// console.log(xhr.response);
// }else {
// console.log(xhr.status);
// }
// }
// }
// 使用 Promise 发起请求
const p = new Promise((resolve, reject) => {
//1. 创建对象
const xhr = new XMLHttpRequest();
//2 初始化
xhr.open('GET', 'https://api.oick.cn/dutang/api.php');
//3, 发送
xhr.send();
//4, 绑定事件,处理响应结果
xhr.onreadystatechange = function () {
// 判断
if (xhr.readyState === 4) {
// 判断响应码 200 ~ 299
if ( xhr.status >= 200 && xhr.status < 300) {
// 表示成功
// console.log(xhr.response);
resolve(xhr.response); // 返回给实例化对象p
}else {
// 表示失败
// console.log(xhr.status);
reject(xhr.status);
}
}
}
});
// 实例化对象p 处理响应结果
// 指定回调
p.then((value)=>{
console.log(value);
}, (reason)=> {
console.log('获取数据失败',reason)
});
promise.prototype.then方法
// 创建 Promise 对象
const p = new Promise((resolve, reject) => {
setTimeout(() => {
// resolve('这是用户数据');
reject("出错了")
}, 1000)
});
// 调用 then 方法
// 查看 then 的返回结果
/**
* 调用then 方法 then 方法的返回结果是 Promise 对象, 对象状态由回调函数的执行结果决定
*
* 1. 如果回调函数中返沪的结果是 非 promise 类型的属性 , 状态为 成功
*
*/
const result = p.then(value => {
console.log(value)
// 1. 非 promise 类型属性
// return 213; // 状态是成功的
// 2. 是promise 对象
// return new Promise((resolve, reject) => {
// resolve('ok');
// })
//3. 抛出错误
throw new Error('出错了')
}, reason => {
console.warn(reason)
})
// 所以可以利用 then 的返回值 可以 进行链式调用
// 链式调用
// p.then(value => {
//
// }).then(value => {
//
// })
console.log(result)
Promise对象catch方法
const p = new Promise((resolve, reject) => {
// 设置 p 对象的状态为失败, 并设置失败的值
reject('出错了')
})
// 通常使用 p.then 方法 指定失败的回调
// p.then(value => {}, reason => {
// console.log(reason);
// })
// 使用 catch 方法
// 只获取出错的回调
p.catch(reason => {
console.log(reason)
})
总要:Promise的链式调用
(套娃)实例
// 这种场景使用在 读取用户数据 之后 才能读取用户的订单 用户商品管理 等等操作
// 遇到时候 可以想到使用 Promise
// Promise实践-读取多个文件内容
const fs = require('fs')
// 默认一个文件内容
fs.readFile('./result/test.md', (err, data) => {
console.log(data.toString())
})
// 使用 Promise 读取多个内容
const p = new Promise((resolve, reject) => {
// 读取第一个文件
fs.readFile('./result/test.md', (err, data) => {
resolve(data)
})
})
p.then(value => { // value 是第一个文件内容
// 使用 p.then 的返回可以是一个 Promise 的特性可以读取第二个文件内容
return new Promise((resolve, reject) => {
fs.readFile('./result/test2.md', (err, data) => {
// 返回 第一个文件内容 和 第二个文件内容
resolve([value, data]);
})
})
}).then(value => { //链式调用, 此时的value 是 [value, data]
return new Promise((resolve, reject) => {
// 读取第三个文件内容
fs.readFile('./result/test3.md', (err, data) => {
// 压入操作
value.push(data);
resolve(value);
})
})
}).then(value => { // 这里就是3个文件的内容了
console.log(value.join('\r\n')) // 打印输出
})
Set 和 Map
Set 方法
Set ES6 提供的新的数据结构 Set 集合 , 类似数组, 但集合中的成员值都是唯一的
Set实现了 iterator 接口, 所以可以使用 … | for…of 进行遍历
* Set 的属性和方法
* size : 返回集合元素的个数
* add : 增加一个新的元素, 返回当前集合
* delete : 删除元素, 返回 boolean值
* has : 检测集合中是否包含某个元素, 返回 boolean值
* clear : 清空集合元素
// 声明一个 Set 集合
let s = new Set();
// console.log(s, typeof s); // Set(0) {size: 0} 'object'
// 使用 Set 的属性方法
let s2 = new Set(['test1', 'test2','test3']);
// 个数
console.log(s2.size);
// 添加
s2.add('test4');
// 删除
s2.delete('test2');
// 检测
console.log(s2.has('test3')); // 返回一个boolean 值
// 清空集合
// s2.clear();
//使用 for...of 遍历
for (let v of s2) console.log(v);
// 使用 扩展运算符 展开集合
console.log(...s2);
console.log(s2);
// set实践
let arr = [1,23,1,21,21,3,31,23,1,1,2,3];
//1. 数组去重
let result = [...new Set(arr)];
// Set特性,在Set集合中元素只能出现一次. | 使用 ... 展开Set集合,保存为数组
console.log(result);
//2. 交集
let arr2 = [1,2,3,2,1,2];
let result = [...new Set(arr)].filter(item => { // arr 去重然后循环过滤
let s2 = new Set(arr2); // arr2 去重
// s2.has(item) 判断s2中是否由 item , 可以获取交集的元素
return s2.has(item)
})
console.log(result);
//简化
let result = [...new Set(arr)].filter(item => new Set(arr2).has(item));
console.log(result);
//3. 并集
// 使用 [...new Set(arr)] 转为一个数组
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 方法
Map ES6提供的Map数据结构。 它类似于对象, 也是键值对的集合。
但是“键”的范围不限于字符串, 各种类型的值(包括对象)都可以当作键。
Map具有 iterator 接口, 可以使用 … | for…of 进行遍历
* Map 具有的属性方法
* size : 返回Map的个数
* set : 增加一个元素, 返回当前的Map
* get : 返回键名对象的键值
* has : 检测Map中是否含有某个元素, 返回 boolean 值
* clear : 清空Map集合, 返回 undefined
* keys() : 获取所有的key名
// 声明 Map
let m = new Map();
console.log(m, typeof m); // Map(0) {size: 0} 'object'
// Map 属性方法
//1. 添加属性 set(key, value ) 形式
m.set('name', "yellowsea");
m.set('change', function() {console.log('这是change方法')}); // key 和 value 不仅仅是字符串,
let key = {
school: 'HIdie'
};
m.set(key, ['test1', 'test2', 'test3']);
// 删除 键
// m.delete('name');
// 检测
console.log(m.has(key)); // true
// 获取 键值value
console.log(m.get('name')); // 通过 key 获取 value 的值
console.log(m.get(key));
// 遍历
console.log(...m); // 展开
for (let v of m.keys()) console.log(v);
// 清空
// m.clear();
console.log(m);
Class 类
ES6 引入了Class类这个概念,作为对象的模板 。 通过class关键字可以定义类。
基本上ES6的class可以看作只是一个语法糖,它的绝大多数功能ES5都可以做到 。 新的class 写法只是让对象原型的写法更加清晰,更像面向编程的语法而已
* 知识点
* class 声明类
* constructor 定义构造函数初始化
* extends 继承父类
* super 调用 父级构造方法
* static 定义静态方法和属性
* 父类方法可以重写
ES5通过构造函数 实现的类方法
//手机
function Phone (brand, price) {
this.brand = brand;
this.price = price;
}
// 添加方法 (在原型上)
Phone.prototype.call = function () {
console.log('这是call 方法 ');
}
// 实例化对象
const Huawei = new Phone('华为',2000);
Huawei.call();
console.log(Huawei);
ES6使用class 构造类
// 使用 ES6 的 class 构造类
class Phone {
// 构造方法, 必须使用 constructor()方法,不能修改,自动执行(在new Phone的时候执行)
constructor(brand, price) {
this.brand = brand;
this.price = price;
}
// 定义方法
call(a) { // 必须使用该语法在class中定义方法,不能使用 ES5的对象完整形式
console.log('这是call 方法 ', a);
}
}
const onePlus = new Phone('1+手机', 1000);
onePlus.call('test');
console.log(onePlus);
class类静态属性
/// Class静态成员
// ES5 的静态成员
function Phone() {
}
// 这样在写属性在 构造函数 对象 上的属性, 实例化对是无法查看到的
// 这种属性叫做静态属性
Phone.name = 'test';
Phone.change = function () {
console.log('这是change 方法');
}
// 如果在构造函数原型上 添加的属性 就可以看到
Phone.prototype.size = '123';
// console.log(Phone.name);
Phone.change();
// 实例化对象
let nokia = new Phone();
console.log(nokia.name); // undefined , 实例化对象出来的, 是无法获取到构造函数中的静态属性
console.log(nokia.size);
// ES6
// Class 定义静态属性
class Shouji {
static mingzi = "手机";
static change() {
console.log('静态属性方法')
}
}
// 实例化对象
const sj = new Shouji();
console.log(sj.mingzi); // undefined , 实例化对象出来的, 是无法获取到Class中的静态属性
class构造函数继承
ES5构造函数继承
// 回顾 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值 ; 实现子类调用父类方法 进行初始化
Phone.call(this, brand,price); // this 是指向 SmartPhone
//子类属性初始化
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 sj = new SmartPhone("这是手机",12312, 'back', '5.5');
console.log(sj);
sj.call();
sj.playGame();
sj.photo();
ES6 class 继承
// Class 的继承
class Phone {
// 构造方法
constructor(brand, price) {
this.brand = brand;
this.price = price;
}
//父类的方法
call() {
console.log('我可以大点话 ');
}
}
// 子类, extends
class SmartPhone extends Phone { // 子类必须使用 extends 指向父类
// 子类的构造方法
constructor (brand,price,color,size) {
// 注意点
super(brand,price) // 必须通过 super 指向父类的constructor 方法,进行父类的属性的初始化
// super(brand,price) 相等于 ES5 中的 Phone.call(this,brand, price)
this.color = color;
this.size = size;
}
// 子类方法
photo() {
console.log('我可以拍照');
}
playGame() {
console.log('我可以打游戏');
}
}
//实例化对象
const Xiaomi = new SmartPhone('小米手机', 2000, 'write', '5.5inch');
console.log(Xiaomi);
Xiaomi.call();
Class中Getter和Setter方法
class Phone {
// get 方法
get price() { // 只要实例化对象 读取了 price属性, 就睡调用 get price 这个方法
// 返回值就是 price 这个属性的值
return 'price的值'
}
// set
//只要price属性被修改了,就会调用set 方法
set price(value) {// price 必须接收一个参数,为修改的值
console.log('price 被修改了 ');
return value
}
}
const s = new Phone();
console.log(s.price)
s.price = 'free';
console.log(s)
ES6数值的扩展
// Number 数值的扩展
//1. 二进制和八进制
let b = 0b1010; // 二进制
let o = 0o777; // 0o 表示八进制
let d = 100; // 十进制
let x = 0xff; // 十六进制
console.log(b,o,d,x); // 10 511 100 255
//2. Number.isFinite 检测一个数值是否为有限数
console.log(Number.isFinite(100))
console.log(Number.isFinite(100/0))
//3. Number.isNaN 检测一个数值是否为NaN
console.log(Number.isNaN(3));
//4. Number.parseInt Number.parseFloat 字符串转为整数
console.log(Number.parseInt('123123aaa'));
console.log(Number.parseFloat('3.12生')); // float
// 5. Number.isInteger 判断一个数是否为 整数
console.log(Number.isInteger(123));
console.log(Number.isInteger(12.3));
//6. Math.trunc 将数字的小数部分抹掉
console.log(Math.trunc(3.14));
//7. Math.sign 判断一个数是否是 正数 零 负数
console.log(Math.sign(100)) //1
console.log(Math.sign(0)) // 0
console.log(Math.sign(-100)) //-1
ES6对象的扩展
// 对象扩展方法
//1. Object.is 判断两个值是否完全相等
console.log(Object.is(123,123));
console.log(Object.is(NaN,NaN));
//2. Object.assign 对象的合并
const obj1 = {
username: 'yellowsea',
password: 'test1'
}
const obj2 = {
username: null,
password: null,
}
// Object.assign(参数1, 参数2); 参数2会覆盖参数1, 后面的会覆盖前面的
// console.log(Object.assign(obj1, obj2));
Object.assign(obj1,{a:1,b:2,c:3}); // 合并
console.log(obj1);
//3. Object.setPrototypeOf 设置原型对象
// Object.getPrototypeOf 获取原型对象
const school = {
name: "Yellowsea"
}
const className = {
name: ['test1', 'test2', 'test3']
}
// 设置原型对象 , Object.setPrototypeOf(对象原型, 设置原型对象上的数据);
Object.setPrototypeOf(school, className);
console.log(Object.getPrototypeOf(school)); // 获取原型 信息
console.log(school);