es6 基础知识点总结

es6 基础知识点总结

      • let 关键字:
      • const 关键字:
      • 常见面试题: var, let 和const 三者的区别
      • es5 数组的遍历(迭代)方式
      • es6的箭头函数
      • es6的解构赋值
      • es6的类和继承
      • Symbol() 数据类型
      • Set() 数据结构
      • for-of 遍历 : 遍历部署了 [Symbol.iterator] 属性的数据
      • Iterator迭代器 (接口)
      • Map 数据结构
      • Promise() 对象
      • Promise() (承诺)基本代码逻辑
      • async 函数 和 await
      • async 和await 的异常捕获
      • 宏任务和微任务
      • Object.defineProperty(): 数据拦截(数据劫持)
      • es6 的 Proxy() 代理器
      • es6 的模块

let 关键字:

  1. 声明的变量是块级作用域
  2. 不允许重复声明变量
  3. 不存在变量提升
for(let i = 0; i < 5; i++){
    setTimeout(() =>{
        console.log(i)
    }, 1000)
}

const 关键字:

  1. 声明的是块级作用域
  2. 不允许重复声明变量
  3. 不存在变量提升
  4. 声明的是一个常量(基本数据类型):本质 是 存放变量的内存地址不允许更改; 基本数据类型的数据和地址存放在栈中(存放在一起的), 因此变成常量, 常量不允许更改; 但是对于引用数据类型, 栈中存放的是地址(指针),地址指向堆内存空间,声明一个引用数据类型作为常量时, 相当于是固定了指针, 而不能固定数据

常见面试题: var, let 和const 三者的区别

  1. var 存在变量提升机制, let和const 不存在变量提升
  2. var 允许重复声明变量, let和const不允许重复声明变量
  3. var 声明的变量值可以随意更改,const 声明的是常量,不允许更改
  4. var 声明的变量会产生内存泄露,let 和 const 不会
  5. var 声明的变量是全局作用域或者局部作用域, let 和 const声明的变量是块级作用域

es5 数组的遍历(迭代)方式

以下两种循环方式可以使用 break 和continue 语句

  1. for循环
  2. for-in循环:可以遍历数组, 但是他最主要的功能是遍历对象
    ————————————————————————————
    以下几种遍历方式不可以使用 break 和continue 语句
    错误信息: Uncaught SyntaxError: Illegal break statement
    错误信息: Uncaught SyntaxError: Illegal continue statement: no surrounding iteration statement
  3. forEach()
  4. map() : 映射, 返回是一个新数组
  5. some() :返回一个布尔值, true: 只要数据中有一个元素满足条件即可
  6. every(): 返回一个布尔值, true: 数据中所有的元素满足条件即可 ;
  7. reduce(function(acc, value, index){}, initValue) : 累计器 ;如果提供初始值 initValue; 则acc 就是初始值,否则是数组中的第一个元素
  8. filter() : 过滤器 ; 返回的是一个新的数组(满足条件的)

是否使用return语句

  • for循环,for-in, forEach() 他们三者不需要使用return语句
  • map() some() every() reduce() filter() 他们需要借助于return语句

es6的箭头函数

使用 => 表示箭头函数

  1. 基本结构
let fun = () => {}
  1. 一个参数: () 可以省略
let fun = (x) => {
    console.log(x)
}

let fun = x => {
    console.log(x)
}

let fun = (x, y) => {
    console.log(x, y)
}

  1. 返回值是单一的语句 : {} 可以省略, 如果返回值是对象, 需要添加 ()
let fun = x => x * x

let fun = () => ({
    name:'tom',
    age:18
})

es6的解构赋值

  1. 对象解构 : 按照对象的key(属性名)进行解构
//  按照默认键名进行解构
let {name, age} = {name:;'tom', age:18}
console.log(name, age) // tom  18

//   重新定义 解构名字 
let {name:xm, age:nl} = {name:;'tom', age:18}
console.log(xm , nl) // tom , 18
  1. 数组解构 : 按照数组的顺序(索引值) 进行解构
let arr = [10, 30, 50];
 // let [a] = arr;
let [a, , b] = arr;

//  结合 扩展运算符进行解构
let [a, ...b] = arr; // 正确   ...b 扩展运算符必须放到最后
let [...b, a] = arr;  // 错误信息:  Rest element must be last element


