欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

es6知识点整理

程序员文章站 2022-07-16 20:25:56
...

es6是什么及兼容性

es6是什么

ECMAScript 6.0(以下简称 ES6) 是 JavaScript 语言的下一代标准,已经在 2015年 6月 正式发布了,它的目标,是使得JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言。

为什么使用es6

  1. 新语法糖能提高编码效率,语法更优雅
  2. 对于js继承的实现,异步的操作有了更好的解决方案
  3. 目前主流的前端框架都使用es6,例如react,vue
  4. 微信小程序、支付宝小程序、uni-app等跨平台框架也都在使用es6
  5. 面试必问的考点

兼容性

  • pc
    • Chrome: 51 版起可以支持 97% 的 ES6 新特性。
    • Firefox: 53 版起便可以支持 97% 的ES6 新特性。
    • Safari: 10 版起便可以支持 99% 的ES6新特性。
    • IE: Edge 15可以支持 96% 新特性。Edge 14 可以支持 93% 的 ES 6 新特性。(IE7~11 基本不支持 ES6)。
  • 移动端
    • ios 10.0版起
    • android 基本不支持
  • 服务端
    • node.js 6.5起

let 和 const 关键字

无变量名的提升

consloe.log(a);  // undefined
var a = 1;
consloe.log(a);  // 报错
const a = 1; 
or
let a = 1;

暂时性死区

在块中使用了const或者let就会形成暂时性死区,简单理解就是将块封闭起来。

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

let or const

 if(true) {
            let a = 2;
        }
  console.log(a);  // Uncaught ReferenceError: a is not defined(报错)

let b = 1;
if(true) {
	let a = 2;
	a = b + 2;
	let b;
}
console.log(b);  // 报错 Uncaught SyntaxError: Identifier 'b' has already been declared

块级作用域

用let或者const,无论是在块的上边还是下边将无法访问到

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

var 与 let 和 const 区别

  1. var声明的变量会挂载在window上,而let和const声明的变量不会;
  2. var声明变量存在变量提升,let和const不存在变量提升;
  3. let和const声明形成块作用域;
  4. 同一作用域下let和const不能声明同名变量,而var可以;
  5. 暂存死区;
  6. let、const都是块级局部变量;
  7. const:
    一旦声明必须赋值,不能使用null占位。
    声明后不能再修改
    如果声明的是复合类型数据,可以修改其属性
const a = 0;
a = a + 1;
console.log(a);  // Uncaught TypeError: Assignment to constant variable.
const obj = {};
 obj.a = 1;
console.log(obj);  // {a: 1}

es6解构赋值

解构赋值是对赋值运算符的扩展。

他是一种针对数组或者对象进行模式匹配,然后对其中的变量进行赋值。

在代码书写上简洁且易读,语义更加清晰明了;也方便了复杂对象中数据字段获取。

对象的解构赋值

	// const obj = {
    //     name: 'allen',
    //     age: 18
    // }
    // let childrenName = obj.name;
    // let childrenAge = obj.age;

    const { name,age } = { name: 'allen', age: 18 };
    console.log(name,age);		// allen 18
const { name: childrenName, age: childrenAge } = { name: 'allen', age: 18 };
 console.log(childrenName,childrenAge);  // allen 18

特性
解构赋值是将地址赋给了变量
可以从原型链中获取元素的属性

数组的解构赋值

var arr = [1, [2, 3], 4, [5, [6, 7]]];
    var [a, [b], c, [d,[e]]] = [1, [2, 3], 4, [5, [6, 7]]];
    console.log(a,b,c,d,e)  // 1 2 4 5 6

模板字符串

传统写法

const name = 'allen'; 
          age = 18;
   console.log('我叫' + name + '。今年' + age + '岁了!');

模板字符串

const name = 'allen'; 
          age = 18;
console.log(`我叫${name},今年${age}岁了!`);

模板字符串的特性

  • ${} 里边可以写变量和表达式
  • 多行字符串,空格和缩进都会保存在输出中

面试题

   var arr = [];
    for(var a = 0; a < 10; a++) {
        arr.push(function(){
            console.log(a);
        })
    }
    arr.forEach(function(fn) {
        fn()
    })
var arr = [];
    for(let a = 0; a < 10; a++) {
        arr.push(function(){
            console.log(a);
        })
    }
    arr.forEach(function(fn) {
        fn()
    })

数值的扩展

Number.isNaN

判断数值是否为NaN

console.log(Number.isNaN(NaN));		// true

Math.trunc

用于去除一个数的小数部分,返回整数部分
不能转换为数值的均为NaN
向下取整

