ES6语法新特性总结

一、let
1、声明变量
let a;
let b, c;//未赋值的输入undefined
let d = 3;
let e = 3, f = 'my is f', g = []
2、变量不能重复声明
//let重复声明会报错,但是使用var不会报错,使用let可以防止变量重复
let num = 100
let num2 = 200
3、块级作用域
//es5有三种作用域 全局,函数,eval(在es5严格模式里才会出现)
//if else while for 在这些里面都有块级作用域

{
    let age = 18
}
console.log(age)//在外面不会输出结果(Uncaught ReferenceError: age is not defined),在括号里面才可以输出,这就是块级作用域,var可以输出
4、不存在变量提升
 //console.log(myAge)
let myAge = 18
//let声明会报错,Uncaught ReferenceError: Cannot access 'myAge' before initialization
//var声明不会报错,会输出undefined
5、不影响作用域链
{
    let age = 18
    function fu() {
        return function fu2() {
            return function fu3() {
                console.log(age)
            }
        }
    }
    fu()()()
}

二、const
//声明常量
const SCHOOL = "艾尼斯";
1、一定要赋初始值(没有初始值会报错)
2、一般常量使用大写(潜规则)
3、常量的值不能修改
4、块级作用域
{
    const A = 'UZI'
    console.log("4.块级作用域", A);
}
5、对于数组和对象的元素修改,不算做对常量的修改,不会报错
const TEAM = ['UZI', 'MLXG', 'Ming', 'Letme']
TEAM.push("Meiko")
console.log(TEAM);

三、解构赋值

ES6 允许按照一定模式从数组和对象中提取值,对变量进行赋值,这被称为解构赋值

1、数据解构赋值 (按照数组下标排序的)
const F4 = ['小沈阳', '刘能', '赵四', '宋小宝'];
let [xiao, liu, zhao, song] = F4;
console.log(xiao);
console.log(liu);
console.log(zhao);
console.log(song);
2、对象解构赋值(根据key值解构)
const PEOPLE = {
    name: '小明',
    age: '21',
    speak() {
        console.log("我可以说话");
    }
}
let { name, age, speak } = PEOPLE
console.log(name);
console.log(age);
speak()

// let { speak } = PEOPLE
// speak()

四、模版字符串

ES6 引入新的声明字符串方式【``】 '' ""

1、声明
let str = `我是字符串`;
console.log("str", typeof str);
2、可以换行
let str2 = `<ul>
                <li>沈腾</li>
                <li>艾伦</li>
                <li>魏翔</li>
            </ul>`;
console.log(str2);
3、变量拼接
 let name = '玛丽'
 let str3 = `${name}在吃饭!`
 console.log(str3);

五、对象简化写法

ES6 允许在大括号里面,直接写入变量和函数,作为对象的属性和方法。

 let name = "张三"
 let speak = function () {
     console.log("我可以说话!!");
 }
 const SCHOOl = {
     name, //简写前name:name
     speak, //简写前speak:speak
     dance() {
         console.log("我可以跳舞");
     }
 }

 console.log(SCHOOl);

六、箭头函数

箭头函数适合与this 无关的回调,定时器,数组的方法回调

箭头函数不适合与this 有关的回调,事件回调,对象的方法

1、箭头函数基本形式
let fn = () => {

}
let func = (num) => num;
let func = () => num;
let sum = (num1,num2) => num1 + num2;
[1,2,3].map(x => x * x);
2、this指向

箭头函数this为父作用域的this,不是调用时的this

箭头函数的this永远指向其父作用域,任何方法都改变不了,包括call,apply,bind。
普通函数的this指向调用它的那个对象。

let person = {
    name:'jike',
    init:function(){
        //为body添加一个点击事件,看看这个点击后的this属性有什么不同
        document.body.onclick = ()=>{
            alert(this.name);//?? this在浏览器默认是调用时的对象,可变的?                  
        }
    }
}
person.init();

上例中,init是function,以person.init调用,其内部this就是person本身,而onclick回调是箭头函数,
其内部的this,就是父作用域的this,就是person,能得到name。