//  数组是按照索引值进行解构
let arr = [10, [23, 456]];
// let [a, b, c] = arr;  // a ===> 10 ;  b===> [23, 456]  c===> undefined
let [a, [b, c]] = arr; //  a ===> 10 ;  b===> 23  c===> 456
console.log(a);
console.log(b);
console.log(c);

  1. 扩展运算符的应用

    • 通过 扩展运算符 实现一维数组的深拷贝
        let arr = [10, 30, 540];
        let [...a] = arr;
        console.log(a);
        a[0] = 'hello';
        console.log(arr);
    
    • 通过 扩展运算符 实现 数组的合并
        let arr = [10, 20],
            arr2 = [30, 50];
        let res = [...arr, ...arr2]
        console.log(res);
    
    • 通过 扩展运算符 求数组中的最大值和最小值
        let arr = [10, 320, 546, 23];
        // // let max = Math.max(...arr); // 原理是对数组进行解构为单一的值作为max()的参数
        // // let min = Math.min(...arr); // 
        let max = Math.max.apply(null, arr) // 原理利用函数对象的 apply() 方法调用执行Math.max() 方法并传参 (apply方法接受数组作为参数)
        let min = Math.min.apply(null, arr)
        // console.log(max, min);
    
  2. 函数参数解构 和默认值
    通常情况下,定义了默认值的参数,应该是函数的尾参数;如果非尾部的参数设置默认值,实际上这个参数是没法省略的。

    // 为函数的参数设置默认值,即直接写在参数定义的后面
    function fun(x, y = 100){console.log(x, y)}
    fun(100) // x ===>100  y===>100
    fun(100, 200) // x ===>100  y===>200


    // 使用参数默认值时,函数不能有同名参数。
    function fun(x, x, y = 100){} // 报错


    // 参数默认值可以与解构赋值的默认值,结合起来使用。
    function foo({x, y = 5}) {
        console.log(x, y);
    }
    fun({}) // undefined 5
    fun({x:100})  // 100 5
    fun({x:100, y:300})  // 100 300 
    fun() // 报错

    // 

es6的类和继承

***通过class 定义类 ***

class Person{
    //  定义一个构造器 , 相当于我们之前讲的 构造函数  私有的属性
    constructor(name, age){
        this.name = name;
        this.age = age;
    }
    //  定义公有的方法 添加到原型对象上 
    study(){
        console.log('学习')
    }
    say(){
         console.log('hello' + this.name)
    }
}

***通过extends 继承; super()关键字 继承父类私有的属性 ***

class Student extends Person{
    //  定义一个构造器 , 相当于我们之前讲的 构造函数  私有的属性
    constructor(name, age, grade){
       super(name, age);
       this.grade = grade;
    }
    //  定义公有的方法 添加到原型对象上 
    study(){
        console.log('自己学习')
    }
}

Symbol() 数据类型

Symbol()提供了一个独一无二的值,是一个基本数据类型; 可以接受一个参数:用来区分

let count1 = Symbol('c1')
let count2 = Symbol('c2')

//  解决的问题: 对库(对象)进行扩展,又不用担心和库(对象)中的属性名冲突
let obj = {
    name:'tom',
    age:18,
    count(){
       console.log('统计计数') 
    }
}

//  借助Symbol()类型 
let count = Symbol();
//  把 count 作为 obj 的属性 需要使用 []
obj[count] = function(){
    console.log('扩展obj')
}

//  调用对象中的 Symbol() 创建的count 的方法
obj.count()  // 调用对象自身的
obj[count](); //  调用对象中的 Symbol() 创建的count 的方法

遍历Symbol()属性名 :Symbol 作为属性名,遍历对象的时候

  1. 通过 Obejct.getOwnPropertySymbols() 遍历, 得到的是所有的Symbol() 属性名; 常规的属性名是获取不到的
  2. 通过 Reflect.ownKeys() 方法遍历对象的所有属性名 (常规和Symbol()的)

Set() 数据结构

set()是一个新的数据类型, 类似于数组,但是不能通过下标取值;set()值不允许重复

  1. 声明set() 数据类型
let set = new Set() // Set() 是一个构造函数   空的set()

let set = new Set([1, 1, 1, 2, 3, 5]) // 参数是数组, 要求值不能重复; 自动去重
  1. 通过set() 的特性 实现 数组去重
let arr1 = [1, 1, 1, 1, 2, 3]
let arr = [...new Set(arr1)]
  1. set() 数据的操作

    • add() : 添加
    • delete() : 删除 ; 返回值是布尔值 true:删除成功。 false:删除失败
    • clear() : 清空
    • has() : 判断是否存在某个值; 返回值布尔值 true:存在 false:不存在
  2. set() 进行遍历 : 由于 Set 结构没有键名,只有键值(或者说键名和键值是同一个值),所以keys方法和values方法的行为完全一致。

    • keys() : 返回键名的遍历器
    • values() : 返回键值的遍历器
    • entries() : 返回键值对的遍历器
    • forEach() : 使用回调函数遍历每个成员(类似数组中的forEach())

