带你一起敲敲ES6的新特性,边解释边应用!

1,628 阅读6分钟

一,变量声明

像在es4中,使用var声明的变量存在变量提升,下面这样是不会报错的。但是在es6中使用的const和let不行,会报错!!

console.log(a);
var a = 5;
  1. 常量(const,不会变量提升,块级作用域,作用域内值不能改)
  2. 块级作用域(let,不会变量提升)
for (let i = 0; i<5; i++) {
  setTimeout(() => {
    console.log(i)    //0 1 2 3 4
  },30)
}
for (var i = 0; i<5; i++) {
  setTimeout(() => {
    console.log(i)   //5 5 5 5 5
  },30)
}

特别要说明一点的是 对于const和let都有暂存死区,所谓暂存死区就是: 如果作用域内 有这样一个变量 那么这个作用域内就会绑定这个变量,不会继续向上查找了,以下代码运行会报错。

const a = 1;
{

  console.log(a);
  const a = 2;
}
console.log(a)

二,解构赋值

所谓解构赋值就是 声明和赋值都放到了一起 一般都是数组 对 数组, 对象 对 对象, 数组能够设置默认值,对象也能够设置默认值,默认值必须采用等号的方式

let [zhan, si, xl = 5] = [3, 4];
console.log(zhan, si, xl) //3, 4, 5

let {name, age = 23} = {name: 'xl', bigAge: 24}
console.log(name, age) //xl, 23

特别的,可能有时会有关键字的情况可以通过:的形式来更改名字,看下面代码:

let { name, age: xl, default: d } = { name: 'xlei', age: 9, default: 'xxx' };
console.log(name, xl, d);

来一个默认值的具体应用吧:

function ajax({
    url = new Error('url without'),
    type = 'get',
    data = xxx
}){
  console.log(data, type)   //{a: 5}, get
}
ajax({
    url: '/test',
    data: {a:5}
})

三,字符串

  1. 模板字符串(拼接方便,可以换行)
let exe1 = xlei
let exe2 = `${exe1}nihao
我也好`
  1. startWith, endWith 返回一个布尔值
let str1 = 'www.bsym.online'
let str2 = 'http://www.bsym.online'
console.log(str1.startsWith('http://'))   //false
console.log(str2.startsWith('http://'))   //true
console.log(str2.endsWith('online'))     //true
  1. padStart, padEnd补全 -- 不会删除原有内容
// padStart padEnd 补全(记住只能增加,不能减少)
let str1 = 'nihao'
let newStr = str1.padStart(8,'xl')
let newStr2 = str1.padEnd(8,'xl')
console.log(newStr, newStr2)   //xlxnihao, nihaoxlx

四,箭头函数(解决this问题,书写起来也更简单)

传统函数内的this是定义时所在的环境,而箭头函数内的this是使用时上下文的环境。

let aa = (arg1, arg2) => {
  console.log(arg1, arg2)
}

aa(1, 2)   //1, 2

;((arg1, arg2) => {
  console.log(arg1, arg2)
})(3, 4);

这里顺带提一下,像上面的自执行匿名函数前后都要加分号,这样既不会被坑,也不会坑别人。另外不要使用箭头函数的argeuments

五,扩展运算符

  1. 数组的扩展运算符:将一个数组转为用逗号分隔的参数序列
let arr = [...[1, 2, 3], ...[4, 5, 6]]
console.log(arr)   // 1, 2, 3, 4, 5, 6
console.log(Math.min(...arr))  // 1
  1. 对象的解构赋值

对象的 Rest 解构赋值用于从一个对象取值,相当于将所有可遍历的、但尚未被读取的属性,分配到指定的对象上面,注意Rest 解构赋值必须是最后一个参数,否则会报错。Rest解构赋值所在的对象,拷贝了对象obj的属性,Rest解构赋值的拷贝是浅拷贝,即如果一个键的值是复合类型的值(数组、对象、函数)、那么Rest解构赋值拷贝的是这个值的引用,而不是这个值的副本,解构赋值不会拷贝继承自原型对象的属性

let obj = {name: 'xl', age: 23, say:'ok', eat: {xl: 'okok'}}
let {name, age, ...z} = obj    //尚未被读取的属性,分配到指定的对象上面,浅拷贝了对象obj的属性
obj.say = 'oo'
obj.eat.xl = 'o?o?'
console.log(name, age, z)  //xl 23 { say: 'ok', eat: { xl: 'o?o?' } }
let z = {a: 3, b: 4, c:{
    eat:'ok'
}}
let n = {...z}   注意这个地方和直接赋值的区别 let n = z; 一个是浅拷贝对象属性,一个是浅拷贝对象
z.a = 5
z.c.eat = 'ok?'
console.log(n)  //{ a: 3, b: 4, c: { eat: 'ok?' } }

那么要是想实现一个深拷贝,怎么实现呢?其实就是遍历属性如果属性是一个普通值就赋值,不是普通值就递归知道是普通值为止,然后赋值,代码如下:

// 实现深拷贝 保留继承关系 可以实现各种类型的拷贝 实现递归拷贝
    function deepClone(obj) {
        if (typeof obj !== 'object') return obj;
        if (obj == null) return null;
        if (obj instanceof Date) return new Date(obj);
        if (obj instanceof RegExp) return new RegExp(obj);
        let o = new obj.constructor(); // 保留类的继承关系
        // for (let key in obj) {
        //     // console.log(obj.hasOwnProperty === Object.prototype.hasOwnProperty) 
        //     if ( obj.hasOwnProperty(key) ) {   //只有自身属性才赋值
        //         if(typeof (obj[key]) == 'object'){
        //             o[key] = deepClone(obj[key])
        //         }else{
        //             // console.log(obj[key])
        //             o[key] = obj[key]
        //         }
                
        //     }
        // }
        Object.keys(obj).forEach((key, index) => {
            if(typeof (obj[key]) == 'object'){
                o[key] = deepClone(obj[key])
            }else{
                // console.log(obj[key])
                o[key] = obj[key]
            }
        })
        return o;
    }
    let o = { a: { a: 1 }, b: function(){
        console.log(this.a)
    } }
    let newObj = deepClone(o);
    o.a.a = 2;
    console.log( newObj.b());

六,数组常用方法

// 1)map返回值 返回值是一个新数组
    Array.prototype.map = function (fn) {
        let arr = [];
        for (let i = 0; i < this.length; i++) {
            arr.push(fn(this[i], i));
        }
        return arr;
    };
    let arr = [1, 2, 3].map(item => {
        return item * 2;
    });
    console.log(arr);
    // 2)filter 过滤 如果返回true表示留下 返回false表示删除
    let arr = [1, 2, 3];
    let filterArr = arr.filter(item => {
        return item > 2;
    });
    console.log(filterArr);
    // 3)some找到后返回true,找false可以用every 
    let r = [2, 1, 3].some(item => {
        return item > 2;
    });
    console.log(r);  //true
    // 4)every 检测数组 ages 的所有元素是否都符合条件 :

    var ages = [2, 1, 3];

    let r = ages.every((item) => {
        return item > 2
    })
    console.log(r)  //false
    // 5)Array.from();   将类数组转为数组

七,es6的class

先复习一下es5中的几个名词:

  1. 成员属性(方法)| 实例属性(方法) :在构造函数中通过this.属性声明的
  2. 静态属性(方法):通过类来声明的 类.xxx
  3. 私有属性(方法):只有在类的内部可以使用,其他任何地方都不可以使用的
  4. 公有属性(方法)|原型属性(方法):在原型上声明的属性或者方法 xx.prototype.xxx 敲代码:
function Parent(name) {
    this.name = name; //成员属性|实例属性
    this.say = function() {   //成员方法
        console.log(this.name)
    }
}
Parent.smoking = 'no'   //静态属性
Parent.prototype.up = function() {   //公有方法|原型方法
    console.log('ok')
}

再来说说es6中的class(es6中不考虑私有属性和方法):

class Parent{
    constructor(x, y){
        this.x = x;      //成员属性|实例属性  可遍历 打印实例可直接打印出来, // 与 ES5 一样,实例的属性除非显式定义在其本身(即定义在this对象上),否则都是定义在原型上(即定义在class上)。
        this.y = y;
        return this.x     //如果不返回 默认返回实例对象 this
    }
    static b(){ // 属于类上的方法 也称静态方法
        return 2;
    }
    eat(){    //原型上的方法 | 公有方法 并且都是不可枚举的 打印实例不能显示的打印出来 
        console.log(this.x);
        return this.x
    }
    // Object.assign(Parent.prototype, {
        // eat(){},
    // });
}
class Child extends Parent{ // 
    constructor(x, y, z){
        super(x, y); // Parent.call(this);     返回的是子类的实例,
        this.age = z; // 成员属性|实例属性
    }
    static a(){ // 属于类上的方法
        return 1;
    }
    smoking(){ // 原型上的方法
        return super.eat() + this.age    //需要说明的是 super不仅可以调用父类的原型方法还可以调用父类的静态方法,方法内部的this指向当前的子类,而不是子类的实例
        // console.log(this.age)
        
    }
}
let child = new Child(2, 3, 4);
// console.log(child);
console.log(child.smoking())

class Foo {
    constructor() {  //constructor函数默认返回this, 这里返回一个全新的对象,结果导致实例对象不是Foo类的实例
        return Object.create(null);
    }
}

new Foo() instanceof Foo
// false

//定义类
class Point {

    constructor(x, y) {
        this.x = x;        
        this.y = y;
    }

    toString() {
    return '(' + this.x + ', ' + this.y + ')';
    }

}

var point = new Point(2, 3);
console.log(point)
point.toString() // (2, 3)

point.hasOwnProperty('x') // true
point.hasOwnProperty('y') // true
point.hasOwnProperty('toString') // false
point.__proto__.hasOwnProperty('toString') // true


class A {
}

class B extends A {
}

B.__proto__ === A // true
B.prototype.__proto__ === A.prototype // true

以上就是ES6常用的几个新特性,动手敲一遍,你就记住了!当然以上肯定会存在很多不足的地方,欢迎各位提出宝贵的意见或建议,也希望能帮助到你从中获得一些知识!