let person = {
    name:'jike',
    init:()=>{
        //为body添加一个点击事件,看看这个点击后的this属性有什么不同
        document.body.onclick = ()=>{
            alert(this.name);//?? this在浏览器默认是调用时的对象,可变的?                  
        }
    }
}
person.init();

上例中,init 为箭头函数,其内部的this为全局window, onclick 的this也就是 init 函数的this,也是window,
得到的 this.name 就为undefined。

3、箭头函数不能作为构造函数,不能使用new

Demo1

let Person = (name, age) => {
    this.name = name
    this.age = age
}
let me = new Person('xiao', 30)
console.log(me);

Demo2

//构造函数如下:
function Person(p){
    this.name = p.name;
}
//如果用箭头函数作为构造函数,则如下
var Person = (p) => {
    this.name = p.name;
}

由于this必须是对象实例,而箭头函数是没有实例的,此处的this指向别处,不能产生person实例,自相矛盾。

4、箭头函数没有arguments,caller,callee

箭头函数本身没有arguments,如果箭头函数在一个function内部,它会将外部函数的arguments拿过来使用。
箭头函数中要想接收不定参数,应该使用rest参数...解决。

let B = (b)=>{
  console.log(arguments);
}
B(2,92,32,32);   // Uncaught ReferenceError: arguments is not defined

let C = (...c) => {
  console.log(c);
}
C(3,82,32,11323);  // [3, 82, 32, 11323]
5、箭头函数通过call和apply调用,不会改变this指向,只会传入参数
let obj2 = {
    a: 10,
    b: function(n) {
        let f = (n) => n + this.a;
        return f(n);
    },
    c: function(n) {
        let f = (n) => n + this.a;
        let m = {
            a: 20
        };
        return f.call(m,n);
    }
};
console.log(obj2.b(1));  // 11
console.log(obj2.c(1)); // 11
6、箭头函数没有原型属性
var a = ()=>{
  return 1;
}

function b(){
  return 2;
}

console.log(a.prototype);  // undefined
console.log(b.prototype);   // {constructor: ƒ}
7、箭头函数不能作为Generator函数,不能使用yield关键字
8、箭头函数返回对象时,要加一个小括号
var func = () => ({ foo: 1 }); //正确
var func = () => { foo: 1 };   //错误
9、箭头函数在ES6 class中声明的方法为实例方法,不是原型方法
//deom1
class Super{
    sayName(){
        //do some thing here
    }
}
//通过Super.prototype可以访问到sayName方法,这种形式定义的方法,都是定义在prototype上
var a = new Super()
var b = new Super()
a.sayName === b.sayName //true
//所有实例化之后的对象共享prototypy上的sayName方法


//demo2
class Super{
    sayName =()=>{
        //do some thing here
    }
}
//通过Super.prototype访问不到sayName方法,该方法没有定义在prototype上
var a = new Super()
var b = new Super()
a.sayName === b.sayName //false
//实例化之后的对象各自拥有自己的sayName方法,比demo1需要更多的内存空间

因此,在class中尽量少用箭头函数声明方法。

10、多重箭头函数就是一个高阶函数,相当于内嵌函数
const add = x => y => y + x;
//相当于
function add(x){
  return function(y){
    return y + x;
  };
}
11、箭头函数常见错误
let a = {
  foo: 1,
  bar: () => console.log(this.foo)
}

a.bar()  //undefined

bar函数中的this指向父作用域,而a对象没有作用域,因此this不是a,打印结果为undefined

function A() {
  this.foo = 1
}

A.prototype.bar = () => console.log(this.foo)

let a = new A()
a.bar()  //undefined

原型上使用箭头函数,this指向是其父作用域,并不是对象a,因此得不到预期结果

12、箭头函数的简写
let add = (n) => { return n + n }
//参数只有一个的时候,可以省略小括号,
let add = n => { return n + n }
//代码体只有一行的时候可以省略大括号,return也必须省略,执行结果就是函数的返回值
let add = n => n + n 

