码迷,mamicode.com
首页 > 其他好文 > 详细

ES6基础知识

时间:2019-07-24 22:51:44      阅读:204      评论:0      收藏:0      [点我收藏+]

标签:win   pack   异常   方法   数组去重   安装   war   dde   typeof   

一、声明 let、const

1. let

1). 作用域是块级作用域(在ES6之前,js只存在函数作用域以及全局作用域)

if(1){
  let a=1;
  console.log(a)
}

2). 不存在变量声明提前;

console.log(b); //ReferenceError: b is not defined
let b=2;

3). 不能重复定义

let a=1;
let a=2;
console.log(a);//Identifier ‘a‘ has already been declared

4). 存在暂时性死区:可以这样来理解

var a=1if(1){
 console.log(a); 
  let a=2;
}

① 在一个块级作用域中,变量唯一存在,一旦在块级作用域中用let声明了一个变量,那么这个变量就唯一属于这个块级作用域,不受外部变量的影响;

② 无论在块中的任何地方声明了一个变量,那么在这个块级作用域中,任何使用这个名字的变量都是指这个变量,无论外部是否有其他同名的全局变量;

③ 暂时性死区的本质就是,只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量。

④ 暂时性死区的意义:让我们标准化代码。将所有的变量的声明放在作用域的最开始。

2.  const

const一般用来声明常量,且声明的常量是不允许改变的,只读属性,因此就要在声明的同时赋值。const与let一样,都是块级作用域,存在暂时性死区,不存在变量声明提前,不允许重复定义

const A=1;//重新给常量A赋值会报错 
A=3;// Uncaught TypeError: Assignment to constant variable.
//错误:赋值给常量

二、解构赋值(es6允许按照一定的模式,从数组或对象中提取值,给变量进行赋值)

//解构赋值,两边格式要一致
let [a,b,c] = [1,2,3];let [a,[b,c]] = [1,[2,3]];
//交互数据
let a = 10;
let b = 20;
[a,b] = [b,a];

三、声明类与继承:class、extend

用class关键字定义对象类型,用extends关键字实现继承

const private2 = Symbol(‘I am symbol value‘)
class A {
   a1 = ‘1‘  // ES7 实例属性,需要new实例来访问, ES6规定class没有静态属性,只有静态方法所以只能在constructor中定义属性
   static a2 = ‘2‘  // ES7的静态属性,直接 A.a2 访问,不需要new实例
   getA1() {
         return  this.a1      // this指向new实例
   }
   static  getA2() {
        return   ‘2’    // 静态方法
   }
   constructor(name) {
         //一定要有构造方法,如果没有默认生成空构造方法
        this.a3 = ‘3‘   // 这里定义实例属性
        this.name = name
    }

   // 私有方法写法
   publicMethod() {
         private1()    // 私有方法1,可以写在class体外
         private2()   // 利用Symbol值来定义
   }
   [private2]() {
       // 这里是私有方法
   }
}
const private1 = function() { // 这里也是私有方法,但别export出去}
// 最后export class
export default A

// 通过extends继承
class B extends A{
    constructor() {
      // 一定要在构造函数的第一句调用super
      super()    // 这是调用父类的构造方法
      this.b1 = ‘11‘
      this.b2 = super.a1    // super直接调用时指向父类构造方法,范围属性时,指向父类实例,或调用父类静态方法
    }
}

四、Promise的使用与实现

Promise是JS异步编程中的重要概念,异步抽象处理对象,是目前比较流行Javascript异步编程解决方案之一。

1. Promise 处理多个相互关联的异步请求

const request = url => { 
    return new Promise((resolve, reject) => {
        $.get(url, data => {
            resolve(data)
        });
    })
};

// 请求data1
request(url).then(data1 => {
    return request(data1.url);   
}).then(data2 => {
    return request(data2.url);
}).then(data3 => {
    console.log(data3);
}).catch(err => throw new Error(err));

2. Promise使用

2.1 Promise 是一个构造函数, new Promise 返回一个 promise对象 接收一个excutor执行函数作为参数, excutor有两个函数类型形参resolve reject

const promise = new Promise((resolve, reject) => {
       // 异步处理
       // 处理结束后、调用resolve 或 reject
});

2.2 promise相当于一个状态机

promise的三种状态

  • pending
  • fulfilled
  • rejected

①promise 对象初始化状态为 pending
②当调用resolve(成功),会由pending => fulfilled
③当调用reject(失败),会由pending => rejected

注意:promsie状态 只能由 pending => fulfilled/rejected, 一旦修改就不能再变

2.3 promise对象方法

1)then方法注册 当resolve(成功)/reject(失败)的回调函数,then方法是异步执行的