console.log(Math.trunc(4.9)); // 4
console.log(Math.trunc('a')); // NaN

扩展运算符

var obj = {a: 1, b:2}
var c = { c: 1 }
c = {
  ...obj,
  ...c
}

扩展运算符的特性

  • 可以对引用类型一维结构进行深拷贝,合并数组/对象
  • 什么是深拷贝?
var a = [1,2,3]
var b = a
a[0] = 2
console.log(a, b)

var a = [1,2,3]
var b = [...a]
a[0] = 2
console.log(a, b)

var obj1 = {a: 1, b:2}
var obj2 = obj1
obj1.a = 2
console.log(obj1, obj2)

var obj1 = {a: 1, b:2}
var obj2 = { ...obj1 }
obj1.a = 2
console.log(obj1, obj2)

注意这里只能对一维结构进行拷贝

var a = [[0,1],2,3]
  var b = [...a]
  a[0][0] = 1
  console.log(a, b)
  • 函数的调用
function f(v, w, x, y, z) {
  console.log(v)
  console.log(w)
  console.log(x)
  console.log(y)
  console.log(z)
}
const args = [0, 1];
const obj = {a: 1}
f({...obj}, ...args, 2, ...[3]);
Function.prototype._call = function (context) {
  // if (typeof context === 'object') {
  //   context = context || window
  // } else {
  //   context = Object.create(null)
  // }

  var fn = +new Date() + '' + Math.random()
  context[fn] = this
  
//   var args = []
//   for(var i = 1; i < arguments.length; i++) {
//     args.push('arguments['+ i + ']')
//   }

//   var result = eval('context[fn]('+args+')')

  //es6 写法
  var result = context[fn](...arguments.slice(1))

  console.log(result)
  delete context[fn]
  // 5 返回结果
  return result
}
  • 可以放置表达式
const arr = [
  ...(x > 0 ? ['a'] : []),
  'b',
];

数值的扩展

指数运算符

2 ** 3
2 ** 3 ** 2 // 512

a **= 2; // a = a**a

rest参数

  • 概念

用于获取函数的多余参数,这样就不需要使用arguments对象了。rest 参数搭配的变量是一个数组,该变量将多余的参数放入数组中。

  • arguments的替代
function fn (...arg) {
  console.log(arguments)
  console.log(arg)
}
fn(1,{a:1},[])

注意,rest 参数之后不能再有其他参数(即只能是最后一个参数),否则会报错。

// 报错
function f(a, ...b, c) {
  // ...
}

箭头函数

var f = () => 5;
// 等同于
var f = function () { return 5 };

var sum = (num1, num2) => num1 + num2;
// 等同于
var sum = function(num1, num2) {
  return num1 + num2;
};

特性

  • 不能作为构造函数
var Fn = () => {}
new Fn()
  • 箭头函数无arguments对象
const fn = ()  => {
  return arguments //报错
}
fn(1,2,3,4)

// 可以使用rest参数
const fn = (...arg)  => {
  return arg
}

  • 如果不写“{}”或“()”等同于return 结果
const fn = (a) => a + 1
console.log(fn(2)) 

// 可以简化写法
// 正常函数写法
[1,2,3].map(function (x) {
  return x * x;
});

// 箭头函数写法
[1,2,3].map(x => x * x);
  • 大括号解析为代码块
let getTempItem = id => ({ id: id, name: "Temp" });
// 等价于
let getTempItem = id => { return { id: id, name: "Temp" }; }
  • 解构赋值同样可以使用
const data = { code: '0',data: [], message: '成功' }
let fn = ({ code, data:arr, message }) => arr.push(message)
fn(data)
  • 函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象
// 例子1
var a = 1
function fn () {
  this.a = a + 1
}
var f = new fn()
var obj = {
  a: 10,
  fn: function () {
    this.a += f.a 
    return function () {
      this.fn()
    }
  }
}
var b = obj.fn()
b()
console.log(a)
console.log(obj.a)

// 例子2
var obj = {
  say: function() {
    var f1 = ()=>{
        console.log(this);	
    }
    f1();
  }
}
var o = obj.say;
console.log(o())
console.log(obj.say())

var id = 21;

foo.call({ id: 42 });
  • call和apply不能影响箭头函数this指向
window.name = '老王'
const person1 = {
  name: 'allen',
  say: () => {
    alert(`我叫${this.name}`)
  }
}
const person2 = {
  name: 'tom'
}

person1.say.call(person2)

尾调用

  • 概念
    • 某个函数的最后一步是调用另一个函数。