七、函数参数默认值设置
1、形参初始值具有默认的参数,一般位置要靠后(潜规则)
function add(a, b, c = 5) {
    return a + b + c
}

console.log(add(1, 2));//如果传值以传的值为准,如果不传以默认值为准
2、与解构赋值结合
 function connect({ host = "192.168.1.1", username, password, port }) {
     console.log(host);
     console.log(username);
     console.log(password);
     console.log(port);
 } 
connect({ host: "baidu.com", username: 'root', password: 'root', port: 8080 })

八、rest参数
1、ES6 rest参数,用于获取函数的实参,用来代替arguments
//ES5 获取实参方式
function add() {
    console.log("ES5 获取实参方式", arguments);
}
add(9, 4, 6)

//ES6 获取实参方式
function add2(...args) {
    console.log("ES6 获取实参方式", args);
}
add2(9, 4, 6)
2、rest参数必须放到参数最后
function num(a, b, ...args) {
    console.log(a);
    console.log(b);
    console.log(...args);
}
num(9, 4, 6, 1, 6, 8, 9)

九、扩展运算符

... 扩展运算符能将[数组] 转换为逗号分隔的[参数序列]

const arr = ['张三', '李四', '王五'];
const arr2 = ['赵六', '孙七', '钱八'];
console.log(arr);//["张三", "李四", "王五"]
console.log(...arr);//张三 李四 王五
1、数组合并
console.log("1.concat数组合并", arr.concat(arr2));
console.log("2.扩展运算符数组合并", [...arr, ...arr2]);
2、数组克隆
const arr3 = [...arr2];
console.log("数组克隆", arr3);
3、伪数组转为真正的数组
const divs = document.querySelectorAll('div')
console.log(...divs);

十、Symbol

ES6 引入了一种新的原始数据类型 Symbol ,表示独一无二的值,他是javascript语言的第七种数据类型,是一种类似于字符串的数据类型

  • Symbol的值是唯一的,用来解决命名冲突的问题
  • Symbol的值不能与其他数据进行运算
  • Symbol 定义的对象属性不能使用for...in 循环遍历,但是可以使用Reflect.ownkeys来获取对象的所有键名

ES6 引入了一种新的原始数据类型 Symbol ,表示独一无二的值,最大的用法是用来定义对象的唯一属性名。

//ES6 数据类型除了 Number 、 String 、 Boolean 、 Object、 null 和 undefined ,还新增了 Symbol 。

// USONB ===>you are so niubility
// u undefined
// s String Symbol
// o Object
// n Number null
// b Boolean
1、声明
let s = Symbol();
console.log(typeof s);//symbol
console.log(typeof (s));//symbol 
2、相同参数 Symbol() 返回的值不相等
let s1 = Symbol('ANS');
let s2 = Symbol('ANS');
console.log(s1 === s2);//false
3、用for创建数据类型是一致的

虽然这样保证了Symbol的唯一性,但我们不排除希望能够多次使用同一个symbol值的情况。

为此,官方提供了全局注册并登记的方法:Symbol.for()

let s3 = Symbol.for('ANS');//检测到未创建后新建
let s4 = Symbol.for('ANS');//检测到已创建后返回
console.log(s3 === s4);//true
4、不能与其他数据类型进行运算
console.log(s1 + 100);
console.log(s1 > 100);
console.log(s1 + s3);
5、当symbol值作为对象的属性名的时候,不能用点运算符获取对应的值。
let name = Symbol();
let person = {
    [name]: "张三"
};
console.log(person[name]);//张三
console.log(person.name);//undefined

symbol 类型的值作为对象的属性名的时候,一定要用中括号[ ]不能用点运算符,因为用点运算符的话,

会导致 javascript 把后面的属性名为理解为一个字符串类型,而不是 symbol 类型

let name = Symbol();
let person = {};
person.name = "张三";
console.log(person[name]);   //结果:undefined  
console.log(person['name']); //结果:张三  
console.log(person.name); //结果:张三 
6、向对象中添加方法

