ES6--使用理解

Es6 简介

  •  ECMAScript 6 简称 ES6,是 JavaScript 语言的下一代标准,已经在 2015 年 6 月整事发布了。
  • ECMAScript和JavaScript的关系,简单来说ECMAScript是JavaScript语言的国际标准,JavaScript是ECMAScript的实现。
  • 它的目标是使 JavaScript语言可以用来编写复杂的大型应用程序,成为企业级开发语言。

ES6新特性

var、let和const

  • 除了 var ,我们现在还可以使用两个新的标示符来定义一个变量 —— let 和 const。和 var 不一样的是,let定义的变量不会被变量提升,const定义的变量不能被修改。   
  •  在ES6前,js是没有块级作用域{}的概念。(有函数作用域,全局作用域,eval作用域)  
  •  在ES6后,let和const的出现,js也有了块级作用域的概念。    
  • (变量提升:)在ES6前,var声明的变量无论声明在何处,都会被视为声明在函数的最顶部,不在函数内即在全局作用域的顶部。

举个例子先。

console.log(a);//undefined
var a = "good";
//代码可以解读为
var a;console.log(a);a="good";

//var声明的变量提升到全局作用域的顶部,但是赋值声明不会被提升复制代码

而let就不会被变量提升

console.log(a);//a is not defined

let a = "good"
复制代码

const定义的常亮是不能被修改的

const a = "good";
a = "bad";
console.log(a);//Assignment to constant variable.复制代码

箭头函数

函数的快捷写法。不需要function关键字来创建函数,省略return关键字,继承当前上下文的this关键字。

拿ES5和ES6函数举个栗子。

//ES5
var arr = [1, 2, 3, 4];var newArr = arr.map(function(x) {    return x + 1;});console.log(newArr);//[ 2, 3, 4, 5 ]
//ES6
var arr = [1, 2, 3, 4];var newArr = arr.map(x => {    return x + 1;});console.log(newArr);//[ 2, 3, 4, 5 ]复制代码

箭头函数小细节:当你的函数有且仅有一个参数的时候是可以省略掉括号的,当你的函数有且仅有一个表达式的时候可以省略{};

var arr = [1, 2, 3, 4];var newArr = arr.map(x =>x+1);console.log(newArr);复制代码

js中的this对象是个有毒的东西,看一个例子。

var obj = {    name: "xing",    fn1: function() {        console.log(this);    },    fn2: function() {        console.log(this);        setTimeout(function() {            console.log(this);        }, 1000);    }};obj.fn2();复制代码

发现两次打印出来的东西不一样。第一次打印this指的对象为obj,第二次打印执行的是setTimeout计时器中的函数,this.fn1作为计时器中的函数体。因为计时器为异步操作,所以计时器中的this所指为全局对象window。

所以为了解决这个问题,我们采用闭包的特性来处理。

var obj = {    name: "xing",    fn1: function() {        console.log(this);    },    fn2: function() {        console.log(this);        var _this = this;        setTimeout(function() {            console.log(_this.fn1);        }, 1000);    }};obj.fn2();复制代码

我们可以先用一个变量_this来存储指向对象obj的this,此时_this指向obj,然后在计时器回调函数中调用我们所定义的变量_this,此时所指的对象就是obj。

模板字符串

解决了ES5在字符串功能上的缺陷。

第一个用途:字符串拼接。将表达式嵌入字符串进行拼接,用`和${}`来界定。

ES5
var name = "牛郎";console.log(name+"&&织女");//牛郎&&织女
ES6
var name = "牛郎";console.log(`${name}&&织女`);//牛郎&&织女复制代码

第二个用途:在ES5时我们通过反斜杠来做多行字符串拼接。ES6中通过``支持换行并且不需要额外的处理。

ES5
var msg = "hello \girl";
console.log(msg);//hello girlES6var msg = `hi,girl.`console.log(msg);
//hi,girl.复制代码

字符串