function f(x) {
  if (x > 0) {
    return m(x)
  }
  return n(x);
}

class类及集成

  • 类的由来
// 传统js生成实例
function Point(x, y) {
	this.x = x;
	this.y = y;
}
Point.prototype.a = 1;
const point = new Point(1, 2);
console.log(point);  //Point {x: 1, y: 2}
class Point {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }
}
const point = new Point(1, 2);
console.log(point);  //Point {x: 1, y: 2}
  • 数据类型 function
class Point{}
console.log(typeof Point); //function

console.log(Point === Point.prototype.constructor); //true
  • 通过new生成实例
  • 在class上定义方法
class Point {
    name(){};
}
const point = new Point();
console.log(point);

constructor 方法

  • 执行机制

constructor方法是类的默认方法,通过new命令生成对象实例时,自动调用该方法。一个类必须有constructor方法,如果没有显式定义,一个空的constructor方法会被默认添加。

  • 定义类(遵循的规律)

实例的属性除非显式定义在其本身(即定义在this对象上),否则都是定义在原型上(即定义在class上)。

  • 生成的示例共享一个原型
class Point {
  constructor (x, y) {
    this.x = function () { return x }
    this.y = y
  }
  name () {
    console.log(`我叫${this.y},今年${this.x()}岁了`)
  }
}
const p1 = new Point(30,'tom')
const p2 = new Point(18,'allen')
p1.name()
p2.name()
  • this指向
class Point {
  fn () {
    console.log(this)
  }
}

const p1 = new Point()
p1.fn()
const { fn } = new Point()
fn()
// class内部走的是严格模式
// 如何解决
// 1.在初始化时给方法绑定this
class Point {
  constructor () {
    this.fn = this.fn.bind(this)
  }
  fn () {
    console.log(this)
  }
}
// 使用箭头函数
// 箭头函数的this总是指向上下文的执行环境
class Point {
  fn = () => {
    console.log(this)
  }
}
  • 静态方法
  • 传统下定义
class Component {}
Component.getClassName = function () {}
// 不会被实例继承
new Component()
  • 通过static关键字定义
class Component {
  static getClassName () {
    console.log(this)
  }
  fn () {}
}
new Component
  • 静态属性 同样也是通过static定义,写法与静态方法类似

class的继承

通过extends关键字实现继承

class Parent {
  house () {
    console.log(`${this.name}继承了父母的房子`)
  }
}
class Son extends Parent {}
Son.prototype.name = '儿子'
var son = new Son()
console.log(son.house())
  • super关键字
class Parent {
  house () {
    console.log(`${this.name}继承了父母的房子`)
  }
}
class Son extends Parent {
  constructor () {
    // 报错
  }
}
Son.prototype.name = '儿子'
var son = new Son()
son.house()

//super作为函数调用时,代表父类的构造函数。ES6 要求,子类的构造函数必须执行一次super函数。
class Parent {
  constructor (x) {
    this.x = x
  }
  house () {

  }
}
class Son extends Parent {
  constructor () {
    super(11)
  }
}

var son = new Son()
console.log(son)

Set和Map数据结构

Set

// Set
const s = new Set()
console.log(s)

// add 方法
const arr = [2, 3, 5, 4, 5, 2, 2]
arr.forEach(v => {
    s.add(v)
})
console.log(s)

// 可以接收一个数组用于初始化
const set = new Set([1, 2, 3, 4, 4]);

// set如何判断数据是否重复?
var s = new Set()
s.add(1)
s.add('1')
s.add({})
s.add({})
s.add([])
s.add([])
var arr = [1]
var arr1 = arr
s.add(arr)
s.add(arr1)
console.log(s)
// 结论add 填加的实质是查看Set中元素是否与添加元素全等,全等则忽略

// set其他方法
    s.delete(arr) // 注意这里如果是复杂数据类型需要传入地址
    s.has(value) //返回一个布尔值,表示该值是否为Set的成员。
    s.clear() // 清除所有成员
// set属性
    s.size //返回Set实例的成员总数。
// set与数组类型相似,数组方法set可以使用
let set = new Set([1, 2, 3, 4, 5]);
set = set.filter(x => (x % 2) == 0);
// 将set转为数组
Array.from(s)

Map

JavaScript 的对象(Object),本质上是键值对的集合(Hash
结构),但是传统上只能用字符串当作键。这给它的使用带来了很大的限制。

var obj = {}
const element = document.getElementById('myDiv');
obj[element] = 'metadata'