向对象中添加一个独一无二的方法,methods.speak 对应都是Symbol数据类型,可以向 people 对象中添加一个独一无二的方法,不会破坏原有的方法

关于Symbol创建对象函数时的调用方法

let people = {
    name: 'ZS',
    age: 19,
    speak() {
        console.log("说话");
    },
    eat() {
        console.log("吃饭");
    }
}
let methods = {
    speak: Symbol(),
    eat: Symbol(),
}

people[methods.speak] = function () {
    console.log("shuohua");
}

people[methods.eat] = function () {
    console.log("chifan");
}

people.eat()//吃饭
people[methods.eat]()//chifan

第二种方式:

let zibao = Symbol();
let say = Symbol();
let youxi = {
    name: '狼人杀',
    [say]: function () {
        console.log("我可以发言");
    },
    [zibao]: function () {
        console.log("我可以自爆");
    }
}
console.log(youxi);
youxi[say]()
youxi[zibao]()

第三种方式

let youxi = {
    name: '狼人杀',
    [Symbol('say')]() {
        console.log("我可以发言");
    },
    [Symbol('zibao')]() {
        console.log("我可以自爆");
    }
}

// 第一种调用方法
const langrensha=Object.getOwnPropertySymbols(youxi)
youxi[langrensha[0]]()
youxi[langrensha[1]]()

// 第二种调用方法 
const langrensha2=Reflect.ownKeys(youxi)
youxi[langrensha2[1]]()
youxi[langrensha2[2]]()
7 、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环境排除。

这些属性都是symbol里面的一个属性,是固定写法,他们整体又作为我们对象的属性去设置,来改变我们对象在特定场景下的表现,说白了就是扩展对象功能的

Symbol.hasInstance 使用

检测类型

 class Person {
     static [Symbol.hasInstance](param) {
         console.log(param);
         console.log("我用来检测类型");
         return true;
     }
 } 
let o=[2,3,4];
//instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。
console.log(o instanceof Person);

Symbol.isConcatSpreadable 使用

设置数组是否展开

let arr = [1, 2, 24, 23]
let arr2 = [42, 25, 24, 235]
//控制arr2是否可以展开
arr2[Symbol.isConcatSpreadable] = false
console.log(arr.concat(arr2)) //(5)[1, 2, 24, 23, Array(4)]

十一、迭代器

迭代器(Iterator)是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署Iterator接口,就可以完成遍历操作。

  1. ES6 创造了一种新的遍历命令 for...of循环,Iterator接口主要提供 for...of 消费
  2. 原生具备Iterator 接口的数据(可用for of 遍历)
    • Array
    • Arguments
    • Set
    • Map
    • String
    • TypedArray
    • NodeList
  3. 工作原理
    • 创建一个指针对象,指向当前数据结构的起始位置
    • 第一次调用对象的next方法,指针自动指向数据结构的第一个成员
    • 接下来不断调用next方法,指针一直往后移动,直到指向最后一个成员
    • 每调用next方法返回一个包含 value 和 done 属性的对象

    注意:需要自定义遍历数据的时候,要想到迭代器

let arr = ['zhansgan', 'lisi', 'wangwu']


for (let a in arr) {
    // 使用for...in a保存的是键名
    console.log(a);//0 1 2
}

for (let a of arr) {
    // 使用for...of a保存的是键值
    console.log(a);//zhansgan lisi wangwu 
}
//for in和 for of 区别 第一个前面常量保存是键名,后面保存的是键值  
//为什么数组可以使用for of 遍及呢,只要他对象里面有symbol.iteratoa属性就可以 我们来看一看,只要打印这个变量看一下就可以,他的值是一个函数
// console.log(arr);
let iterator=arr[Symbol.iterator]();
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());

迭代自定义遍厉对象例子

要求:使用遍及对象,让他返回数组中的每个成员,按照自己意愿遍厉,按照自己意愿去做这个事情