// onFulfilled 是用来接收promise成功的值
// onRejected 是用来接收promise失败的原因
promise.then(onFulfilled, onRejected);

2)resolve(成功) onFulfilled会被调用

const promise = new Promise((resolve, reject) => {
   resolve(‘fulfilled‘); // 状态由 pending => fulfilled
});
promise.then(result => { // onFulfilled
    console.log(result); // ‘fulfilled‘ 
}, reason => { // onRejected 不会被调用
    
})

3)reject(失败) onRejected会被调用

const promise = new Promise((resolve, reject) => {
   reject(‘rejected‘); // 状态由 pending => rejected
});
promise.then(result => { // onFulfilled 不会被调用
  
}, reason => { // onRejected 
    console.log(rejected); // ‘rejected‘
})

4)promise.catch

在链式写法中可以捕获前面then中发送的异常

promise.catch(onRejected)
相当于
promise.then(null, onRrejected);

// 注意
// onRejected 不能捕获当前onFulfilled中的异常
promise.then(onFulfilled, onRrejected); 

// 可以写成:
promise.then(onFulfilled)
       .catch(onRrejected); 

3. promise chain

promise.then方法每次调用 都返回一个新的promise对象 所以可以链式写法

function taskA() {
    console.log("Task A");
}
function taskB() {
    console.log("Task B");
}
function onRejected(error) {
    console.log("Catch Error: A or B", error);
}

var promise = Promise.resolve();
promise
    .then(taskA)
    .then(taskB)
    .catch(onRejected) // 捕获前面then方法中的异常

4. Promise的静态方法

1)Promise.resolve 返回一个fulfilled状态的promise对象

Promise.resolve(‘hello‘).then(function(value){
    console.log(value);
});

Promise.resolve(‘hello‘);
// 相当于
const promise = new Promise(resolve => {
   resolve(‘hello‘);
});

2)Promise.reject 返回一个rejected状态的promise对象

Promise.reject(24);
new Promise((resolve, reject) => {
   reject(24);
});

3)Promise.all 接收一个promise对象数组为参数

只有全部为resolve才会调用 通常会用来处理 多个并行异步操作

const p1 = new Promise((resolve, reject) => {
    resolve(1);
});

const p2 = new Promise((resolve, reject) => {
    resolve(2);
});

const p3 = new Promise((resolve, reject) => {
    reject(3);
});

Promise.all([p1, p2, p3]).then(data => { 
    console.log(data); // [1, 2, 3] 结果顺序和promise实例数组顺序是一致的
}, err => {
    console.log(err);
});

4)Promise.race 接收一个promise对象数组为参数

Promise.race 只要有一个promise对象进入 FulFilled 或者 Rejected 状态的话,就会继续进行后面的处理

function timerPromisefy(delay) {
    return new Promise(function (resolve, reject) {
        setTimeout(function () {
            resolve(delay);
        }, delay);
    });
}
var startDate = Date.now();
Promise.race([
    timerPromisefy(10),
    timerPromisefy(20),
    timerPromisefy(30)
]).then(function (values) {
    console.log(values); // 10
});

5. promise实现