ES6更新了许多新的对于字符串的函数,比如includes()repeat()startsWith,endsWith,padStart,padEnd

.includes()判断是否包含然后直接返回布尔值

var str = "xing";console.log(str.includes("i"));//true复制代码

.repeat(N)获取字符串重复N次

var s= "ha";console.log(s.repeat(3));//hahaha复制代码

startsWith

var str = "abc def";console.log(str.startsWith("abc"));      //trueconsole.log(str.startsWith("abcd"));     //false复制代码

endsWith

var str = "abc def";console.log(str.endsWith("def"));      //trueconsole.log(str.endsWith("abcd"));     //false复制代码

padEnd和padStart

var str = "abc def";console.log(str.padStart(15, "!*"));  //!*!*!*!*abc defconsole.log(str.padEnd(15, "!*"));    //abc def!*!*!*!*复制代码

解构

自动解析数组或对象中的值。比如若一个函数要返回多个值,常规的做法是返回一个对象,将每个值做为这个对象的属性返回。但在ES6中,利用解构这一特性,可以直接返回一个数组,然后数组中的值会自动被解析到对应接收该值的变量中。

var [x, y] = getVal(),    [name, , age] = getMsg();
function getVal() {    return [1, 2];}function getMsg() {    return ["xing", "care", "21"];}console.log(`x:${x},y:${y}`);//x:1,y:2console.log(`name:${name},  age:${age}`);//name:xing,  age:21
复制代码

增强的对象字面量

在ES6中,对象字面量被加强了,写法更加简洁与灵活,同时在定义对象的时候能够做的事情更多了。

  • 可以在对象字面量里面定义原型
  • 定义方法可以不用function关键字
  • 直接调用父类方法