const banji = {
    name: '终极一班',
    stus: [
        "zhangsan",
        "lisi",
        "wangwu",
        "zhaoliu"
    ], 
}
//要求:使用遍及对象,让他返回数组中的每个成员,按照自己意愿遍厉,按照自己意愿去做这个事情
 for (let v of banji) {
     console.log(v);
 }

//直接只用for循环不行

需要添加 Symbol.iterator

 const banji = {
     name: '终极一班',
     stus: [
         "zhangsan",
         "lisi",
         "wangwu",
         "zhaoliu"
     ],
     [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);
 }

十二、生成器

生成器他是一个特殊的函数

作用:用来执行异步编程。 之前用的是纯回调函数比如 node 里面fs模块 ajax monhobd数据库 他们都是异步的我们用的方式都是回调函数一层调一层,会形成回调地狱。 生成器就是对异步编程的一种解决方案

 function* gen() {
     console.log("hello");
 } 
// gen().next();
let iterator=gen();
iterator.next();

1.声明特殊,

    需要加上 `*` 号( `*` 位置靠前、靠后、居中都可以)

2.执行特殊

 直接调用不可以,需要.next()
  1. 还有一个特殊,就是在生成器函数中可以出现 yield 语句后面使用自变量或者表达式,yield 语句他是函数代码的分隔符,下图是分成四块

他不想之前一下子执行完成,是通过next方法向下执行的

function* gen() {
    console.log(11);
    yield '一只没有耳朵';
    console.log(22);
    yield '一只没有尾巴';
    console.log(33);
    yield '真奇怪';
    console.log(44);
}

let iterator = gen(); 
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());

//iterator既然他是一个对象,可以使用for of来做遍及,每一次调用返回的结果是yield后面的表达式或者是自定义变量
for (let v of gen()) {
    console.log(v);
}

生成器函数传参 第二次调用将作为第一次 yeild 语句整体的返回结果也就是说传的参数将作为上一个 yeild 语句的返回结果

function* gen(arg) {
    console.log(arg);//AAA
    let one = yield '一只没有耳朵';
    console.log(one);//BBB
    let two = yield '一只没有尾巴';
    console.log(two);//CCC
    let three = yield '真奇怪';
    console.log(three);//DDD
}

//执行获取迭代器对象
let iterator = gen("AAA")
console.log(iterator.next());//{value: "一只没有耳朵", done: false}
//next方法可以传入实参
console.log(iterator.next("BBB"));//{value: "一只没有尾巴", done: false}
console.log(iterator.next("CCC"));//{value: "真奇怪", done: false}
console.log(iterator.next("DDD"));//{value: undefined, done: true}
Demo1 例子:

要求: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();

这样看着给同步的代码是一样的,实际上执行的时候他是异步的,这是生成器函数在异步任务的表现,成功解决了回调地狱的问题

Demo2 例子:

要求:模拟获取 (传参数) 用户数据 订单数据 商品数据

function getUser() {
    setTimeout(() => {
        let data = "用户数据"
        iterator.next(data);//传参数
    }, 1000)
}
function getOrders() {
    setTimeout(() => {
        let data = "订单数据"
        iterator.next(data);//传参数
    }, 1000)
}
function getGoods() {
    setTimeout(() => {
        let data = "商品数据"
        iterator.next(data);//传参数
    }, 1000)
}

function* gen(sss) {
    console.log(sss);
    let users = yield getUser();
    console.log(users);
    let orders = yield getOrders();
    console.log(orders);
    let goods = yield getGoods();
    console.log(goods);
}

//调用生成器函数
let iterator = gen("传参数");//传参数
iterator.next();

这样看着给同步的代码是一样的,实际上执行的时候他是异步的,这是生成器函数在异步任务的表现,成功解决了回调地狱的问题


十三、promise

promises 是ES6引入的异步编程的新解决方案,语法上Promise是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果

promise是es6非常重要的一个内容,也是面试经常问到的点,异步编程主要指io的代码,包括文件io,数据库io ,网络请求等