/**
 * 摘自https://www.cnblogs.com/minigrasshopper/p/9141307.html
 * Promise类实现原理
 * 构造函数传入一个function,有两个参数,resolve:成功回调; reject:失败回调
 * state: 状态存储 [PENDING-进行中 RESOLVED-成功 REJECTED-失败]
 * doneList: 成功处理函数列表
 * failList: 失败处理函数列表
 * done: 注册成功处理函数
 * fail: 注册失败处理函数
 * then: 同时注册成功和失败处理函数
 * always: 一个处理函数注册到成功和失败
 * resolve: 更新state为:RESOLVED,并且执行成功处理队列
 * reject: 更新state为:REJECTED,并且执行失败处理队列
**/

class PromiseNew {
  constructor(fn) {
    this.state = ‘PENDING‘;
    this.doneList = [];
    this.failList = [];
    fn(this.resolve.bind(this), this.reject.bind(this));
  }

  // 注册成功处理函数
  done(handle) {
    if (typeof handle === ‘function‘) {
      this.doneList.push(handle);
    } else {
      throw new Error(‘缺少回调函数‘);
    }
    return this;
  }

  // 注册失败处理函数
  fail(handle) {
    if (typeof handle === ‘function‘) {
      this.failList.push(handle);
    } else {
      throw new Error(‘缺少回调函数‘);
    }
    return this;
  }

  // 同时注册成功和失败处理函数
  then(success, fail) {
    this.done(success || function () { }).fail(fail || function () { });
    return this;
  }

  // 一个处理函数注册到成功和失败
  always(handle) {
    this.done(handle || function () { }).fail(handle || function () { });
    return this;
  }

  // 更新state为:RESOLVED,并且执行成功处理队列
  resolve() {
    this.state = ‘RESOLVED‘;
    let args = Array.prototype.slice.call(arguments);
    setTimeout(function () {
      this.doneList.forEach((item, key, arr) => {
        item.apply(null, args);
        arr.shift();
      });
    }.bind(this), 200);
  }

  // 更新state为:REJECTED,并且执行失败处理队列
  reject() {
    this.state = ‘REJECTED‘;
    let args = Array.prototype.slice.call(arguments);
    setTimeout(function () {
      this.failList.forEach((item, key, arr) => {
        item.apply(null, args);
        arr.shift();
      });
    }.bind(this), 200);
  }
}

// 下面一波骚操作
new PromiseNew((resolve, reject) => {
  resolve(‘hello world‘);
  // reject(‘you are err‘);
}).done((res) => {
  console.log(res);
}).fail((res) => {
  console.log(res);
})

五、generator(异步编程、yield、next()、await 、async)

使用Generator可以很方便的帮助我们建立一个处理Promise的解释器;

async/await这样的语法,可以让我们以接近编写同步代码的方式来编写异步代码(无需使用.then()或者回调函数)

1. Generator

Generator是一个函数,可以在函数内部通过yield返回一个值(此时,Generator函数的执行会暂定,直到下次触发.next()) 创建一个Generator函数的方法是在function关键字后添加*标识。

在调用一个Generator函数后,并不会立即执行其中的代码,函数会返回一个Generator对象,通过调用对象的next函数,可以获得yield/return的返回值。 无论是触发了yield还是returnnext()函数总会返回一个带有valuedone属性的对象。 value为返回值,done则是一个Boolean对象,用来标识Generator是否还能继续提供返回值。 P.S. Generator函数的执行时惰性的,yield后的代码只在触发next时才会执行。

function * oddGenerator () {
  yield 1
  yield 3
  return 5
}
let iterator = oddGenerator()
let first = iterator.next()  // { value: 1, done: false }
let second = iterator.next() // { value: 3, done: false }
let third = iterator.next()  // { value: 5, done: true  }

2. Async

function getRandom () {
  return new Promise(resolve => {
    setTimeout(_ => resolve(Math.random() * 10 | 0), 1000)
  })
}

async function main () {
  let num1 = await getRandom()
  let num2 = await getRandom()

  return num1 + num2
}

console.log(`got data: ${await main()}`)

Async函数始终返回一个Promise