for-of 遍历 : 遍历部署了 [Symbol.iterator] 属性的数据

原生具有iterator接口的数据类型:

  • Array
  • Map
  • Set
  • String
  • TypedArray
  • 函数的 arguments 对象
  • NodeList 对象

自定义对象不存在 该接口的, 不能使用for-of遍历 ; 如果要使用for-of遍历自定义对象,需要自己部署接口

Iterator迭代器 (接口)

  1. 一是为各种数据结构,提供一个统一的、简便的访问接口;
  2. 是一个函数
  3. Iterator 接口主要供for…of消费
  4. (原理) 每一次调用next方法,都会返回数据结构的当前成员的信息。具体来说,就是返回一个包含value和done两个属性的对象。其中,value属性是当前成员的值,done属性是一个布尔值,表示遍历是否结束。(false:意味着遍历没有结束; true:意味着遍历结束了, value属性的值 是undefined)

自定义对象 部署Iterator接口

let obj = {
    name:'tom',
    age:19,
    say:'hello',
    sleep:'睡觉',
    [Symbol.iterator]: function(){
        let index = 0;  // 模拟指针移动
        let key = null;  // 存储键  
        let self = this;  // 存储this
        return {
            next: function(){
                if(key == null){
                    //  key 是存储所有的键名  是一个数组
                    key = Object.keys(self)
                }
                return {
                    value:self[key[index]],
                    done:++index > key.length
                }
            }
        }
    }
}

//  没有部署之前 报错: obj is not iterable   (obj 不可迭代的)
// for(let key of obj){
//     console.log(key);
// }

//  执行的过程
let iterator = obj[Symbol.iterator]();
let res1 = iterator.next();
let res2 = iterator.next();
let res3 = iterator.next();
let res4 = iterator.next();
let res5 = iterator.next();
console.log(res1);  // {value:tom, done:false}
console.log(res2);  // {value:, done:false}
console.log(res3);
console.log(res4);
console.log(res5);

Object.keys() 方法 获取对象属性名的集合(结果是属性名组成的数组)(获取的是对象常规的属性名,不包含Symbol()类型)

Map 数据结构

Map 是es6新增的数据结构; 存储的是键值对, 但是键不局限于字符串, 可以是任意类型

  1. 声明方式
let map = new Map() // 声明一个空的map结构

// 数组作为参数
let map = new Map([[10, 'hello'], [20,'world']])

// 使用对象作为参数   借助set()方法实现
let o = {name:'tom'}
let map = new Map()
map.set(o, '姜子牙')

// 可以使用Set() 数据结构作为参数
const set = new Set([
  ['foo', 1],
  ['bar', 2]
]);
const m1 = new Map(set);
m1.get('foo') 
  1. Map()的数据操作

    • set(key, value) : 设置键和值
    • delete(key) : 删除键值对 ; 结果是布尔值, true: 删除成功, false:删除失败
    • has(key) : 判断是否存在指定的键 结果 布尔值; true:存在; false:不存在
    • clear() : 清空
    • get(key) : 获取值 , 参数是键名
  2. Map() 的遍历方式

    • keys() : 返回键名的遍历器。
    • values() : 返回键值的遍历器。
    • entries() : 返回键值对的遍历器。
    • forEach() :遍历 Map 的所有成员 ;类似数组的forEach()

Promise() 对象

  1. 回调地狱: 在使用JavaScript时,为了实现某些逻辑经常会写出层层嵌套的回调函数,如果嵌套过多,会极大影响代码可读性和逻辑,这种情况也被成为回调地狱
  2. 通过 Promise() 解决回调地狱

Promise() 基本实现流程(执行机制)

Promise对象是一个构造函数,用来生成Promise实例。

promise 的作用:Promise对象,可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise对象提供统一的接口,使得控制异步操作更加容易。

promise 接受一个函数作为参数: 函数有两个参数: resolve(成功) reject(失败); 他们两个是函数,由 JavaScript 引擎提供,不用自己部署。

Resolve函数的作用是,将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;

Reject函数的作用是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。

promise 的状态: 有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。

Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。 当处于pending状态时,无法得知目前进展到哪一个阶段

Promise() (承诺)基本代码逻辑

let flag = true;
function fun(){
    return new Promise( (resolve, reject) =>{
        if(flag){
            // resolve() 代表成功, resolve() 调用执行 then() 中的回调函数
            // resolve()
            //  参数 result 就是传递的数据  需要通过then() 中回调函数接受
            resolve(result) 
        }else{
            //  reject() 代表失败, reject() 调用执行 catch() 中的回调函数
            // reject()
            //  参数 error 就是传递的错误信息 需要通过catch() 中回调函数接受
            reject(error)
        }
    })
}

