前端ES6 面试过关宝典

  • 前端ES6 面试过关宝典已关闭评论
  • 135 次浏览
  • A+
所属分类:Web前端
摘要

https://juejin.cn/post/6844903734464495623新增 find,且修复 [NaN].indexOf(NaN) === -1 的bugcopyWithin(target , start 【, end 默认length】),将数组 (s,end] 的内容复制到 target开始的地方,end为负数则就取start处的数据

  1. ES6 部分

  2. Typescript 部分

  3. 前端工程面经(节流防抖、https、前端攻击、性能优化...)

https://juejin.cn/post/6844903734464495623

ES6面试

为什么选择 ES6 ?
  • ES6是新一代的 JS 语言标准,规范了JS的使用标准(var标量提升)、新增了 JS 原生方法更加优雅
ES5、ES6、ES2015区别
  • ES2015特指在2015年发布的新一代JS语言标准,ES6泛指下一代JS语言标准,包含ES2015、ES2016、ES2017、ES2018等。现阶段在绝大部分场景下,ES2015默认等同ES6。ES5泛指上一代语言标准。ES2015可以理解为ES5和ES6的时间分界线。
babel is what?
  • babel是一个 ES6 转码器,可以将 ES6 代码转为 ES5 代码,以便兼容那些还没支持ES6的平台。
String字符串类型的升级优化

优化:

  • 新增模板字符串,不需要再使用 + 拼接字符串,使用(${})取代以往字符串形式,可以保存空格、换行符等

升级:

  • 新增 includes 方法(以往只有indexOf、lastIndexOf查找字符位置)
  • 新增 startsWith()、endsWith()、padStart()、padEnd()、repeat()
Array数组类型的升级优化

优化:

  • 数组解构赋值 let [a,b,c] = [1,2,3]形式进行赋值
  • 扩展运算符 实现数组和松散序列的转化 let args = [...arguments],轻松实现数组结构复制

升级:

  • 新增 find,且修复 [NaN].indexOf(NaN) === -1 的bug

    • 这里的修复指传 callback arr.find(item => isNaN(item))
  • copyWithin(target , start 【, end 默认length】),将数组 (s,end] 的内容复制到 target开始的地方,end为负数则就取start处的数据

  • includes() :可以用来改写 条件1 && 条件2 && 条件3

  • fill() : new Array(10).fill(1)

  • flat() : [1,2,[2,3]].flat(),只能展开一层

Number数字类型的升级优化

优化:

  • 更加严谨安全
    • Number.isNaN:更为严格安全,isNaN()会将字符串先往Number类型转换,再判断
    • Number.isFinite(): Infinity、字符串、对象返回 false全局isFinite()同上
    • Number.isInteger(1.0) // true,判断是否是整数
  • Math:
    • Math.cbrt(8) === 2,计算立方根
    • Math.hypot(3:,4) === 25,计算所有参数的平方的和的平方根
    • Math.sign():正数返回1,负数返回-1,非数字返回NaN
    • Math.trunc():先转换为Number类型,正数、负数取整 / 非数字返回NaN
Object类型的升级优化

优化:

  • 对象属性变量式声明:
// 属性名与对应value的变量名相同时可缩写 let [apple, orange] = ['red appe', 'yellow orange']; let myFruits = {apple, orange};     // let myFruits = {apple: 'red appe', orange: 'yellow orange'}; 
  • 对象解构赋值
  • 对象的扩展运算符(...)let {...obj} = {'a' : 1 , 'b' : 2}
  • super关键字:同this总是指向当前函数所在的对象不同
    • super总是指向当前函数所在对象的原型对象

升级,ES6在Object原型上新增的方法

  • Object.is:做两个目标对象的相等比较,修复NaN === NaN //falseObject.is(NaN,NaN) // true
  • Object.assign(onlyTarget , source1 ,...):合并覆盖到onlyTarget
    • source中的自身属性会被合并
    • source中的继承属性不可枚举的属性不会被合并
      • 且无法正确复制get和set属性(会直接执行get/set函数,取return的值)
  • getOwnPropertyDescriptors(obj):获取对象所有的自身属性(配合defineProperties使用),ES5中getOwnPropertyDescriptor(obj,属性名)只能单个获取(配合defineProperty使用)
    • defineProperties( obj , {属性1 : {配置文件} , 属性2 :{配置文件} ... } )
    • defineProperty( obj , 属性名 , {配置文件} )
  • getPropertypeOf()setProperTypeOf():获取或设置当前对象的prototype对象
    • __proto__属性只是各大浏览器私加过于广泛而默许的属性
      • 在非浏览器环境不一定可以使用
  • keys() / values() / entries():分别获取对象 键 / 值 / 键值对数组