//实例化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 里面封装一个异步操作,用定时器模拟一个异步操作,得到数据后调用 resolvereject 两个函数来改变 promise 对象的状态。

调用 resolve promise对象状态(初始化,成功,失败)就会变成成功,成功就会调用 promise 对象的 then 方法,then 接受两个参数,这两个参数都是函数(函数带个参数),一个成功,一个失败,成功会调用then方法第一个回调, 失败调用reject 会调用then第二个回调。 通过这样方式,我们就吧一个异步任务封装在promise对象里面 ,而且通过resolve reject这两个函数来改变promise对象的状态,改变状态后来调用then方法里面的回调

封装ajax请求

接口地址:https://api.apiopen.top/getJoke

原始封装方法

//1.创建对象
const xhr = new XMLHttpRequest();

//2.初始化
xhr.open("GET", "https://api.apiopen.top/getJoke");

//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.error(xhr.status);
        }
    }
}

promise 封装方法

具体百度查询吧


十四、set

ES6提供了新的数据结构 Set(集合)。它类似于数组,但成员的值都是唯一的。集合实现了iterator接口。所以可以使用扩展运算符和for of 进行遍历。

集合的属性和方法

  • size 返回集合的元素个数
  • add 增加一个新元素,返回当前集合
  • delete 删除元素,返回boolean 值
  • has 检测集合中是否包含某个元素,返回boolean值
let s = new Set();//声明一个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);
// }
1.数据去重复
let arr=[1,2,3,4,5,1,2,3,7,11,66];
let result=[...new Set(arr)]
console.log(result);//[1, 2, 3, 4, 5, 7, 11, 66]
2.交集

交集 (数组1和数组2 都有的) 中括号是转化成数组,通过集合吧元素去重,去重以后还是个集合,本身是个集合转化成数组

let arr=[1,2,3,4,5,1,2,3,7,11,66];
let arr2 = [4, 5, 6, 5, 6,10]
let result = [...new Set(arr)].filter(item => {
  let s2 = new Set(arr2);//4,5
  if (s2.has(item)) {
      return true;
  } else {
      return false;
  }
})

//简写
//let result = [...new Set(arr)].filter(item => new Set(arr2).has(item));
console.log(result);//[4, 5]
3.并集 (两个数据合并去重)
let arr=[1,2,3,4,5,1,2,3,7,11,66];
let arr2 = [4, 5, 6, 5, 6,10]
let union=[...new Set([...arr,...arr2])];
console.log(union);//[1, 2, 3, 4, 5, 7, 11, 66, 6, 10]
4.差集(arr2 和 arr 相差的,也就是说arr2 不包含的)
let arr=[1,2,3,4,5,1,2,3,7,11,66];
let arr2 = [4, 5, 6, 5, 6,10]
let diff = [...new Set(arr)].filter(item => !(new Set(arr2).has(item)));
console.log(diff);// [1, 2, 3, 7, 11, 66]

十五、Map

ES6 提供了 Map数据结构。它类似于对象,也是键值对的集合。但是"键"的范围不限于字符串,各种类型的值(包括对象)都可以当作键。Map也实现了iterator接口,所以可以使用扩展运算符和for of 进行遍历。

Map 的属性和方法

  • size 返回Map 的元素个数

  • set 增加一个新元素,返回当前Map

  • get 返回键名对象的键值

  • has 检测Map 中是否包含某个元素,返回boolean值

  • clear 清空集合,返回undefined

map其实就是升级版的对象,原来key只能是字符串,现在可以设置成对象,

1.声明

let m = new Map()//声明

2.添加元素

m.set('name','张三')
m.set('speak',function(){
    console.log("说话");
})

let key={
    school:'ANS'
}
m.set(key,['北京','上海','天津'])
console.log(m);

3.获取个数

console.log(m.size);

4.删除

m.delete('name')

5.获取

console.log(m.get('speak'));
console.log(m.get(key));

6.清空

m.clear();

7.遍历

for(let v of m){
    console.log(v);
}

