面试题2-原生js

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)
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • async 函数 含义 ES2017 标准引入了 async 函数,使得异步操作变得更加方便。 async 函数是...
    huilegezai阅读 4,999评论 0 6
  • 弄懂js异步 讲异步之前,我们必须掌握一个基础知识-event-loop。 我们知道JavaScript的一大特点...
    DCbryant阅读 7,636评论 0 5
  • 面试题一:https://github.com/jimuyouyou/node-interview-questio...
    R_X阅读 5,572评论 0 5
  • PNG 有PNG8和truecolor PNG PNG8类似GIF颜色上限为256,文件小,支持alpha透明度,...
    hudaren阅读 5,590评论 0 0
  • async 函数 ES2017 标准引入了 async 函数,使得异步操作变得更加方便。async 函数是什么?一...
    _羊羽_阅读 6,370评论 0 1