Function函数类型

优化:

  • 箭头函数:箭头函数内的 this 指向函数定义时所在的对象,而不是函数执行时所在的对象
    • 箭头函数如果外层仍是箭头函数,将继续向更外层寻找
    • 箭头函数不能用作构造函数,因为没有自己的this,在new重定向this指向时,没有属于自己的this的可供绑定
    • 箭头函数没有this,也不存在arguments对象,不过对象扩展符获取
      • var fn = (...arguments)=>{console.log(arguments)} ; fn(1,2,3) // [1,2,3]
  • 函数默认赋值,ES6之前无法通过形参给出默认赋值

升级部分

  • ES6新增了双冒号运算符,用来取代bind、call和apply(浏览器暂不支持,Babel已经支持转码)
foo::bar; // 等同于 bar.bind(foo); foo::bar(...arguments); // 等同于 bar.apply(foo, arguments); 

Symbol是什么
  • ES6引入的第7种基本数据类型,Symbol()生成的值都是独一无二的
    • 解决对象属性名太多导致的属性名冲突问题
    • Symbol作对象属性名无法被for infor ofObject.keys()Object.getOwnPropertyNames()JSON.stringify()遍历到
      • Symbol() 不是对象的私有属性,其它对象也可以使用它作属性
let a = Symbol('a'); let obj = {} ; obj[a] = 'xxx'; // obj = {a : 'xxx'} 的属性名不是Symbol('a'),而是默认使用字符'a' 作属性名 
Set 是什么
  • 成员唯一,可以用来去重,Array.from(new Set([1,2,3,3,3,4]))
    • 多个NaN被Set认为是相同的,+0-0也是相同的,undefined也会被存储
  • .size().add().clear().delete().has()
    • 继承自Object,.keys().values().entries().forEach()
Map 是什么
  • new Map() | new Map([['key1' , 'v1'] , ['key2', 'v2']])
  • Map可以看作是Object的超集,打破传统键值的限制
    • 出现原因:Object的key局限于字符串,可以是函数、对象、任意基本类型(甚至是NaN)
    • .size().clear()delete()entries()get(key)has(key)keys()set(key,value)values()
      • entries()返回迭代对象(遍历:for...of... / next())
    • 遍历Map:for (let [key, value] of myMap)myMap.forEach(function(value, key){}
Proxy 是什么
  • Proxy可以拦截对象的get/set方法自由去处理
const handler = {     get: function(obj, prop) {         return prop in obj ? obj[prop] : 37;     } }; const p = new Proxy({}, handler); 
Reflect 是什么
  • 是将原生的一些零散分布在Object、Function或者全局函数里的方法(如apply、delete、get、set等等),统一整合到Reflect上
    • Reflect.apply(target, thisArgument, argumentsList) 整合 apply方法
    • Reflect.defineProperty(target, propertyKey, attributes) 整合defineProperty方法
Promise 是什么
  • 解决 JS 异步机制中回调机制产生的回调地狱问题
    • 可以链式调用
Iterator 是什么
  • 是一种标准、解决方案,Set、Map都不能用for循环遍历

    • 要么单独为它俩设计,要么统一规划新的API(被采取)
  • 就好像JavaScript是ECMAScript标准的一种具体实现一样,Iterator标准的具体实现是Iterator遍历器

Iterator标准规定
  • 所有部署了key值为[Symbol.iterator],且[Symbol.iterator]的value是标准的Iterator接口函数
    • 该函数必须返回一个对象
    • 对象中包含next方法
    • 执行next()能返回包含value/done属性的Iterator对象)的对象,都称之为可遍历对象
    • next()后返回的Iterator对象也就是Iterator遍历器
//obj.[Symbol.iterator]() 就是Iterator遍历器 let obj = {   data: [ 'hello', 'world' ],   [Symbol.iterator]() {     const self = this;     let index = 0;     return {       next() {         if (index < self.data.length) {           return {             value: self.data[index++],             done: false           };         } else {           return { value: undefined, done: true };         }       }     };   } }; 
  • ES6规定,所有部署了Iterator接口的对象(可遍历对象)都可以用for...of遍历
    • 扩展运算符本质上也是由for...of的一种实现