async function throwError () {
  throw new Error()
}
async function returnNumber () {
  return 1
}

console.log(returnNumber() instanceof Promise) // true
console.log(throwError() instanceof Promise)   // true

Await是按照顺序执行的,并不能并行执行,JavaScript是单线程的,这就意味着await一只能一次处理一个,如果你有多个Promise需要处理,则就意味着,你要等到前一个Promise处理完成才能进行下一个的处理,这就意味着,如果我们同时发送大量的请求,这样处理就会非常慢。

function delay () {
  return new Promise(resolve => setTimeout(resolve, 1000))
}

let tasks = [1, 2, 3, 4]

//要4s才能执行完
async function runner (tasks) {
  for (let task of tasks) {
    await delay()
  }
}
//优化,缩短执行时间
async function runner (tasks) {
  tasks = tasks.map(delay)
  await Promise.all(tasks)
}

console.time(‘runner‘)
await runner(tasks)
console.timeEnd(‘runner‘)

Generatorasync function都是返回一个特定类型的对象:

  • Generator: 一个类似{ value: XXX, done: true }这样结构的Object
  • Async: 始终返回一个Promise,使用await或者.then()来获取返回值

Generator是属于生成器,一种特殊的迭代器,用来解决异步回调问题感觉有些不务正业了。。 而async则是为了更简洁的使用Promise而提出的语法,相比Generator + co这种的实现方式,更为专注,生来就是为了处理异步编程。

六、箭头函数this指向问题、拓展运算符

// 两个参数:
(x, y) => x * x + y * y

// 无参数:
() => 3.14

// 可变参数:
(x, y, ...rest) => {
    var i, sum = x + y;
    for (i=0; i<rest.length; i++) {
        sum += rest[i];
    }
    return sum;
}

1. 不绑定this

var obj = {
   age: 1,
   say: function() {
      setTimeout(function() {
         console.log(this, this.age); // window undefined
      }, 0);
   },
}
var obj1 = {
   age: 1,
   say: function() {
      setTimeout(() => {
         console.log(this, this.age); // obj1 1
      }, 0);
   }
};

这里可以看出箭头函数中访问的this实际上是其父级作用域中的this,箭头函数本身的this是不存在的,这样就相当于箭头函数的this是在声明的时候就确定了(即this总是指向词法作用域,也就是外层调用者handler),这个特性是很有用的,所以,call()或者apply()调用箭头函数时,无法对this进行绑定,即传入的第一个参数被忽略。

var handler = {
   id: ‘111‘,
   doSomething: function(e) {
       console.log(e);
   },
   init: function() {
      document.addEventListener(‘click‘, (event) => { // 这里绑定事件,函数this就可以访问到handler的方法doSomething
         this.doSomething(event);
      }, false);
   }
}
handler.init();

2. 不可以作为构造函数来使用

var Person = (name) => { // Uncaught TypeError: Person is not a constructor
    this.name = name;
}
var person = new Person(‘Jack‘);

3. 不绑定arguments(如果有要使用arguments的时候可以使用rest参数代替)

var foo = (val) => {
    console.log(arguments); // Uncaught ReferenceError: arguments is not defined
};
foo();
//这个特性也很好测试,但是实在要使用arguments对象要怎么办呢?我们可以使用es6的另一个新特性rest参数,完美替代
var foo = (...args) => {
    console.log(args); // [1, 2, 3]
};
foo(1, 2, 3);

4. 不可以使用yield命令,因此箭头函数不能用作Generator函数

七、map和set有没有用过,如何实现一个数组去重,map数据结构有什么优点?

JavaScript的默认对象表示方式{}可以视为其他语言中的MapDictionary的数据结构,即一组键值对。但是JavaScript的对象有个小问题,就是键必须是字符串。但实际上Number或者其他数据类型作为键也是非常合理的。为了解决这个问题,最新的ES6规范引入了新的数据类型Map。