为了解决这个问题,ES6 提供了 Map 数据结构。它类似于对象,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。换句话说,Object 结构提供了“字符串—值”的对应,Map 结构提供了“值—值”的对应,是一种更完善的 Hash 结构实现。如果你需要“键值对”的数据结构,Map 比 Object 更合适。

const m = new Map();
const element = document.getElementById('myDiv');
// m[element] = 'metadata'
m.set(element, 'metadata')

m.has(element) // true
m.delete(element) // true
m.clear()
const map = new Map([
  ['name', '张三'],
  ['title', 'Author']
]);

Symbol

const obj = {
    a: 1
}

obj.a = 2

const a = Symbol()
obj[a] = 2

数据类型

  • 基本数据类型
  • String Number Boolean null undefined
  • 引用数据类型
  • Array Object symbol
// const a = Symbol()
// console.log(typeof a)

const a = 1
const b = 1

a === b

let arr1 = []
let arr2 = arr1
arr1 === arr2


let a = Symbol()
let b = a

a === b

特性

  • Symbol一旦声明,全局唯一
  • 没有字面量
// const arr = []
// const arr = new Array()
  • Symbol可以接受参数,并且会调用入参的toString方法作为描述的结果
function fn () {}
const f = Symbol(fn)
Symbol()
  • 描述的传入会不会影响Symbol
cosnt s1 = Symbol(1)
cosnt s2 = Symbol(1)
s1 === s2
  • Symbol能否参与运算
let s1 = Symbol('1')
let s2 = 1 + s1
let s1 = Symbol('1')
String(s1)
  • Symbol可以转为字符串和Boolean,但不能转为数值类型
  • Symbol.prototype.description(获取symbol的描述信息)
let s1 = Symbol('1')
s1.description
  • Symbol在创建对象key值的运用
let a = {}
const mySymbol = Symbol()
a[mySymbol] = 1
a.mySymbol = 1
Function.prototype._call = function (context) {
  // if (typeof context === 'object') {
  //   context = context || window
  // } else {
  //   context = Object.create(null)
  // }

//   var fn = +new Date() + '' + Math.random()
  const fn = Symbol('唯一的key值')
  context[fn] = this
  
//   var args = []
//   for(var i = 1; i < arguments.length; i++) {
//     args.push('arguments['+ i + ']')
//   }

//   var result = eval('context[fn]('+args+')')

  //es6 写法
  var result = context[fn](...arguments.slice(1))

//   console.log(result)
  delete context[fn]
  // 5 返回结果
  return result
}

const obj = {
    name: 'allen',
    fn: function () {
        console.log(this.name)
    }
}
const obj1 = {
    name: 'tom'
}

obj.fn._call(obj1)
  • 属性名的遍历
const obj = {
    a: 1,
    b: 2,
    c: 'allen'
}
const s = Symbol()
obj[s] = 'symbol'
for (let k in obj) {
    console.log(k)
}

Promise对象

  • 概念

定时器、回调、事件、promise

const a = 1

function fn (callback) {
    // 计算量非常大的运算
    setTimeout(function(){
        callback('异步操作完成信息')
    },0)
}
function callback (data) {
    return data
}
cosnt f = fn(callback) 

const b = 2
console.log(a)
console.log(b)
const promise = new Promise(function (resolve, reject) {
    // 异步操作成功
    if (true) {
        resolve(value)
    } else {
        reject(error)
    }
})

promise.then(function (data) {
    console.log(data) // 接受的就是resolve(value),value的值
}, function (error) {
    console.log(error) // reject(error)
})
  • promise创建时,他的状态为padding
  • resolve,状态由padding变为resolved,从未完成变为成功
  • reject,状态由padding变为rejected,从未完成变为失败

执行顺序

const promise = new Promise(function (resolve, reject) {
    console.log('Promise')
    resolve()
})
promise.then(function () {
    console.log('resolved')
})
console.log('Hi!')

一道面试题

async function async1 () {
    console.log('async1 start')
    await async2()
    console.log('async1 end')
}
async function async2 () {
    console.log('async2')
}
console.log('script start')
setTimeout(() => {
    console.log('timeout')
}, 0)
async1()
new Promise(resolve => {
    console.log('promise1')
    resolve()
}).then(() => {
    console.log('promise2')
})
console.log('script end')

// Promise.all(x,x,x,x,x).then()

async函数

async 函数是什么?一句话,它就是 Generator 函数的语法糖。

async function name([param[, param[, ... param]]]) { statements }

Proxy构造函数

Proxy 用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种“元编程”(meta programming),即对编程语言进行编程。

Proxy
可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy
这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”。

es6学习参考网站