对过去两周所学的ES6知识做一下总结 ,理一下思路 加深记忆
自已的理解 有不对的请指正 共同学习
更详细的请访问文档 ECMAScript 6 入门
Symbol
// 向对象中添加方法
let game = {
name: '狼人杀',
up: function () {
},
down: function () {
}
}
let methods = {
up: Symbol(),
down: Symbol()
};
game[methods.up] = function () {
console.log("upupup!")
}
game[methods.down] = function () {
console.log("downdown")
}
game[methods.up]() // upupup!
game[methods.down]() // downdown
let mysymbol = Symbol('say');
let mysymbol2 = Symbol('me');
let game1 = {
name: 'langrensha',
[mysymbol]: function () {
console.log("我可以说话!")
},
[mysymbol2]: function () {
console.log("自爆了!")
}
}
console.log(game1)
game1[mysymbol]() // 我可以说话!
game1[mysymbol2]() // 自爆了!
- Symbol扩展
// [Symbol.hasInstance]
// 当其他属性使用了instanceof运算符时,判断是否为该对象的实例
class MyClass {
[Symbol.hasInstance](param) {
console.log("我被用来检测类型了")
}
}
let a = {};
console.log(a instanceof MyClass)
// [Symbol.isConcatSpreadable]
// 合并后数组是否可以展开,默认展开
const arr = [1, 2, 3]
const arr2 = [4, 5, 6]
arr2[Symbol.isConcatSpreadable] = false;
console.log(arr.concat(arr2, 7))
// [Symbol.species]
// 创建衍生对象时,会使用该属性。
// 它主要的用途是,有些类库是在基类的基础上修改的,那么子类使用继承的方法时,
// 作者可能希望返回基类的实例,而不是子类的实例。
class MyArry extends Array {
static get [Symbol.species]() { return Array; }
}
const _a = new MyArry();
const b = _a.map(x => x)
console.log(b instanceof MyArry) // false
console.log(b instanceof Array) // true
// Symbol.match
// 对象的Symbol.match属性,指向一个函数。当执行str.match(myObject)时,
// 如果该属性存在,会调用它,返回该方法的返回值。
//String.prototype.match(regexp)
//RegExp[Symbol.match](this) // 等同于
class MyMatcher {
[Symbol.match](String) {
return 'hello world'.indexOf(String)
}
}
const me = 'e'.match(new MyMatcher())
console.log(me) // 1
// Symbol.iterator 指向该对象的默认遍历器方法
const myIterable = {};
myIterable[Symbol.iterator] = function* () {
yield 1;
yield 2;
yield 3;
}
console.log([...myIterable]) //[1,2,3]
// Symbol.replace
// 会接收到两个参数,第一个是replace方法正在作用的对象 hello ,二 替换后的值 world
const X = {}
X[Symbol.replace] = (...s) => console.log(s);
'hello'.replace(X, 'world d')
迭代器
- 工作原理
- 创建一个指针对象,指向当前数据结构起始的位置
- 第一次调用对象的next方法,指针自动指向数据的第一各成员
- 然后不断调用next方法 ,指针向后移动 直到指向最后一个成员
- 每次调用next方法都会包含一个value,done属性的对象
const game=['孙悟空','猪八戒','沙僧','唐僧']
// for in for of
// 区别:a:保存的是键值索引 b:直接输出value值
for(i of game){
console.log(i)
}
// 调用iterator时 会有一个next方法 不断调用next方法 直到最后一个值
// 调用时next对象done属性为false 结束返回true
let iterator=game[Symbol.iterator]()
console.log(iterator)
console.log(iterator.next()) // {value: "孙悟空", done: false}
console.log(iterator.next()) // {value: "猪八戒", done: false}
console.log(iterator.next()) // {value: "沙僧", done: false}
console.log(iterator.next()) // {value: "唐僧", done: false}
console.log(iterator.next()) // {value: undefined, done: true}
- 自定义迭代器遍历对象
let banji = {
name: '熊出没',
stus: [
'光头强',
'熊大',
'熊二'
],
[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 (i of banji) {
console.log(i)
} // 光头强 熊大 熊二
生成器 generator *
- generator 生成器 是ES6 提供的一种异步编程解决方案
- 生成器就是一个特殊函数
- 两个特征:1)function 关键字与函数名之间有一个星号 位置没有规定偏左或偏右
- 函数体内部 使用yield表达式 定义不同的状态 可以理解为函数代码分隔符
function* gen() {
// console.log("hello generator!")
console.log(111)
yield '两只老虎'
console.log(222)
yield '一只没有耳朵,一只没有尾巴'
console.log(333)
yield '真奇怪'
console.log(444)
}
let inerator = gen()
console.log(inerator.next())
console.log(inerator.next())
console.log(inerator.next())
console.log(inerator.next())
// 2.生成器函数参数
// yield 表达式本身没有返回值, next方法可以带一个参数,该参数会被当做上一个yield语句的返回值
function * gen1(args){
console.log(args)
one= yield 111
console.log(one)
yield 222
yield 333
}
let iteator1=gen1('aaa')
console.log(iteator1.next()) // aaa 会在 yield 111 之前返回 aaa {value: 111, done: false}
console.log(iteator1.next('bbb')) // bbb {value: 222, done: false}
- 生成器实例
// 1.实例 1秒后输出111 2秒后输出222 3秒后输出333
function one() {
setTimeout(() => {
console.log(111)
ineatoe_one.next();
}, 1000)
}
function two() {
setTimeout(() => {
console.log(222)
ineatoe_one.next();
}, 2000)
}
function three() {
setTimeout(() => {
console.log(333)
ineatoe_one.next();
}, 3000)
}
// setTimeout()
function* gen_one() {
yield one()
yield two()
yield three()
}
let ineatoe_one = gen_one()
ineatoe_one.next();
// 2.用户数据 商品数据 订单数据 接收数据并带回
function getUsers(){
setTimeout(()=>{
let data ="用户数据 樱花"
inerator.next(data)
},2000)
}
function getOrders(){
setTimeout(()=>{
let data="商品数据 百合"
inerator.next(data)
},2000)
}
function getGoods(){
setTimeout(()=>{
let data="订购数据 玫瑰"
inerator.next(data)
},2000)
}
function * shopp(){
let users= yield getUsers()
console.log(users) // 用户数据 樱花
let orders= yield getOrders()
console.log(orders) // 用户数据 樱花
let goods= yield getGoods()
console.log(goods) // 订购数据 玫瑰
}
let inerator =shopp()
inerator.next()
对象方法的扩展
- object.assign() 用于对象的合并
- 第一个参数是目标对象,后面的参数都是源对象
- 注:如果目标对象和源对象有同名的属性,或多个源对象同名的属性 则后面的会覆盖前面的属性
// 1.object.is 判断两个值是否相等 相当于 ===
// 区别 一是+0不等于-0,二是NaN等于自身。
console.log(Object.is(120, 120)) // true
console.log(Object.is(NaN, NaN)) // true
console.log(Object.is(+0, -0)) // false
console.log(NaN === NaN) // false
console.log(+0 === -0) // true
// 2.object.assign() 用于对象的合并
const config1={
name:'小明',
age:'21',
aihao:'打游戏'
}
const config2={
name:'xiaoming',
age:'22',
aihao2:'wan'
}
console.log(Object.assign(config1,config2)) //name: "xiaoming", age: "22", aihao: "打游戏", aihao2: "wan"
// 3.__proto__属性,Object.setPrototypeOf(),Object.getPrototypeOf()
const school={
name:'小花',
}
const cities={
xiaoqu:['北京','深圳']
}
Object.setPrototypeOf(school,cities) // 把cities的属性设置成school原型链的属性
console.log(school)
console.log(Object.getPrototypeOf(school)) // {xiaoqu: Array(2)} xiaoqu: (2) ["北京", "深圳"] __proto__: Object
const school = {
name: '小蔡',
city: ['陕西', '深圳']
}
// Object.keys 获取对象所有的键值
console.log(Object.keys(school)) // ["name", "city"]
// Object.values 获取对象所有的值
console.log(Object.values(school)) // ["小蔡", Array(2)] 0: "小蔡" 1: (2) ["陕西", "深圳"]
// Object.entries 返回的是一个数组 第一个是键值 第二个是值 方便创建Map
console.log(Object.entries(school)) // 0: (2) ["name", "小蔡"] 1: (2) ["city", Array(2)]
const m = new Map(Object.entries(school))
console.log(m.get('name')) // 小蔡
// 获取object.create 创建时带的属性 可以进行深层次的拷贝
console.log(Object.getOwnPropertyDescriptors(school))
// name:
// value: "小蔡"
// writable: true
// enumerable: true
// configurable: true
const obj = Object.create(null, {
name: {
value: '小明',
writable: true,
enumerable: true,
configurable: true
}
})
数值的扩展
- ES6 提供了二进制和八进制数值的新的写法,分别用前缀0b(或0B)和0o(或0O)
- 检测一个数值是否为有限数 ,如果参数类型不是数值,Number.isFinite一律返回false。
- 用来检查一个值是否为NaN
- Number.parseInt() 截取字符串中整数
- Number.parseFloat() 截取小数
- Number.isInteger() 检测一个数是否为整数
- Math.sign 判断一个数为正数(1) 负数(-1) 0(0)
// 0 Number.EPSILON 是JavaScript表示的最小精度
function equal(a, b) {
if (Math.abs(a - b) < Number.EPSILON)
return true
else
return false
}
console.log(equal(0.1 + 0.2, 0.3)) // true
console.log(0.1 + 0.2 === 0.3) // false
// 1 二进制 八进制
// ES6 提供了二进制和八进制数值的新的写法,分别用前缀0b(或0B)和0o(或0O)
let b =0b1010
let o = 0b111
// 将字符串数值转换为十进制 使用Number
console.log(Number('0b111'))
console.log(0)
// 2.Number.isFinite 检测一个数值是否为有限数
// 如果参数类型不是数值,Number.isFinite一律返回false。
console.log(Number.isFinite(100)) //true
console.log(Number.isFinite(100/0)) // false
// 4.Number.parseInt() Number.parseFloat()
console.log(Number.parseInt('123fsf')) // 123
console.log(Number.parseFloat('12.3fsf')) // 12.3
// 5.Number.isInteger() 检测一个数是否为整数
console.log(Number.isInteger(5)) // true
console.log(Number.isInteger(3.14)) // false
// 6.Math.trunc 将数字的小数部分抹掉
console.log(Math.trunc(3.14)) // 3
// 对于非数值,使用NUmber方法将其转换为数值
Math.trunc('123.456') // 123
Math.trunc(true) //1
Math.trunc(false) // 0
Math.trunc(null) // 0
// 对于空值和无法截获整数的值 返回NaN
Math.trunc(NaN); // NaN
Math.trunc('foo'); // NaN
Math.trunc(); // NaN
Math.trunc(undefined) // NaN
// 7.Math.sign 判断一个数为正数 负数 0
console.log(Math.sign(100));
console.log(Math.sign(-100000));
console.log(Math.sign(0));
Map
ES6 提供了 Map 数据结构, 它类似于对象,也是键值对的集合
但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。
// 声明MAp
let m = new Map()
m.set('name','小明')
// 可以为一个方法
m.set('change',function(){
console.log("改变世界")
})
// 方法属性也可以作为键值
let key ={
school:'ATGUIGU'
}
m.set(key,['上海','北京','深圳'])
// 大小
console.log(m.size)
console.log(m.delete('name'))
// // 读取
console.log(m.get('change'))
console.log(m.get(key))
// // 清空 clear()
console.log(m)
// 遍历出m所有的属性
for (let i of m){
console.log(i)
}
set
es6 提供了新的数据结构 set 类似于数组,但是成员的值都是唯一的
可以使用扩展运算符 … 和for of 遍历
// 声明一个set
let s = new Set()
let s1=new Set(['1','2','2','3','4','3'])
console.log(s,typeof s) // Set(0) {} "object"
console.log(s1) // Set(4) {"1", "2", "3", "4"}
// 添加数据
s1.add("小明")
// 元素个数
console.log(s1.size)
s1.delete("1")
// 检测是否存在
console.log(s1.has('2'))
// s1.clear()
console.log(s1)
for(let i of s1){
console.log(i)
}
- Set 练习
let arr = [1, 2, 3, 4, 5, 4, 3, 2, 1]
// 1.数组去重
let result = new Set(arr)
console.log(result) // Set(5) {1, 2, 3, 4, 5}
// 2.交集
let arr2 = [4, 5, 6, 5, 6]
// let result=[...new Set(arr)].filter(item=>{
// let s2 =new Set(arr2);
// if(s2.has(item))
// return true;
// else
// return false;
// })
let result=[...new Set(arr)].filter(item => new Set(arr2).has(item))
console.log(result) // (2) [4, 5]
// 3.并集
let union=[...new Set([...arr,...arr2])]
console.log(union) // (6) [1, 2, 3, 4, 5, 6]
// 4.差集
let result1=[...new Set(arr)].filter(item => !(new Set(arr2).has(item)))
console.log(result1)
class
// 传统方式
function phone(brand, price) {
this.brand = brand;
this.price = price
}
phone.prototype.call = () => { console.log("我可以打电话") }
let xiaomi = new phone('小米', 4399)
xiaomi.call() // 我可以打电话
console.log(xiaomi) // phone {brand: "小米", price: 4399}
// class
class phone1{
// 构造方法 名字不能修改
constructor(brand,price){
this.brand=brand;
this.price=price;
}
// 方法必须使用该语法 不能使用es5的对象完整形式 call : function name(params) {}
call(){
console.log("我可以接电话")
}
}
let oppo = new phone1("oppo a57",1400)
oppo.call() // 我可以接电话
console.log(oppo) // phone1 {brand: "oppo a57", price: 1400}
class_静态成员
function phone() {
}
phone.name = "hello"
phone.change = () => { console.log("我可以改变世界") }
let nokia=new phone()
// 实例对象和函数对象是不通的 原型上的属性是相同的
phone.prototype.size='5.4Se'
console.log(nokia.name) //undefined
console.log(nokia.change()) // TypeError: nokia.change is not a function
console.log(nokia.size) // 5.4Se
class phone1{
static name='oppo';
static change=()=>{console.log('你好')}
}
let nokia1=new phone1()
// name 属于类而不是古语实例对象
console.log(nokia1.name) // undefined
console.log(phone1.name) // oppo
class_继承
// 构造函数继承
function phone(brand,price){
this.brand=brand
this.price=price
}
phone.prototype.call=()=>{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.playgame=()=>{
console.log("我可以打游戏")
}
let oppo=new smartphone('oppo','1400','玫瑰金','14')
console.log(oppo)
// class 继承
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);
this.color = color;
this.size=size;
}
playgame(){
console.log("我可以打游戏")
}
// 对父类的方法重写
call(){
// super.call()
console.log("我可以视频通话")
}
}
let xiaomi =new smartphone('小米','4399','玫瑰金','17')
console.log(xiaomi)
xiaomi.playgame()
xiaomi.call()
class_getSet
// get set
class phone {
// 封装动态属性
get price() {
console.log("价格属性被读取了")
return 123
}
// 对传入的属性进行限制
set price(nval) {
console.log("属性被修改")
}
}
let s = new phone()
// console.log(s.price) // 价格属性被读取了 123
s.price = 'free' // 属性被修改