Map的遍历

  • keys():返回键名的遍历器。
  • values():返回键值的遍历器。
  • entries():返回所有成员的遍历器。
  • forEach():遍历 Map 的所有成员。
  • 需要特别注意的是,Map 的遍历顺序就是插入顺序
var m = new Map([[‘Michael‘, 95], [‘Bob‘, 75], [‘Tracy‘, 85]]);
m.get(‘Michael‘); // 95

//初始化Map需要一个二维数组,或者直接初始化一个空Map。Map具有以下方法:
var m = new Map(); // 空Map
m.set(‘Adam‘, 67); // 添加新的key-value
m.set(‘Bob‘, 59);
m.has(‘Adam‘); // 是否存在key ‘Adam‘: true
m.get(‘Adam‘); // 67
m.delete(‘Adam‘); // 删除key ‘Adam‘
m.get(‘Adam‘); // undefined
//由于一个key只能对应一个value,所以,多次对一个key放入value,后面的值会把前面的值冲掉
//遍历Map
var m = new Map([[1, ‘x‘], [2, ‘y‘], [3, ‘z‘]]);
m.forEach(function (value, key, map) {
    console.log(value);
});

SetMap类似,也是一组key的集合,但不存储value。由于key不能重复,所以,Set中,没有重复的key

//要创建一个Set,需要提供一个Array作为输入,或者直接创建一个空Set:
var s1 = new Set(); // 空Set
var s2 = new Set([1, 2, 3]); // 含1, 2, 3

//重复元素在Set中自动被过滤:
var s = new Set([1, 2, 3, 3, ‘3‘]);
s; // Set {1, 2, 3, "3"}

//通过add(key)方法可以添加元素到Set中,可以重复添加,但不会有效果:
s.add(4);
s; // Set {1, 2, 3, 4}
s.add(4);
s; // 仍然是 Set {1, 2, 3, 4}

//通过delete(key)方法可以删除元素:
var s = new Set([1, 2, 3]);
s; // Set {1, 2, 3}
s.delete(3);
s; // Set {1, 2}

//遍历Set
var s = new Set([‘A‘, ‘B‘, ‘C‘]);
s.forEach(function (element, sameElement, set) {
    console.log(element);
});

数组去重

//1.for循环嵌套,利用splice去重
function newArr(arr){
    for(var i=0;i<arr.length;i++){
        for(var j=i+1;j<arr.length;j++)
            if(arr[i]==arr[j]){ 
            //如果第一个等于第二个,splice方法删除第二个
            arr.splice(j,1);
            j--;
            }
        }
    }
    return arr;
}
var arr = [1,1,2,5,6,3,5,5,6,8,9,8];
console.log(newArr(arr))

//2.建新数组,利用indexOf去重
function newArr(array){ 
    //一个新的数组 
    var arrs = []; 
    //遍历当前数组 
    for(var i = 0; i < array.length; i++){ 
        //如果临时数组里没有当前数组的当前值,则把当前值push到新数组里面 
        if (arrs.indexOf(array[i]) == -1){ 
            arrs.push(array[i])
        }; 
    } 
    return arrs; 
}
var arr = [1,1,2,5,5,6,8,9,8];
console.log(newArr(arr))

//3.ES6中利用Set去重
function newArr(arr){
    return Array.from(new Set(arr))
}
var arr = [1,1,2,9,6,9,6,3,1,4,5];
console.log(newArr(arr))

八、ES6怎么编译成ES5,css-loader原理,过程