var father = {    say() {        console.log("11111111111");    }};var son = {    __proto__: father,//设置此对象的原型是father,相当于继承father    name: "xiaoMing",    work() {        console.log("22222222222222");    }};father.say();//11111111111son.say();//11111111111复制代码

类class

在ES5中最令人头的部分:原型,构造函数,继承,在ES6中引入了Class(类)的概念。

JS本身就是面向对象的,ES6中提供的类实际上只是原型模式的包装。现在提供原生的class支持后,对象的创建和继承更加直观了,并且父类方法的调用、实例化静态方法和构造函数等概念都更加形象化。

class Animal {    constructor(name) {//ES6中新型的构造器        this.name = name;    }    say() {        console.log(`我是一只${this.name}`);    }}
class Dog extends Animal {    constructor(name) {        super(name);//直接调用父类构造器进行初始化    }    bark() {        console.log("5555555555555");    }}var animal = new Animal("cat"),    dog = new Dog("dog");animal.say();//我是一只catdog.say();//我是一只dogdog.bark();//5555555555555
复制代码

参数新特性

默认参数值

现在可以在定义函数的时候指定参数的默认值,而不用像以前那样通过逻辑或操作符来达目的了。

function say(name = "girl"){    console.log(`Hello ${name}`);}say();//Hello girlsay("man");//Hello man复制代码

不定参数

不定参数是在函数中使用命名参数同时接受不定数量的未命名参数。这只是一种语法糖,在以前的JavaScript代码中我们可以通过arguments变量来达到这一目的。不定参数的格式是三个句点后跟代表所有不定参数的变量名。比如下面这个例子中,…x代表了所有传入add函数的参数。

function add(...x){    return x.reduce((m,n)=>m+n);}console.log(add(1,2,3));//输出:6console.log(add(1,2,3,4,5));//输出:15复制代码

拓展参数

拓展参数则是另一种形式的语法糖,它允许传递数组或者类数组直接做为函数的参数而不用通过apply

var people = ["one", "two", "three","four","five"];function say(people1, people2, people3) {    console.log(`Hello ${people1},${people2},${people3}`);}
//我们将一个数组以拓展参数的形式传递,它能很好地映射到每个单独的参数say(...people);//Hello one,two,three//而在以前,如果需要传递数组当参数,我们需要使用函数的apply方法say.apply(null, people); //Hello one,two,three复制代码

for of  值遍历

我们知道for in循环遍历数组,类数组和对象,ES6中新引入的for of循环功能相似,不同的是每次循环它提供的不是序号而是值。

var arr = [1, 2, 3, 4];for (var a of arr) {    console.log(a);}
//输出
1234复制代码

Map,Set

这些是新加的集合类型, 提供了更加方便的获取属性值的方法,不用像以前一样用hasOwnProperty来检查某个属性是属于原型链上的呢还是当前对象的。同时,在进行属性值添加与获取时有专门的getset 方法。

set

还是举个栗子来的实在。

var s = new Set();s.add("hello")    .add("goodbye")    .add("goodbye")    .add("goodbye")    .add("hello2")    .add("hello3")    .add("hello4")    .add("hello5");//删除set中的一个元素s.delete("goodbye");

//遍历set集合for (var p of s) {    console.log(p);}console.log(s.size); console.log(s.has("hello")); console.log(Array.isArray(s));
//输出:
hellohello2hello3hello4hello55truefalse复制代码

  • 可以看出来set里面的值是唯一的没有重复的,利用这点可以做到数组去重。
  • set不是数组,是一个像对象的数组,是个伪数组

map

var m = new Map([["name", "xing"], [1, 234]]);m.set(false, "abc");m.set([1, 2, 3], { year: "2018" });console.log(m.get("name"));       //xingconsole.log(m.get(1));            //234console.log(m.get(false));        //abcconsole.log(m.get([1,2,3]));      //undefined复制代码

  • 它类似与对象,里面存放的也是键值对,区别在于:对象中的键名只能是字符串,如果使用map,它里面的键可以使任意值。
  • 通过get("键名")获取值是里面不能是数组,因为get()要比较栈中的地址,而不是堆区中的数据
  • 重复的数据会覆盖。

严格模式

之前学习的JS,语法非常灵活,JS中这个灵活的特性,弊大于先利。后来增加了严格模式。

使用严格模式的目的:规则,提高编译效率。

启动严格模式 "use strict"

严格模式和非严格模式有什么区别:

在严格模式下不能使用没有var的变量


在严格模式下不能使用8进制的数字


在严格模式下不能把函数定义在if语句中


在严格模式下函数不能有重名的形参


在严格模式下arguments不再跟踪形参的变化

"use strict"    function fn(a, b) {        console.log(a, b);        console.log(arguments[0], arguments[1]);        arguments[0] = 11111;        arguments[1] = 222222;        console.log(a, b);        console.log(arguments[0], arguments[1]);    }    fn(1, 2)
输出://
1 21 21 211111 222222复制代码

在严格模式下function中的this指向的不是window

    "use strict"    function f() {        console.log(this);    }    f();//undefined复制代码

promise

Promise 可以让我们远离平行的代码(回调地狱):

func1(function(value1) {    func2(value1, function(value2) {        func3(value2, function(value3) {            func4(value3, function(value4) {                func5(value4, function(value5) {                    // Do something with value 5                });            });        });    });});复制代码

func1(value1)    .then(func2)    .then(func3)    .then(func4)    .then(func5, value5 => {});
复制代码
  • 用同步的方式去写异步代码
  • 没有异步就不需要 promise。
  • Promise 本身不是异步,只是我们去编写异步代码的一种方式。

四大术语

一定要结合异步操作来理解。
既然是异步,这个操作需要有个等待的过程,从操作开始,到获取结果,有一个过程的。
1、解决(fulfill :指一个 promise 成功时进行的一系列操作,如状态的改变、回调的执行。
虽然规范中用 fulfill 来表示解决,但在后世的 promise 实现多以 resolve 来指代之。
2拒绝(reject :指一个 promise 失败时进行的一系列操作。
3、 终值(eventual value :所谓终值,指的是 promise 被解决时传递给解决回调的值,由于
promise 有一次性的特征,因此当这个值被传递时,标志着 promise 等待态的结束,故称
之终值,有时也直接简称为值(value)。
4、据因(reason :也就是拒绝原因,指在 promise 被拒绝时传递给拒绝回调的值。

三种状态

在异步操作中有三个状态。
当操作发出时对象处于等待状态(等待态 Pending),当操作完成是,结果有两种,操作成功(执行态 Fulfilled)或者操作失败( 拒绝态 Rejected ),

两种事件

针对三种状态,只有如下两种转化方式

在状态转换的时候,就会触发事件。
  •  如果是 pending --> fulfiied,就会触发 onFulFilled 事件
  •  如果是 pendeing --> rejected,就会触发 onRejected 事件

一个对象

就是指 promise 对象


在状态转换的时候,就会触发事件

如果是 pending --> fulfiied,就会触发 onFulFilled 事件
如果是 pendeing --> rejected,就会触发 onRejected 事件

Promise 对象提供了 then 方法

Promise.then(onFulFilled,onRejected)

参数作为两个回调函数

p.then(    function(res) {        console.info(res);    },    function(err) {        console.info(err);    });复制代码

针对 onFulFilled,会自动提供一个参数,作为终值value(res)

针对 onRejected,会自动提供一个参数,作为据因reason(err)

其中第二个回调表示 从 pending ---> rejected 时的回调。

由于这种写法,辨识度不高。Promise 就提供了一个 catch 方法,用于注册 onRejected 回调。


p.then(function(res) {    console.info(res);}).catch(function(err) {    console.info(err);});复制代码

catch其实是then的简写,then方法调用后返回的还是promise 对象,所以可以链式调用,如下。

p.then(res => console.info(res)).catch(err => console.info(err));复制代码

简单的理解意思就是,我们在使用promise对象,异步操作成功的时候走then,失败的时候走catch

解析一个例子

const fs = require("fs");var p = new Promise(function(resolve, reject) {    fs.readFile("./MyTest/SelfTest/data.txt", "utf8", (err, data) => {        if (err) {            reject(err);        } else {            resolve(data);        }    });});p.then(res => console.info(res)).catch(err => console.info(err));复制代码

使用node的fs模块来读取文件
创建promise对象,当前对象处在pedding状态
回调函数中的两个参数作用是用于状态的转换
resolve,将状态从 pending --> fullFilled
reject,将状态从 pending --> rejected
resolve函数的参数指的是 终值(res)
reject函数的参数指的是 据因(err)

所以读取文件成功的话则打印文本数据data,失败的则打印错误原因err

Symbols

我们知道对象其实是键值对的集合,而键通常来说是字符串。而现在除了字符串外,我们还可以用symbol这种值来做为对象的键。Symbol是一种基本类型,像数字,字符串还有布尔一样,它不是一个对象。Symbol 通过调用symbol函数产生,它接收一个可选的名字参数,该函数返回的symbol是唯一的。之后就可以用这个返回值做为对象的键了。Symbol还可以用来创建私有属性,外部无法直接访问由symbol做为键的属性值。

var key = Symbol("key");function MyClass(privateData) {    this[key] = privateData;}MyClass.prototype = {    doStuff: function() {        this[key];    }};var c = new MyClass("hello");console.log(c.key);//undefined无法访问该属性,因为是私有的复制代码

Symbol() 的一个使用情况是给一个类或者命名空间打上补丁,但是可以确定的是你不会去更新它。比如,你想给 React.Component 类添加一个 refreshComponent 方法,但是可以确定的是你不会在之后更新这个方法:

const refreshComponent = Symbol();
React.Component.prototype[refreshComponent] = () => {
    // do something
    }复制代码
本文同时借鉴网路一些大神,如有冒犯,吾定改之。-^_^-


你可能感兴趣的:(javascript)