es6知识点整理
es6是什么及兼容性
es6是什么
ECMAScript 6.0(以下简称 ES6) 是 JavaScript 语言的下一代标准,已经在 2015年 6月 正式发布了,它的目标,是使得JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言。
为什么使用es6
- 新语法糖能提高编码效率,语法更优雅
- 对于js继承的实现,异步的操作有了更好的解决方案
- 目前主流的前端框架都使用es6,例如react,vue
- 微信小程序、支付宝小程序、uni-app等跨平台框架也都在使用es6
- 面试必问的考点
兼容性
- 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 区别
- var声明的变量会挂载在window上,而let和const声明的变量不会;
- var声明变量存在变量提升,let和const不存在变量提升;
- let和const声明形成块作用域;
- 同一作用域下let和const不能声明同名变量,而var可以;
- 暂存死区;
- let、const都是块级局部变量;
- 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 function name([param[, param[, ... param]]]) { statements }
Proxy构造函数
Proxy 用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种“元编程”(meta programming),即对编程语言进行编程。
Proxy
可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy
这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”。
上一篇: es6语法的使用