1.必考: ES 6语法知道哪些,分别怎么用?
1.1 import、export模块化:在项目中常用来导入导出组件,对象或者方法(封装请求数据的方法)
1.2 解构赋值:
- 变量赋值:const {a, b} = {a: 'aaaa', b: 123456}减少变量的声明
- 函数参数的定义
function personInfo({name, age, address, gender}) {
console.log(name, age, address, gender)
}
personInfo({gender: 'man', address: 'changsha', name: 'william', age: 18})
- 避免参数顺序错误的问题
- 函数的默认参数
避免使用的过程中因为没有默认值而报错
es5:name = name || 'william'
es6:function saveInfo({name= 'william'...
1.3 let,const
1.4 class和extends
在es5中就是组合继承的语法糖
1.5 箭头函数
1.6 模板字符串
1.7 from of数组遍历
1.8 对象的简洁表达式
1.9 promise对象
2.Promise、Promise.all、 Promise.race 分别怎么用?
const promise = new Promise((resolve, reject) => {
let timer = setTimeout(() => {
if (1 === 3) {
resolve('success');
} else {
reject('fail');
}
}, 1000);
});
promise.then(res=> console.log(res)).catch(err=>console.log(err))
Promise.all可以将多个Promise实例包装成一个新的Promise实例。
同时,成功和失败的返回值是不同的,成功的时候返回的是一个结果数组,
而失败的时候则返回最先被reject失败状态的值。
Promse.all在处理多个异步处理时非常有用,比如说一个页面上需要等两个或多个ajax的数据回来以后才正常显示,在此之前只显示loading图标。
Promise.all获得的成功结果的数组里面的数据顺序和Promise.all接收到的数组顺序是一致的,
在前端开发请求数据的过程中,偶尔会遇到发送多个请求并根据请求顺序获取和使用数据的场景,
使用Promise.all毫无疑问可以解决这个问题。
Promise.race([p1, p2, p3])里面哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态。开发中用的很少
3.手写函数防抖和函数节流
函数防抖用于延时执行,客户只关心"最后一次"操作(也可以理解为停止连续操作后)所返回的结果.
输入搜索关键词,用户在不断输入值时,用防抖来节约请求资源。
按钮点击:收藏,点赞,心标等
const debounce = (fn, delay) => {
let timer = null
return (...args) => {
clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(this, args)
}, delay);
}
}
函数节流用于稀释执行次数,用户关心在操作过程中持续的反馈:滑到底部自动加载更多
const throttle = (fn, delay) => {
let flag = true
return (...args) => {
if (!flag) return
flag = false
setTimeout(() => {
fn.apply(this, args)
flag = true
}, delay);
}
}
flag为ture表示当前定时器的延时还没到
4.手写AJAX
var request = new XMLHttpRequest()//初始化 请求代理对象
request.open('GET', '/a/b/c?name=ff', true);//open方法已经调用,建立一个与服务端特定端口的连接
request.onreadystatechange = function () {//readystate发生改变
if(request.readyState === 4 && //整个相应报文已经完整下载了
request.status === 200) {//状态码
console.log(request.responseText);//响应体
}};
request.send();//发生http请求
readystate表示xhr代理当前所处的状态
6.闭包/立即执行函数是什么?
- 1.可以保留局部变量不被释放的代码块被称作闭包
- 2.怎么形成:1.在外层函数中返回一个内层函数 2.在内存函数中能访问到外层函数中的变量 3.一定要定义一个变量接受内存函数
- 3.使用 :定义一些有作用域局限的持久化变量,这些变量可以作为缓存或者计算的中间量
- 4.弊端:持久化变量不会被正常释放,会持续占用内存空间,很容易造成内存的浪费,一般需要额外手动去清理。
- 5.应用场景:封装变量,实现对数据的保护。
实现设计模式:单例模式,策略模式,观察者模式等
实现封装独立的作用域:轮播图的小圆点添加点击事件,解决循环变量i不正确的问题,防抖节流函数
闭包:一个函数能访问这个函数作用域外的变量,那么这个函数和这个变量就叫闭包。
立即执行函数 :立即执行函数,声明一个函数,然后立马执行。!function(){alert('我是匿名函数')}(),他的作用是创建一个独立的作用域。
7.什么是JSONP, 什么是CORS,什么是跨域?
跨域:指的是浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,
所谓同源是指域名,协议,端口完全相同,只有同源的地址才可以相互通过 AJAX 的方式请求。
jsonp:是一种借助于 script 标签发送跨域请求的技巧
其原理就是在客户端借助 script 标签请求服务端的一个动态网页(php 文件),
服务端的这个动态网页返回一 段带有函数调用的 JavaScript 全局函数调用的脚本,将原本需要返回给客户端的数据传递进去
cors:Cross Origin Resource Share,跨域资源共享
再被请求的服务端加
// 允许远端访问 header('Access‐Control‐Allow‐Origin: */指定的域');
就可以用ajax跨域请求
服务端的nginx反向代理
使用:配置nginx的时候配置一个代理服务器,然后把它做成跳板,比如说我要访问domain2,但是前端只能访问domain1,nginx做一个跳板,
每次访问domain1的时候就自动指向domain2这个接口。
原理是什么?同源策略是浏览器的安全策略而不是http协议的一部分,
如果在服务器端调用接口,因为不存在浏览器所以他走的只是http协议,所以不存在跨域的问题。
8.async/await 怎么用,如何捕获异常?
https://segmentfault.com/a/1190000007535316
https://www.cnblogs.com/fundebug/archive/2019/07/24/async-await-error-handling-in-js.html
async 会将其后的函数返回值封装成一个 Promise 对象,
而 await 会等待这个 Promise 完成,并将其 resolve 的结果返回出来。
async 函数返回的是一个 Promise 对象
await 用于等一个 async 函数的返回值,或者任意表达式的结果
如果它等到的不是一个 Promise 对象,那 await 表达式的运算结果就是它等到的东西。
如果它等到的是一个 Promise 对象,它会阻塞后面的代码,等着 Promise 对象 resolve,然后得到 resolve 的值,作为 await 表达式的运算结果。
async/await 的优势在于处理 then 链
假设一个业务,分多个步骤完成,每个步骤都是异步的,而且依赖于上一个步骤的结果。
function takeLongTime(n) {
return new Promise(resolve => {
setTimeout(() => resolve(n + 200), n);
});
}
function step1(n) {
console.log(`step1 with ${n}`);
return takeLongTime(n);
}
function step2(n) {
console.log(`step2 with ${n}`);
return takeLongTime(n);
}
function step3(n) {
console.log(`step3 with ${n}`);
return takeLongTime(n);
}
//使用promise
function doIt() {
console.time("doIt");
const time1 = 300;
step1(time1)
.then(time2 => step2(time2))
.then(time3 => step3(time3))
.then(result => {
console.log(`result is ${result}`);
console.timeEnd("doIt");
});
}
doIt();
//使用async/await
async function doIt() {
console.time("doIt");
const time1 = 300;
const time2 = await step1(time1);
const time3 = await step2(time2);
const result = await step3(time3);
console.log(`result is ${result}`);
console.timeEnd("doIt");
}
doIt();
// 处理异常
async function myFunction() {
try {
await somethingThatReturnsAPromise();
} catch (err) {
console.log(err);
}
}
// 另一种写法
async function myFunction() {
await somethingThatReturnsAPromise().catch(function (err){
console.log(err);
});
}
9.如何实现深拷贝?
JSON.stringfy(JSON.parse(obj))
1.时间对象=>字符串的形式
2.RegExp、Error => {}
3.function,undefined 丢失
4.NaN、Infinity和-Infinity会变成null
5.如果json里有对象是由构造函数生成的,则序列化的结果会丢弃对象的 constructor
6.循环引用的情况也无法实现深拷贝
手写深拷贝
var deepClone=(obj)=>{
let newObj;
if(typeof obj==='object'&& obj!==null){
newObj=Array.isArray(obj)?[]:{};
for(let prop in obj){
if(obj.hasOwnProperty(prop)){
newObj[prop]=deepClone(obj[prop])
}
}
return newObj;
}
else {
return obj;
}
};
思路:
1.定义一个deepclone函数,将要克隆的对象作为参数
2.定义一个新的newobj,判断newobj是不是对象且不为null,
如果不是对象直接返回。如果是对象或者数组,给newobj一个初始值[]或者{}。
3.遍历obj,将obj里面的值赋值给newobj
并且在赋值之前再调用深拷贝的函数。
10.常考:如何用正则实现 trim()?
背代码
String.prototype.trim = function(){
return this.replace(/^\s+|\s+$/g, '')
}
//或者
function trim(string){
return string.replace(/^\s+|\s+$/g, '')
}
+匹配一个或多个\s(空格)
11.不用 class 如何实现继承?用 class 又如何实现?
组合式继承:原型链继承(原型链上定义的属性)+构造函数继承(构造函数中定义的属性)
function Animal(color){
this.color = color
}
Animal.prototype.move = function(){} // 动物可以动
function Dog(color, name){
Animal.call(this, color) // 或者 Animal.apply(this, arguments)
this.name = name
}
// 下面三行实现 Dog.prototype.__proto__ = Animal.prototype
function temp(){}
temp.prototye = Animal.prototype
Dog.prototype = new temp()
Dog.prototype.constuctor = Dog // 这行看不懂就算了,面试官也不问
Dog.prototype.say = function(){ console.log('汪')}
var dog = new Dog('黄色','阿黄')
用 class 又如何实现?
class Animal{
constructor(color){
this.color = color
}
move(){}
}
class Dog extends Animal{
constructor(color, name){
super(color)
this.name = name
}
say(){}
}
14.如何实现数组去重?
1.创建新数组,遍历旧数组,比较旧数组中的项是否存在于新数组,不存在则加入到新数组
2.原数组上用splice进行去重,遍历数组,如果该项的后一项与它相同则去掉后一项,数组长度减一
3.对象key值不能重复的特性进行去重,
4.set
15.送命题:手写一个 Promise
function myPromise(executor) {
let self=this;
self.status='pending';
self.value=undefined;
self.error=undefined;
function resolve(value) {
if(self.status==='pending'){
self.value=value
self.status="resolved"
}
}
function reject(reason) {
if(self.status==='pending'){
self.error=errot
self.status=status
}
}
try{
executor(resolve,reject)
}
catch (e) {
reject(e)
}
}