//Array let array = ['red', 'green', 'blue']; array[Symbol.iterator]() //Iterator遍历器 array[Symbol.iterator]().next() //{value: "red", done: false}  //String let string = '1122334455'; string[Symbol.iterator]() //Iterator遍历器 string[Symbol.iterator]().next() //{value: "1", done: false}  //set let set = new Set(['red', 'green', 'blue']); set[Symbol.iterator]() //Iterator遍历器 set[Symbol.iterator]().next() //{value: "red", done: false}  //Map let map = new Map(); let obj= {map: 'map'}; map.set(obj, 'mapValue'); map[Symbol.iterator]().next()  {value: Array(2), done: false} 
for...of 来由
  • 由上可知出现了统一的遍历方法
  • ES6规定,所有部署了Iterator接口的对象(可遍历对象)都可以用for...of遍历
    • 扩展运算符本质上也是由for...of的一种实现
Generator 函数

Generator函数可以说是Iterator接口的具体实现方式

  • yeild 相当于 next() 方法
// 注意 * 贴着function function* generator(){   yeild 1;   yeild 2; } 
async 函数

Generator函数可以说是Iterator接口的具体实现方式

  • async函数可以理解为内置自动执行器的Generator函数语法糖,它配合ES6的Promise近乎完美的实现了异步编程解决方案
Class、extends 是什么

作为ES5生成实例对象的语法糖,使对象实例化的过程更像面向对象编程

  • Class内部定义的所有方法都是不可枚举的
// ES5 玩法 function MyClass(data , props){     this.data = data     this.props = props     return this } MyClass.prototype.toString = function(){     return this.data + ',' + this.props } var mc = new MyClass('a','b') // ES6 玩法 class MyClass{     constructor(data,props){         this.data = data         this.props = props     }     toString(){         return this.data + ',' + this.props     } } Object.keys(MyClass.prototype) // [] 
  • ES6的构造函数必须使用new,ES5不使用new也可以执行
  • Class不存在变量提升,必须先声明Class才能使用,ES5中可以先实例化、再声明
  • ES5的继承实质:先创造子类的实例化对象this,再将父对象的方法挂载到this上
    • ES6则是先将父类实例对象的方法、属性挂载到this(super),再用子类构造函数进一步实例化this
// ES5方法 function Parent(){ } function Child(){ } // 方法1 var child1 = new Child() child1.prototype = new Parent() // 这样 child1 就可以访问 Parent 上的方法了 // 方法2 function Child(){      Parent.call(this , arguments)  }  // ES6方法 class Child extends Parent{     constructor(props){         super(props) // 可以在父类中打印数据         this.props = props     } } 
module、export、import 是什么
  • module、export、import是ES6用来统一前端模块化方案的设计思路和实现方案
    • import引入的模块是静态加载(编译阶段加载)而不是动态加载(运行时加载)
      • 静态加载优点:引入宏(macro)类型检验(type system)
      • 将来浏览器的新 API 就能用模块格式提供,不再必要做成全局变量或者navigator对象的属性
      • 不再需要对象作为命名空间(比如Math对象),未来这些功能可以通过模块提供
    • import引入export导出的接口值是动态绑定关系,即通过该接口,可以取到模块内部实时的值
编程中哪些适合用ES6优化/规范
  • 箭头函数取代var self = this
  • let取代var
  • 常用数组/对象的解构赋值来命名变量
    • let { name , age } = { ...{name:'lhx' , age : 12 } }
  • 长字符串拼接可以使用模板字符串
  • Class取代传统构造函数,实例化对象
  • 保持模块化开发思维,常用 import、 export方法


Typescript 函数

参数部分
  • 基础传参 function fn(str1 : string , num1 : number)
  • 默认传参 function fn(str1 : string = 'default' , num1 : number = 12)
  • 剩余传参 function fn(s1 : string . s2 : string , arr : string[] ) 调用=> fn('a','b','c','d','e')
  • 可选传参 function fn(s1 : string , num1 ?: number )
函数重载
  • 先给出函数名相同、接收不同参数的函数声明,再给出函数的定义
    • 不同参数定义:
      • 数量不同
      • 顺序不同
      • 类型不同
function disp(s1:string):void;  function disp(n1:number,s1:string):void;  function disp(s1:string,n1:number):void;  //  参数类型不同,应设置为any function disp(x: string | number,y?:string | number):void {     console.log(x);     console.log(y); } disp("abc") disp(1,"xyz"); disp('a' , 100)