前端面试之——ES6的新特性

原文链接:https://blog.csdn.net/chenacxz/article/details/110354507

前端面试之——ES6的新特性

模板字符串

传统字符串用法

const str = 'hello world this is a string'

模板字符串

const str = `hello world this is a \`string\``
console.log(str)//hello world this is a `string`

const str = `hello world
 this is a \`string\``
console.log(str )
//输出 hello world
 this is a \`string\`
 
const name = 'tony'
constr str = ` hey,${
    
    name}`
console.log(str)//hey,tony

带标签的模板字符串

let data = console.log`hello world`
console.log(data)//["hello world"]

const name = 'tom'
const gender = true
function dealData(strings){
    
    
	console.log(strings)//['hey ,', ' is a', '.']//用嵌入的表达式作为分隔符
}
 dealData`hey , ${
      
      name} is a ${
      
      gender} .`

const name = 'tom'
const gender = true
function dealData(strings,name,gender){
    
    
	console.log(strings)//['hey ,', ' is a', '.']//用嵌入的表达式作为分隔符
	console.log(name,gender)//tom true
}
const result = dealData`hey , ${
      
      name} is a ${
      
      gender} .`
console.log(result)

const name = 'tom'
const gender = true
function dealData(strings,name,gender){
    
    
	//return '1243'
	const sex = gender ? 'man' : 'woman'
	return strings[0] + name + strings[1] + sex+ strings[2]
	//目的是对模板字符串进行加工,让返回的结果更适合用户的阅读
	// hey ,tom is a true.
}
const result = dealData`hey , ${
      
      name} is a ${
      
      gender} .`
console.log(result)//1243

字符串扩展方法

includes  startwith endwith
const msg ='Error foo is not defined .' 
console.log(msg.includes('foo'))
console.log(msg.startwith('error'))
console.log(msg.endwith('.'))

参数默认值

//在形参的后面加一个等于号设置默认值
function foo(fo,bar = true) {
    
    //如果参数较多的情况下,只能放在最后一位
	console.log(false)//false 以为传入的实参是false,不是undefined或者没有传递
}
foo(false)//没有传递实参,或者实参是undefined才会被使用

剩余参数

function foo(...args){
    
    
	console.log(args)//[1,2,3,4]
}
foo(1,2,3,4)

function foo(first,...args){
    
    
	console.log(args)//[2,3,4]
}
foo(1,2,3,4)

展开数组

const arr = ['foo','bar','styring']
console.log(...arr)//foo bar styring

对象字面量

var bar = '124'
var obj = {
    
    
	name:'toney',
	bar //bar:bar
}
console.log(obj.bar)

var obj1 = {
    
    
	name:'toney',
	bar ,//bar:bar
	//method:functiion(){
    
    
	//	console.log(this)
	//},
	method(){
    
    
		console.log(this)
	}
}
console.log(obj1.method())

Object.assign

将源对象的属性赋值到目标对象中去

var target = {
    
    
	a:'121',
	b:'212'
}
var source= {
    
    
	a:'1211',
	c:'111'
}
var source1= {
    
    
	a:'1212',
	d:'111'
}
var result = Object.assign(target , source, source1)
console.log(result )
//{
    
    
//	a:'1212',
//	b:'212',
//	c:'111',
//	d:'111'
//}
console.log(result  == target )//true

Object.is

console.log(Object.is(+0,-0))//false
console.log(Object.is(Nan,Nan))//true

Proxy代理对象

监视某个对象中的属性读写
可以使用ES5的Object.defineProperty为对象添加属性,Vue使用这个实现数据相应,从而实现数据的双向绑定
Proxy专门为了给对象设置访问代理器的
	var person = {
    
    
		name:'tony',
		age:20
	}
	//第一个参数是代理的处理对象,
	const personProxy = new Proxy(person,{
    
    
		//第一个参数代表目标对象,第二个是访问的属性名
		get(target, property){
    
    //监视属性的访问
			//console.log(target, property)
			//return 100
			return property in target ? target[property ] : 'default'
		},
		//第一个参数代表目标对象,第二个是写入的属性名称,第三个地表写入的值
		set(target, property, value){
    
    //监视属性设置
			//{name:'tony',age:20} gender true
			//console.log(target, property, value)
			if(property == 'age'){
    
    
				if(!Number.isInteger(value)){
    
    /如果value不是Number类型报错
					throw new Error (`${
      
      value} is not a int`)
				}
			}
			target[property ] = value//给代理目标设置专门的属性
		}
	})
	personProxy.gender = true
	//{name:'tony',age:20} name
	console.log(personProxy.name)//100

Proxy与Object.defineProperty的区别

Proxy的功能更为强大

Object.defineProperty只能监听对象属性的读写,而Proxy不仅能监听对象的读写
还能监听到更多对象操作,例如delete操作或者对象中方法的调用等

var person ={
    
    
	name:'ceshi',
	age:20
}
const proxy = new Proxy(person, {
    
    
	deleteProperty(person, property){
    
    
		console.log(person,property)
		delete person[property]
	}
})
delete proxy.name
console.log(person )
Proxy 更好支持数组对象的监视
let list = []
const listProxy = new Proxy(list,{
    
    
	set(target, property, value){
    
    
		console.log(target, property, value)
		target[property] = value
		return true
	}
}) 
listProxy.push(100)
// [] "0" 100
// [100] "length" 1
//get方法走了两边,set方法走了两边。因为push方法其实做了两步,第一是再length出加上push的值,第二是把length加一,所以走了两边。
Proxy是以非侵入的方式监管对象的读写

已经定义好的对象,不需要对对象做任何的操作就可以实现监听

var person ={
    
    }
Object.defineProperty(person,'name',{
    
    
	get(){
    
    
		console.log('name被访问')
		return person._name
	},
	set(value){
    
    
		console.log('name被设置')
		person._name = value
	}
})
Object.defineProperty(person,'age',{
    
    
	get(){
    
    
		console.log('age被访问')
		return person._age
	},
	set(value){
    
    
		console.log('age被设置')
		person._age = value
	}
})
person.name = 'jack'
console.log(person)

Relect

ES6提供的一个静态类,是一个内置对象,统一对象操作Api
不能通过new构建一个实例对象,只能调用静态类里的静态方法Relect.get()去调用
内部封装了一系列对对象的底层操作(13个静态方法)

内部成员方法是Proxy处理对象的默认实现

const person = {
    
    
	name:'tony',
	age:20
}
const personProxy = new Proxy(person, {
    
    
	get(target, property){
    
    
		return Reflect.get(target, property)
	}
})
console.log(personProxy.name)
const person = {
    
    
	name:'tony',
	age:20
}
console.log('name' in person)
console.log(Reflect.has(person,'name'))

console.log(delete person['name'])
console.log(Reflect.deletePorperty(person,'name'))

consoe.log(Obejct.keys(person))
consoe.log(Reflect.ownKeys(person))

class

function Person(name){
    
    
	this.name = name
}
Person.prototype.say = function(){
    
    
	console.log(`this is a name called ${
      
      this.name}`)
}

class Person{
    
    
	constuctor(name){
    
    
		this.name = name
	}
	say(){
    
    
		console.log(`this is a name called ${
      
      this.name}`)
	}
}
const p = new Person('tony')
console.log(p.say())

静态方法

class Person{
    
    
	constuctor(name){
    
    
		this.name = name
	}
	say(){
    
    
		console.log(`this is a name called ${
      
      this.name}`)
	},
	static create(name){
    
    
		return new Person(name)
	}
}
const p = new Person('tony')
const tom  = Person.create('tom')
//静态方法是挂载到类型上的,所以this不会指向实例对象,而是当前的类型
console.log(p.say())
console.log(tom.say())

继承 extends

可以集成对象中相似属性

class Person{
    
    
	constuctor(name){
    
    
		this.name = name
	}
	say(){
    
    
		console.log(`this is a name called ${
      
      this.name}`)
	}
}
class Student extends Person{
    
    
	constuctor(name,number){
    
    
		super(name)
		this.number = number
	}
	hello(){
    
    
		super()
		console.log(`this is a age called ${
      
      this.number}`)
	}
}
const p = new Student ('tony',21)
console.log(p.hello())//连同person一起被打印

set数据集合

类数组,没有重复的数据

const set = new Set()
set.add(1).add(2).add(3).add(2)
console.log(set)//Set {1, 2, 3}
set.forEach(i => console.log(i))//1 2 3
for(var i  of set){
    
    
	 console.log(i)
}
console.log(set.size)
console.log(set.has(100))
console.log(set.delete(3))
set.clear()
const arr = [1,2,4,5,6,3,1]
const s = new Set(arr)
Array.from(s)
[...s]

map

类对象,和传统的对象一样,都是键值对集合,但是传统对象 键只能是字符串

let obj = {
    
    }
obj[true] = 'val1'
obj[1243] = 'val2'
obj[{
    
    a:1}] = 'val3'
console.log(Object.keys(obj))//['1243','true','object object']
console.log(obj['object object'])//val3

const m = new Map()
const tom = {
    
    tn : 90}
m.set(tom, 200)
console.log(m)
console.log(m.get({
    
    tn : 90}))
console.log(m.has({
    
    tn : 90}))
console.log(m.delete({
    
    tn : 90}))
m.clear()
m.forEach((val, key) => {
    
    
	console.log(val, key)
})
与对象最大的区别是可以用任意类型作为键

Symbol

一种全新的数据类型
之前之前的字符串可以重复,从而导致冲突

const obj = {
    
    }
//a.js
obj['foo'] = Math.random()
//b.js
obj['foo'] = '123'
console.log(obj)

//表示独一无二的值
const s = Symbol()
console.log(s)//Symbol()
console.log(typeof s)//Symbol
console.log(Symbol() === Symbol() )//false

console.log(Symbol('foo'))
console.log(Symbol('bar'))
console.log(Symbol('baz'))

const obj1= {
    
    }
obj1[Symbol()] = '123'
obj1[Symbol()] = '456'
console.log(obj1)

const obj2= {
    
    
	[Symbol()] : '789'
}
console.log(obj2)

const name = Symbol()
const obj3 ={
    
    
	[name]:'012',
	say(){
    
    
		console.log(this[name])
	}
}
console.log(obj3.say())

//主要用处是为对象添加一个独一无二的属性值

如果要实现相同的Symbol,可以使用提供的静态方法实现 for
const s1 = Symbol.for('foo')
const s2 = Symbol.for('foo')
console.log(s1===s2)
但是这个方法内部维护的是字符串和Symbol的对应方式,传入的不是字符串方法内容会自动转换为字符串
Symbole.for(true) = Symbole.for('true') 

const obj = {
    
    
	[Symbol.toStringTag] = 'XObject'
}
console.log(obj.toString()//[object XObject]
Symbol类型的属性名,通过常规的方法无法获取
const obj = {
    
    
	[Symbol()]:'symbol value',
	foo:'normal value'
}
for(var key in obj ){
    
    
	console.log(obj[key])//foo
}
console.log(Object.keys(obj ))//foo
console.log(JSON.stringify(obj ))//{'foo':'normal value'}
可以用它作为私有属性
console.log(Object.getOwnPropertySymbol(obj))

for of循环

const arr = [1, 2, 3, 4]
for(const item of arr ){
    
    
	console.log(item )
}
for(const item of arr ){
    
    
	console.log(item )
	if(item>2){
    
    
		break;//可以随时终止循环
	}
}
//除了数组还可以用来遍历类数组类对象的数据
const newArr = new Set(['foo', 'bar'])
for(const item of newArr ){
    
    
	console.log(item)//'foo' 'bar'
}
const m = new Map()
m.set('foo', '123')
m.set('bar', '456')
for(const [key, val] in m){
    
    
	console.log(key, val)//foo 123  bar 456
}
const newM = {
    
    foo:'123',bar:'456'}
for(const item of newM ){
    
    
	console.log(item)//普通的对象会报错不可迭代
}

可迭代接口

实现可迭代接口是for of 使用的前提
数组,类数组,类对象,他们都有共同的属性,可以通过展开内部的原型对象看到
const arr = [1, 2, 3, 4]
const it = arr[Symbol.iterator]()
//内部有一个数据指针,我们每调用一次,指针就会向后面移一位
console.log(it.next())//{value:1,done:false}不断的去遍历 done代表是否遍历结束
console.log(it.next())//{value:2,done:false}
console.log(it.next())//{value:3,done:false}
console.log(it.next())//{value:4,done:false}
console.log(it.next())//{value:undefined,done:true}
console.log(it.next())//{value:undefined,done:true}

实现可迭代接口

const obj = {
    
    
	[Symbol.iterator]:function(){
    
    //实现可迭代接口,iterable可迭代接口约定内部必须有定义一个返回iterator的接口
		return {
    
    
			next:function(){
    
    //实现了迭代器接口iterator接口,约定了内部必须有个next方法
				return{
    
    //返回的对象,叫做iterationResult
					value:'foo',
					done:true
				}
			}
		}
	}
}
for(const item of obj ){
    
    
	console.log('循环体')
]

const obj = {
    
    
	store:[1, 2, 3, 4],
	[Symbol.iterator]:function(){
    
    //实现可迭代接口,iterable可迭代接口约定内部必须有定义一个返回iterator的接口
	let index = 0;
	let _this = this
		return {
    
    
			next:function(){
    
    //实现了迭代器接口iterator接口,约定了内部必须有个next方法
				let result = {
    
    //返回的对象,叫做iterationResult
					value:_this.store[index],
					done:index>= _this.store.length
				}
				index++
				return result 
			}
		}
	}
}
for(const item of obj ){
    
    
	console.log(item )
]

iterator 迭代器模式

const obj = {
    
    
	learn:["语文","数学","英语"],
	life:["吃饭","睡觉","学习"],
	each:function(callback){
    
    
		let arr = [].concat(this.learn,this.life)
		for(const item of arr){
    
    
			callback(item)
		}
	},
	[Symbol.iterator]:function(){
    
    
	let index = 0;
	let _this = this
	let arr = [...this.learn,...this.life]
		return {
    
    
			next:function(){
    
    
				return {
    
    
					value:arr [index],
					done:index++ >= arr .length
				} 
			}
		}
	}	
}
obj.each(function(item){
    
    
	console.log(item)
})
console.log("---------")
//迭代器模式,是向外部提供一个统一遍历接口,让外部不用去关系内部数据的结构
for(const item of obj){
    
    
	console.log(item )
}

生成器 Generator

避免异步回调编程中嵌套太深
提供更好的异步编程解决方案

生成器函数,在function后面添加一个*function * fun(){
    
    
	console.log("111")
	return 100
}
const g = fun()
console.log(g)//输出了生成器对象,对象的原型上有一个next方法
console.log(g.next())//111 {value:100.done:true}

function * foo(){
    
    
	console.log("111")
	yield 100
	console.log("222")
	yield 200
	console.log("333")
	yield 300
}
const f = fun()
console.log(f.next())//111 {value:100.done:false}
console.log(f.next())//222 {value:200.done:false}
console.log(f.next())//333 {value:300.done:false}
console.log(f.next())//undefined {value:undefined.done:true}

生成器使用

function * createId (){
    
    
	let id = 1
	while(true){
    
    
		yield id ++ 
	}
}
const c = createId ()
console.log(c.next().value)
console.log(c.next().value)
console.log(c.next().value)
console.log(c.next().value)

ES2016

inclues

传统寻找数组是否函数某个元素使用indexOf
includes
const arr = [1,"string",NaN,undefined,null,Symbol(),true]
console.log(arr.indexOf(1))//但是不能用于NaN
console.log(arr.includes(NaN))//true 

指数运算符

const num = Math.pow(2,10)
console.log(num)//2的10次方

console.log(2 ** 10)//2的10次方

ES2017

Object.values()
获取value 和 Object.keys()对应

Object.entries()
//有点类似于这个功能
const m = new Map()
m.set(‘foo’,123)
m.set(‘bar’,456)
for(const [key, val] in m){
    
    
console.log(key, val)//foo 123 bar 456
}

const obj = {
    
    
name:‘tony’,
age:20
}
for(const [key, val] in Object.entries(obj ){
    
    
console.log(key, val)//foo 123 bar 456
}

Async Await

猜你喜欢

转载自blog.csdn.net/weixin_45054614/article/details/113358433