// fun().then(() => {}).catch(() => {})

fun().then((data) => {}).catch((err) => {})

async 函数 和 await

async: async函数返回一个 Promise 对象,可以使用then方法添加回调函数。当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。
async 和 await 的使用: await必须在 async函数内部使用 , await命令后是一个 promise()对象
***async函数返回一个 Promise 对象。 ***

//  简单用法:
async function fun(){
    await new Promise((resolve, reject) => {

    })
}

//  
async function fun2(){
    // await fun3();
    //  async 函数 内部使用 return 语句传递数据
    return 'hello'
}

async function fun3(){
    
}

fun2().then((data) => {
    console.log(data)
})

async 和await 的异常捕获

通过 try-catch语句捕获异常

async function fun() {
    try {
        await new Promise((resolve, reject) => {
            reject('执行失败');
        });
    } catch (err) {
        console.log('捕获异常'+err)
    }
}
fun();

宏任务和微任务

  1. 宏任务: 整体的JavaScript代码, setTimeout, setInterval
  2. 微任务: Promise, process.nextTick(nodejs的方法) ; process.nextTick 优先于 promise 执行
  3. 事件循环机制 :
  4. 宏任务和微任务执行机制(微任务先执行, 宏任务后执行)
  5. 执行遇到await 命令,会让出线程,执行完所有的

Object.defineProperty(): 数据拦截(数据劫持)

方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。

  1. 基本用法:
// Object.defineProperty(obj, prop, descriptor)
/* 
* obj: 要定义属性的对象 (监听的对象)
* prop: 要定义或修改的属性的名称或 Symbol 。(监听的属性名)
* descriptor: 要定义或修改的属性描述符。 (该描述符是一个对象;对监听的对象的属性的具体操作; 常用的 set() 和 get() 方法)
 */
let obj = {
    name:'tom'
    age:18
}
//  需要借助一个中间变量实现 操作: 
let newName = obj.name;
Object.defineProperty(obj, 'name', {
    get(){
        //  获取/读取 对象的属性是 进行数据拦截(数据劫持)
        //  通过 return 语句 返回劫持后修改的数据
        return `《${newName}》`
    },
    set(value){
        //  设置对象的属性 进行拦截
        newName = value;
    }
})

作用: 通过数据劫持 可以 实现 数据的双向绑定(vue2 框架的数据双向绑定的原理)

es6 的 Proxy() 代理器

Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写

Proxy() 是一个构造函数

//  var proxy = new Proxy(target, handler);
/* 
* target:要使用 Proxy 包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。  (监听拦截的对象)
* handler : 一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理 p 的行为。(监听对象后进行具体操作)
 */

 let obj = {
     name:'tom',
     age:18
 }

 let p = new Proxy(obj, {
     get(target, props){
        //  target 代理对象 obj 
        //  props 拦截的属性名 
        //  通过return语句返回拦截(修改)的数据
        return target[props]
     },
     set(target, props, value){
        //   target 代理对象 obj 
        //   props 拦截的属性名 
        //  value 设置的属性值(新值)
        target[props] = value;
     } 
 })
//  后期的操作完全有 代理器 p进行 
 p.name = 'hello'

es6 的模块

ES6 在语言标准的层面上,实现了模块功能,而且实现得相当简单,完全可以取代 CommonJS 和 AMD 规范成为浏览器和服务器通用的模块解决方案。

  1. 模块导出方式: export 对象导出
//  导出单一模块(导出的模块可以是任意类型)
export function fun(){}
export function say(){}
export let num = 100;

//  把模块作为整体导出
function print(){}
let obj = {};
let str = 'hello';

export {print, obj, str}

//  导出默认模块 一个文件中只能有一个默认模块
export default function(){}

//  导出模块也可以命名别名; 引入时通过别名进行引入
function sleep(){}
export {sleep as s}
  1. 模块引入方式: import 模块名 from ‘url’
//  引入 单一模块
import {fun} from 'url'

//  引入多个模块
import {fun, say, num} from 'url'

//  引入默认模块 默认模块可以自定义引入的模块名, 可以省略 {}
import a from 'url'

//  整体加载模块 使用 * 加载, 把引入的模块作为一个对象的属性 ; 默认模块的属性名为default
import * as f from 'url'

//  引入默认模块和普通模块
import a,{fun} from 'url'

//  引入模块命名别名 使用as 关键字 ; 后期通过 别名 f 操作模块
import {fun as f} from 'url'
  1. 模块模块之间可以相互依赖引入; 一个文件可以引入多个模块, 一个模块可以引入多个文件

你可能感兴趣的:(javascript)