现在的Chrome浏览器已经支持ES6了,但是有些低版本的浏览器还是不支持ES6的语法,这就需要我们把ES6的语法自动的转变成ES5的语法。Webpack是有自动编译转换能力的,除了Webpack自动编译,还可以使用用Babel来完成。

  • 初始化项目
    打开终端或者通过cmd打开命令行工具,进入项目目录,输入下边的命令:
     npm init -y 
    -y代表全部默认同意,就不用一次次按回车了。命令执行完成后,会在项目根目录下生产package.json文件。
{
  "name": "es6",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

可以根据自己的需要进行修改,比如我们修改name的值为es6。

  • 全局安装Babel-cli
     npm install -g babel-cli 
  • 本地安装babel-preset-es2015 和 babel-cli
     npm install --save-dev babel-preset-es2015 babel-cli 
  • 新建.babelrc
    在根目录下新建.babelrc文件,并打开录入下面的代码
{
    "presets":[
        "es2015"
    ],
    "plugins":[]
}

这个文件我们建立完成后,现在可以在终端输入的转换命令了,这次ES6成功转化为ES5的语法。 babel dist/index.js -o src/index.js 

  • 简化转化命令:
    在学习vue 的时候,可以使用npm run build 直接利用webpack进行打包,在这里也希望利用这种方式完成转换。打开package.json文件,把文件修改成下面的样子。
{
  "name": "es6",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "build": "babel src/index.js -o dist/index.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "babel-cli": "^6.24.1",
    "babel-preset-es2015": "^6.24.1"
  }
}

修改好后,以后我们就可以使用  npm run build  来进行转换了。

webpack的loaders是一块很重要的组成部分。我们都知道webpack是用于资源打包的,里面的所有资源都是“模块”,内部实现了对模块资源进行加载的机制。但是Webpack本身只能处理 js模块,如果要处理其他类型的文件,就需要使用 loader 进行转换。 

Loader 可以理解为是模块和资源的转换器,它本身是一个函数,接受源文件作为参数,返回转换的结果,例如可以使用loader加载器可以快速编译预处理器(less,sass,coffeeScript)。 Loader 可以在require()引用模块的时候添加,也可以在 webpack 全局配置中进行绑定,还可以通过命令行的方式使用。

loader的特性是: 

  • loaders可以串联,他们应用于管道资源,最后的loader将返回javascript,其它的可返回任意格式(传递给下一个loader)
  • loaders 可以同步也可以异步
  • loaders在nodejs下运行并且可以做一切可能的事 loader接受参数,可用于配置里 
  • loaders可以绑定到extension/RegExps 配置 
  • loaders可以通过npm发布和安装 正常的模块儿可以到处一个
  • loader除了 loaders可以访问配置 插件可以给loaders更多的特性
  • loaders可以释放任意额外的文件
本部分摘自链接:https://www.jianshu.com/p/059c5b68d9d5

九、ES6转成ES5的常见例子

//摘自博客:https://blog.csdn.net/qq_42149830/article/details/88295747
function _defineProperties(target,prop){
        prop.forEach(ele => {        //可能会传入多个属性
            Object.defineProperty(target,ele.key,{
                value:ele.value,
                writable:true,
                configurable:true,
            })
        });//设置所设置的属性是否可写,可枚举
}

function _createClass(_constructor,_prototypeProperties,_staticProperties){ //这里传入的三个参数分别是构造函数,原型上的属性,静态属性
    if(_prototypeProperties){   //设置公有属性
        _defineProperties(_constructor.prototype,_prototypeProperties)
    }
    if(_staticProperties){  //设置静态属性
        _defineProperties(_constructor,_staticProperties)
    }
}

function _classCallCheck(_this,_constructor){
    if(!(_this instanceof _constructor)){     //判断是否是通过new(创建实例)来调用_constructor
            throw "TypeError: Class constructor AirPlane cannot be invoked without ‘new‘"
    }
}
var FatherPlane=(function(){
    function FatherPlane(name,color){
        _classCallCheck(this,FatherPlane)
        this.name=name||‘liu‘;
        this.color=color||‘red‘
    }
    _createClass(FatherPlane,[
        {
            key:‘fly‘,
            value:function(){
                console.log(‘fly‘)
            }
        }
    ],[
        {
           key:‘static‘,
           value:function(){
               console.log(‘static‘)
           } 
        }
    ])
    return FatherPlane;
})()
var airplane=new FatherPlane()

ES6基础知识

标签:win   pack   异常   方法   数组去重   安装   war   dde   typeof   

原文地址:https://www.cnblogs.com/lxy-starry/p/11239376.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!