十六、class
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);//call改变this指向
    this.color = color;
    this.size = size;
}

//让子类的原型对象指向父类实例, 这样一来在 SmartPhone 实例中找不到的属性和方法就会到原型对象(父类实例)上寻找
SmartPhone.prototype = new Phone();
// 根据原型链的规则,顺便绑定一下 constructor, 这一步不影响继承, 只是在用到constructor时会需要
SmartPhone.prototype.constructor = SmartPhone;

// SmartPhone.prototype = {
//     constructor: Phone,
//     photo: function () {
//         console.log("我可以拍照");
//     },
//     playGame: function () {
//         console.log("玩游戏");
//     }
// }
SmartPhone.prototype.photo = function () {
    console.log("我可以拍照");
}
SmartPhone.prototype.playGame = function () {
    console.log("玩游戏");
}

调用

let xm = new SmartPhone("小米", 1499, '红色', '5.5inch')
console.log(xm);
xm.call()

// let huawei = new Phone("华为", 2000)
// huawei.call()
// console.log(huawei);
ES6 类

父类

class Shouji {
    //构造方法,名字不能修改
    constructor(brand, price) {
        this.brand = brand;
        this.price = price;
    }

    //方法必须使用该语法,不能使用ES5的对象完整形式
    call() {
        console.log("打电话");
    }
}

子类

class Znsj extends Shouji {
    constructor(brand, price, color, size) {
        // super 就是父类的constructor方法 通过这样的方式来完成调用 
        super(brand, price)//Phone.call(this, brand, price);
        this.color = color;
        this.size = size;
    }
    photo() {
        console.log("拍照");
    }
    playGame() {
        console.log("玩游戏");
    }
}

调用

let znsj = new Znsj("魅族", 1500,'白色','5.5inch')
console.log(znsj);
znsj.playGame()

let mz = new Shouji("魅族", 1500)
// console.log(mz);

十七、数值扩展
二进制和八进制
let b = 0b1010;
let o = 0o777;
let d = 100;
let x = 0xff;
console.log(b);
console.log(o);
console.log(d);
console.log(x);
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);
console.log(equal(0.1 + 0.2, 0.3));
// console.log(Math.abs(-5));
Number.isFinite
//Number.isFinite  检测一个数值是否为有限数
console.log(Number.isFinite(1000));
console.log(Number.isFinite(1000/0));
console.log(Number.isFinite(Infinity));
Number.isNaN
//Number.isNaN 检测一个数值是否为NaN
console.log(Number.isNaN(123));
Number.parseInt(Number.parseFloat)
//Number.parseInt  Number.parseFloat 字符串转整数
console.log(Number.parseInt('524545sadasd'));
console.log
Number.isInteger
//Number.isInteger 判断是否为整数
console.log(Number.isInteger(5));
console.log(Number.isIn
Math.trunc
// Math.trunc  将数字的小数部分抹掉
console.log(Math.trunc(3.8));
Math.sign
// Math.sign 判断一个数到底为正数 负数 还是零
console.log(Math.sign(100));
console.log(Math.sign(0));
console.log(Math.sign(-100));

十八、get set 设置

ES5 也使用过,对对象属性进行方法的绑定,当对某一个属性进行获取时,去执行get对应函数

Set 必须传个参数,Get 调用这个,就会执行里面代吗,这个返回值就是这个属性的值

使用场景,get通常对动态属性进行封装,他这个属性是变化的,比如求总数,求平均数,他的值是随着数据变化而变化,而不是固定的,这时候我们通过get函数动态计算结果,就变得非常方便

Set 添加更多控制,和判断 比如传过来的这个值是否合法的,我要num类型你给我传个字符串那肯定不行啊,这个时候可以通过判断成功就赋值,失败就不赋值

class Phone {
    get price() {
        console.log('价格属性被读取了');
        return 'iloveyou'
    }

    set price(newVal) {
        console.log('价格属性被修改了');
    }
}

//实例化对象
let p = new Phone();

console.log(p.price);
p.price = '3000'
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容