ES6新特性

let与const

let命令

ES6新增了let命令,用来声明变量。他的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效。通过let声明的变量也不能再次被声明,否则会报错。

块级作用域:

function f1(){
    let n=5;
    if(true){
        let n=10;
    }
    console.log(n);//5
}

const命令

const用于声明一个只读常量。一旦声明,常量的值就不能改变且必须立即初始化,不能留到以后赋值。常量像let一样不存在变量提升,同样存在暂时性死区,只能在声明的位置后面使用。

字符串的扩展

ES6加强了对Unicode的支持,并且扩展了字符串对象,但在实际应用中常用的是模板字符串。模板字符串(template string)是增强版的字符串,用反引号(`)标识。它可以当作普通的字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量,下面通过传统字符串定义来理解模板字符串。

//传统的JavaScript语言,使用连接字符串
var str=
    "<h1>前端开发常用技术</h1>"
    "<ul>"
    "<li>HTML5</li>"
    "<li>CSS</li>"
    "<li>JavaScript</li>"
    "</ul>";

上面这种写法相当烦琐不方便,ES6引入了模板字符串解决这个问题。

var str=`
    <h1>前端开发常用技术</h1>
    <ul>
    <li>HTML5</li>
    <li>CSS</li>
    <li>JavaScript</li>
    </ul>`

使用模板字符串可以方便的换行,不用使用+号连接。如果需要拼接上变量,那么拼接的格式是使用${}包裹变量即可。

let myName=`雪儿`  //使用反引号
let age=18
let=`${myName}年龄是${age}`//雪儿年龄是18

反引号内可以放JavaScript表达式,也可调用函数,将显示函数执行后的返回值都写在${}里面fn()。代码如下:

var a=3;
var b=5;
var c=`${a}+${b}=${a+b}`;
console.log(c);//结果:3+5=8

使用模板字符串注意以下两点:

(1)如果拼接的变量没有声明,会报错。

(2)如果${}里面放的是字符串,则输出还是字符串。

对象那个的扩展

1.简写的属性初始化

function createPerson(name,age){
//返回一个对象:属性名和参数名相同
    return{
        name:name,
        age:age
    }
}
console.log(createPerson("李丽",18)); //{name:"李丽",age:18}

在ES6中,上面的写法可以简化成如下格式。

function createPerson(name,age){
//返回一个对象:属性名和参数名相同
    return{
        name,//当对象属性名和本地变量名相同时,可以省略冒号和值
        age
    }
}
console.log(createPerson("李丽",18));//{name:"李丽",age:18}

该项扩展在使得对象字面两的初始化变得简明的同时,也清楚了命名错误。对象属性被同名变量赋值在JavaScript中是一种普通的编程模式,所以这项扩展的添加非常受欢迎。

2.简写的方法声明

var person={
    name:"李丽",
    sayHello:function(){
        console.log("我的名字是:"+this.name);
    }
}
person.sayHello()

在ES6中,上面的写法可以简化成如下格式。

var person={
    name:'李丽',
    sayHello(){
        console.log("我的名字时:"+this.name);
    }
}
person.sayHello()

3.扩展运算符

对象的扩展运算符(...)用于取出参数对象的所有课遍历属性,复制到当前对象之中

let z={a:3,b:4};
let n={...z};
//n的值为{a:3,b:4}

这个方法对于数组也通用。

let foo={...['a','b','c']};

箭头函数

1.箭头函数基本用法

ES6标准新增了箭头函数Arrow Function,箭头函数是一种更加简洁的函数书写方法。代码如下:

参数=>函数体

ES6之前通常的函数定义方法:

var fn1=function(a,b){
    return a+b
}
function fn2(a,b){
    return a+b
}

使用ES6箭头函数语法定义函数,将原函数的‘function’关键字和函数名都删掉,并使用‘=>'连接参数列表和函数体。

当函数参数只有一个,括号可以省略;但是没有参数时,括号不可以省略,代码如下:

//无参
var fn1=function(){}  //ES6之前定义
var fn1=()=>{}  //ES5箭头函数

//单个参数
var fn2=function(a){}
var fn2=a=>{}

//多个参数
var fn3=function(a,b){}
var fn3=(a,b)=>{}

//可变参数
var fn4=function(a,b,...args){}
var fn4=(a,b,...args)=>{}

箭头函数相当于匿名函数,并且简化了函数定义。箭头函数有两种格式,一种只包含一个表达式,省略了{...}和return。还有一种可以包含多条语句,这时候就不能省略{...}和return,如下:

()=>return 'hello'
(a,b)=>(a+b)
(a)=>{
    a=a+1;
    return a;
}

箭头函数返回一个对象。需要特别注意,如果是单表达式要返回自定义对象,不写括号会报错,因为和函数体的{...}由语法冲突。

x=>({key:x})

2.this问题

箭头函数看上去是匿名函数的一种简写,但实际上,箭头函数和匿名函数有个明显的区别:箭头函数内部的this是词法作用域,由上下文确定。词法作用域就是定义在词法阶段的作用域。换句话说,词法作用域是由在写代码时将变量和块作用域写在哪里来决定的,因此当词法分析器处理代码时会保持作用域不变。在ES5中,this:执行函数的上下文;在ES6中,this:定义函数的上下文。

注意:用小括号包含大括号时对象的定义,而非函数主体

箭头函数没有自己的this,函数体内的this对象就是定义时所在的函数上下文,而不是使用时(执行时)所在的函数上下文。

       document.onclick=function(){
                console.log(this);//输出document
                let f=()=>{
                    console.log(this);//下面语句调用输出document
                };
                f();
            };

 其中,document。οnclick=function(){}的这个函数执行时,函数内部的this是执行时的函数上下文document,而第二的console时箭头函数定义时所在环境为document

    document.onclick=()=>{
                console.log(this);
            };

箭头函数中的this会去赵当前定义这个函数的环境中的this为window,因此输出的对象为window。

  function fn(){
                setTimeout(()=>{
                    console.log(this);
                },1000);
            }
            fn();
            document.onclick=fn;

当这个函数执行document.οnclick=fn时,那么fn()函数中的this为document,使用setTimeout就会去找定义时所在环境中的this为document;当直接执行fn()函数时,fn()函数中的this为window,那么就会输出window

   const cat={
                lives:9,
                jumps:()=>{
                    return this;
                },
            };
            console.log(cat.jumps(),"this的指向");

因为对象不构成单独的作用域(在里面没有this指向),导致jumps箭头函数(想上找)定义时的作用域,因此输出结果为window

      function fn(){
                 const cat={
                lives:9,
                jumps:()=>{
                    return this;
                },
            };
            console.log(cat.jumps(),"this的指向");
            }
            document.onclick=fn;

给cat对象套上一个函数时执行document.οnclick=fn,由于这个函数中的this为document,因此,jumps中的this在定义时所指向的为document

 类基本语法

JavaScript语言的传统方法是通过构造函数,定义并生成新对象,例如:

//传统对象原型写法
function Point(x,y){
    this.x=x;
    this.y=y;
    console.log(x,y);
}
Point.prototype.toString=function(){
    return '('+this.x+','+this.y+')';
};
var p=new Point(1,2);

这种写法与传统的面向对象语言差异很大,很容易让新学习这门语言的程序员感到困惑。ES6提供了更接近传统语言的写法,引入了Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。基本上ES6的class的绝大部分功能在ES5中也可以做到,新的class写法只是让对象圆形的写法只是让对象原型的写法更加清晰、更像面向对象的编程的语法而已。上面的代码用ES6的“类”改写,代码如下:

class Point{
    constructor(x,y){
        this.x=x;
        this.y=y;
        console.log(x,y);
    }
    toString(){
        return '('+this.x+','+this.y+')';
    }
}

上面代码定义了一个“类”,可以看到里面有个constructor()方法,这就是构造方法,而this关键字则代表实例对象。也就是说,ES的构造函数Point对应ES的Point类的构造方法。Point类除了构造方法,还定义了toString()方法。constructor()方法是类的默认方法,通过new命令生成对象实例时,自动调用该方法。一个类必须由constructor()方法,如果没有显示定义,会默认添加一个空constructor()方法。

类本质上就是一个函数,类自身指向的就是构造函数,类完全可以看作构造函数的另一种写法。

console.log(Person===Person.prototype.constructor);

实际上类的所有方法都定义在类的prototype属性上,可以通过prototype属性对类添加方法。

Person.prototype.addFn=function(){
    return "我是通过prototype新增加的方法,名字叫addFn";
}
var point=new Point(2,3);
console.log(point.addFn());//我是通过prototype新增加的方法,名字叫addFn

还可以通过Object.assign()方法来为对象动态增加方法 :

Object.assign(Point.prototype,{
    getX: function(){
        return this.x;
    },
    getY: function(){
        return this.y;
    },
});
var point=new Point(2,3);
console.log(point.getX());//输出2
console.log(point.getY());//输出3

类创建好后,生成类的实例对象时要使用new命令。如果忘记加上new,像ES5函数那样调用class将会报错。

let point=new Point(2,3);
  class Point{
                constructor(x,y){
                    this.x=x;
                    this.y=y;
                    console.log(x,y);
                }
                toString(){
                    return "("+this.x+","+this.y+")";
                }
            }
            var point=new Point(2,3);
            console.log(point.toString());//(2,3)
            console.log(point.hasOwnProperty("x"));//true
            console.log(point.hasOwnProperty("y"));//true
            //x,y都是构造函数本身的属性,因此返回true
            console.log(point.hasOwnProperty("toString"));//false
            //toString是原型上的属性,因此返回false
            console.log(point.__proto__.hasOwnProperty("toString"));//true

其中,hasOwnProperty()方法返回一个布尔值,判断对象是否包含特定的自身(非继承)属性,效果图如下:

 class的继承

可以使用extends关键字实现继承。子类继承父类,相当于继承了家产一样,继承了父类所有属性和方法。并且,每次extends后面只能跟一个父类,代码格式如下:

class 父类名{
    //父类的属性和方法
}
//子类继承父类
class 子类名 extends 父类名{
    //子类的属性和方法
}

例如:

    class Father{
                constructor(){
                    this.name="father";
                    this.money=60000;
                }
                say(){
                    console.log(`${this.name} say hello`);
                }
                myMoney(){
                    console.log(`${this.name} has ${this.money}元`);
                }
            }
            class Son extends Father{
                constructor(){
                    super();//注意这个一定要写
                    this.name="son";
                    this.addmoney=40000;
                }
                addMonth(){
                    console.log(`${this.name}共有${this.addmoney}+${this.money}=${this.money+this.addmoney}元`);
                }
            }
            var son1=new Son();
            son1.say();//son say hello
            son1.addMonth();

运行结果:

继承用extends。继承后,需要用super()来接收父类的constructor构造函数,否则会报错。当new一个子类时,先把参数传入子类构造函数,在通过super()将父类的构造函数引入,就可以调用父类。

class静态方法 

类(class)通过static关键字定义静态方法,所有在类中定义的方法都会被实例继承,但定义成静态方法后,就表示该方法不会被实例继承,而是直接通过类来调用。

语法格式:

class 类名{
    static 方法名(){
        //属性
    }
}

在类中也可以静态属性,语法格式如下:

class 类名{
    static 属性;
}

解构赋值

1.数组的解构赋值

在ES6中,添加了一种名为解构复制特性,能从数组和对象中提取内容和赋值给变量。结构赋值,也称模式匹配,即赋值的左右两边模式相同,则等号右边的值赋给左边的变量。解构赋值适用于let、var、const声明变量/常量。

//在解构赋值前,声明多个变量
let a=1;
let b=2;
let c=3;
//解构赋值
Let[a,b,c]=[1,2,3];

这种写法属于模式匹配,即只要等号(=)两边的模式相同,等号左边的变量就会被赋予对应的值。如果解构失败,那么变量的值会被设置为默认值undefined。

2.对象的解构赋值

对象的解构赋值将对象属性的值赋给多个变量。在ES6之前,可以这样把对象的属性赋值给多个变量,代码如下:

var obJect={name:"john",age:23};
var name=object.name;
var age=object.age;
console.log(name,age);//john 23

在ES6中,可以使用对象解构表达式,在单行里给多个变量赋值,代码如下:

let object={name:"john",age:23};
let name age;
({name,age}=object);
console.log(name,age);//john 23

对昂解构赋值时的左侧为解构赋值表达式,右侧为对应要分配赋值的对象。当先定义变量,后使用解构语句时,两边千万不要遗漏左右括号(),否则会报错。

在解构对象针对未分配值的变量,可以为变量提供默认值,代码如下:

let {a,b,c=3}={a:"1",b:"2"};
console.log(c);//输出3

 数组的扩展

1.扩展运算符

扩展运算符(spread)是三个点(...),像rest参数的逆运算,将一个数组转为用逗号分隔的参数序列。

var arr=[33,1,34,35,8,9]
console.log('arr:',...arr);

数组是复合的数据类型,直接复制数组会指向底层数据解构的指针,而不是数组。使用扩展运算符来复制数组更方便。

//ES5的解决办法
const a1=[1,2];
const a2=a1.concat();
a2[0]=2;
console.log('a1:',a1);//[1,2]


//ES6的写法
const a1=[1,2];
const a2=[...a1]
a2[0]=2;
console.log('a1:',a1);//[1,2]
console.log('a2:',a2);//[2,2]

合并数组:

var a1=[1,2];
var a2=['aa','bb','cc'];
var a3=['张三','李四'];
//ES5操作方法
const new1=a1.concat(a2).concat(a3);
//ES6操作方法
const new2=[...a1,...a2,...a3];
console.log('new1:',new1);
console.log('new2:',new2);

使用扩展运算符将字符串转为数组:

var str='hello';
var arr=[...str];
console.log('arr:',arr);//["h","e","l","l","o"];

2.新增的数组方法

(1)Array.from()方法。Array.from()方法用于将两类对象转为真正的数组,类似数组的对象(arrayLike object)和可遍历(iterable)的对象(包括ES6新增的数据结构Set和Map)。

let arrayLike={
    '0':'a',
    '1':'b',
    '2':'c',
    length:3
};
//ES5的写法
var arr1=[].style.call(arrayLike);//['a','b','c']
//ES6的写法
var arr2=Array.from(arrayLike);//['a','b','c']

(2)Array.of()方法。Array.of()方法用于将一组值转换为数组。这个方法的主要目的是弥补数组构造函数Array()的不足。因为参数个数的不同,会导致Array()的行为有差异。

Array.of(3,11,8)  //[3,11,8]
Array.of(3) //[3]
Array.of(3).lenght //1
Array()  //[]
Array(3)  //[,,,]
Array(3,11,8) //[3,11,8]

(3)find()与findindex()方法。数组实例的find()方法用于找出第一个符合条件的数组成员。它的参数是一个回调函数,所有数组成员依次执行该回调函数,直到找出第一个返回值为true的成员,然后返回该成员。如果没有符合条件的成员,则返回undefined。

[1,5,10,15].find(function(value,index,arr){
    return value>9;
})//10

find()方法的回调函数可以接受三个参数,以此为当前的值、当前的位置和原数组。数组的实例的findIndex()方法的用法与find()方法非常类似,返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1.

[1,5,10,15].findIndex(function(value,index,arr){
    return value>9;
})//2

这两个方法都可以发现NaN,弥补了数组的indexOf()方法的不足。

(4)find()方法。find()方法使用给定值,填充一个数组。

['a','b','c'].fill(7)//[7,7,7]
new Array(3).fill(7)//[7,7,7]

fill()方法用于空数组的初始化非常方便。数组中已有的元素会被抹去,方法还可以接受第2个和第3个参数,用于指定填充的起始位置和结束位置。

['a','b','c'].fill(7,1,2) //['a',7,'c']

(5)遍历。ES6提供entries()、keys()、values()等3个新方法,用于遍历数组。他们都返回一个遍历器对象,可以用for...of循环进行遍历,唯一的区别是keys()是对键名的遍历,values()是对键值的遍历,entries()是对键值对的遍历。

例如:

let arr=['小红','小明','小芳']
for(let index of arr.keys()){
    console.log('index:',index);
    //*index:0
    //*index:1
    //*index:2
}

for(let value of arr.values()){
    console.log('value:'values);
    //*value:小红
    //*value:小明
    //*value:小芳
}
for(let [index,value] of arr.entries()){
    console.log(index+":"+value);
    //*0:小红
    //*1:小明
    //*2:小芳
}

(6)includes()方法。includes()方法返回一个布尔值,表示某个数组是否包含给定的值,与字符串的includes()方法类似。

[1,2,3].include(3);//true
[1,2,3].include(3,3);//true
[1,2,3].include(3,-1);//true

该方法的第2个参数表示搜索的起始位置,默认为0.如果第2个参数为负数,则表示倒数的位置,如果这时它大于数组的长度(如第2个参数为-4,但数组长度为3),则会重置为从0开始。

(7)flat()方法。flat()方法用于将嵌套的数组“拉平”,变成一堆的数组。该方法返回一个新数组,对原数据没有影响。可以将flat()方法的参数写成一个整数,表示想要拉平的层数,默认为1.

[1,2,[3,[4,5]]].flat()//[1,2,3,[4,5]]

Set/Map数据结构

在ES6中添加了两种新的数据结构及其对应的方法,这两种结构在编程中可以提高开发效率。

1.ES6中Set

ES6中提供了Set数据容器,这是一个能够存储无重复值的有序列表,通过new Set()可以创建Set,然后通过add()方法能够向Set中添加数据项。

Set结构的常用方法或属性
方法名或属性描述
size属性返回Set实例的成员总数
add(value)添加值,返回Set结构本身
delete(value)删除值,返回布尔值,表示删除是否成功
has(value)返回布尔值,表示该值是否为Set的成员
clear()清除所有成员,没有返回值
keys()/values()返回键名/键值的遍历器(无差别)
entries()返回键值对应的遍历器
forEach()使用回调函数遍历每个成员

Set结构的遍历顺序与插入顺序相同,但是他没有键名只有键值,因此keys()和values()方法的行为一致,也可以使用for...of的方法直接遍历。

2.ES6中的Map

Map是一种键值对的对象,相比较对象来说,他的键可以是各种类型的,如果需要在一个地方使用键值对应的数据结构,Map比起Object会更合适。

Map结构的常用方法
方法描述
size()返回Map结构的成员总数
set(key,value)设置key对应的值为value,返回整个结构,可以使用链式写法
get(key)读取key对应的值,找不到则返回undefined
has(key)返回布尔值,表示键是否在Map对象中
delete(key)返回布尔值,表示键是否删除成功
clear()清除所有成员,没有返回值
keys()返回键名的遍历器
values()返回键值的遍历器
entries()返回所有成员的遍历器
forEach()遍历Map的所有成员

  • 25
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值