大前端面试汇总

JS杂烩:

1.垃圾回收机制

主要机制是标记并清除,部分老版ie还会用到计数清除。

2.判断括号的匹配

利用栈的特性。push()入栈和pop()出栈。

3.尾递归和尾调用及优化

看阮一峰大佬的文档:尾调用优化

4.数组与树结构的相互转换

JS实现数组与树结构的相互转换

5.宏任务和微任务

  • 宏任务(macro-task):整体代码script、setTimeOut、setInterval
  • 微任务(mincro-task):promise.then、promise.nextTick(node)

 1.事件循环  

当主线程内的任务执行完毕,主线程为空时,会检查微任务的Event Queue,如果有任务,就全部执行,如果没有就执行下一个宏任务;

6.ES6

7.javascript的浅拷贝与深拷贝

深拷贝 JSON.parse(JSON.stringify(object))

 8.数据扁平化

function fn(arr) {
      return arr.reduce((prev,cur) =>{
        return prev.concat(Array.isArray(cur) ? fn(cur) : cur)
      },[])
    }

// 增加dep 代表深度
function flat(arr, dep) {
      if(dep === 0) {
        return arr
      }
      return arr.reduce((prev, cur) => {
        return prev.concat(Array.isArray(cur) ? flat(cur, --dep) : cur)
      }, [])
    }

注意:push返回的数组的长度,concat返回的是合并后的数组,所以要用concat
a++ 先用a,再加一   --a 先减一,再用a

 9.数组去重

let arr = Array.from(new Set(arr))

 10.数组求最大最小值

 // es5
 let max = Math.max.apply(null, arr)
 let min = Math.min.apply(null, arr)

 //es6
 let max = Math.max(...arr)

 11.两个数组取交集和差集

 12.数组求和

var numbers = [65, 44, 12, 4]
var result = numbers.reduce((total, num) => { return total + num })

 13.promise、async有什么区别

  • promise是ES6为解决异步回调而生,async/await是基于Promise实现的,它不能用于普通的回调函数。建议使用async/await
  • async更简洁,不需要写.then,不需要写匿名函数处理Promise的resolve值,也不需要定义多余的data变量,还避免了嵌套代码
  • Async/Await让try/catch可以同时处理同步和异步错误,Promise中要分别处理
  • 根据返回数据决定的时候,async更简洁易读。
  • promise不能在返回表达式的箭头函数中设置断点,async更容易调试

14.手写promise 

15.input 中监听值的变化是在监听什么事件

keypress,keydown,keyup,input可以实时监控,onChange需要失去焦点才能触发。

16.函数科里化 

function add() {
      // 第一次执行时,定义一个数组专门用来存储所有的参数
      var _args = Array.from(arguments);

      // 在内部声明一个函数,利用闭包的特性保存_args并收集所有的参数值
      var _adder = function () {
        _args.push(...arguments);
        return _adder;
      };

      // 利用toString隐式转换的特性,当最后执行时隐式转换,并计算最终的值返回
      _adder.toString = function () {
        return _args.reduce(function (a, b) {
          return a + b;
        });
      }
      return _adder;
    }
    console.log(add2(1, 2)(4)(2)) // 9

17. 变量提升

var a = 10
    function test() {
      console.log(a)
      var a = 1
    }
    test()

输出 undefined

先找搜索局部变量,再搜索全局变量。
先声明变量,再赋值。
变量提升 相当于 var a;

var a = 10
    function test() {
      console.log(a)
       a = 1
    }

输出 10

 

原型链:

1.原型、构造函数、实例、原型链

2.instanceof 和 typeof 的区别

typeof 对于基本数据类型(null, undefined, string, number, boolean, symbol),除了 null 都会返回正确的类型。null 会返回 object。
typeof 对于对象类型,除了函数会返回 function,其他的都返回 object。
如果我们想获得一个变量的正确类型,可以通过 Object.prototype.toString.call(xx)。这样我们就可以获得类似 [object Type] 的字符串。

instanceof 用于判断一个引用类型是否属于某构造函数;还可以在继承关系中用来判断一个实例是否属于它的父类型。
instanceof 的原理是判断实例对象的 __proto__ 是否与构造函数的 prototype 指向同一个引用。

3.判断是否等于undefined的方法

let a

a === void 0 // true

 4.手写代码实现new,call方法

// new
function Person(name, age) {
            this.name = name
            this.age = age
        }

        Person.prototype.sayName = function () {
            console.log(this.name + this.age)
        }

    // 手写new
    function _new(fn, ...args) {
            // Object.create方法使用当前对象原型, 创建一个新对象
            const obj = Object.create(fn.prototype)
            // apply 改变 this
            const rej = fn.call(obj, ...args)
            // 优先返回新的构造函数
            return rej instanceof Object ? rej : obj
        }

    const per = _new(Person, 'hello', 20)

    per.sayName()

// call
 Function.prototype._call = function (thisArg, ...args) {
      if (typeof this !== 'function') {
         throw new TypeError('err')
      }
      const fn = Symbol('fn') // 声明一个独有的Symbol属性, 防止fn覆盖已有属性
      thisArg = thisArg || window // 若没有传入this, 默认绑定window对象
      thisArg[fn] = this // this指向调用call的对象,即我们要改变this指向的函数
      const result = thisArg[fn](...args) // 执行当前函数
      delete thisArg[fn] // 删除我们声明的fn属性
      return result // 返回函数执行结果
    }

// bind
Function.prototype.myBind = function(thisArg) {
  if (typeof this !== 'function') {
    return
  }
  var _self = this
  var args = Array.prototype.slice.call(arguments, 1)
  var fnNop = function () {} // 定义一个空函数
  var fnBound = function () {
    var _this = this instanceof _self ? this : thisArg

    return _self.apply(_this, args.concat(Array.prototype.slice.call(arguments)))
  }
  // 维护原型关系
  if (this.prototype) {
    fnNop.prototype = this.prototype;
  }

  fnBound.prototype = new fnNop();

  return fnBound;
}

 5.继承

function Person (name) {
      this.name = name 
    }

    function Child(name, age) {
      Person.call(this, name)
      this.age = age
    }

    Child.prototype = Object.create(Person.prototype)
    Child.prototype.constructor = Child
   
    const p1 = new Child('wqs', 20)

网络服务相关:

1.浏览器输入 url 之后发生了什么

参考文档:在浏览器输入url后发生了什么

  • 浏览器的地址栏输入URL并按下回车。
  • 浏览器查找当前URL是否存在缓存,并比较缓存是否过期。
  • DNS解析URL对应的IP。
  • 根据IP建立TCP连接(三次握手)。
  • HTTP发起请求。
  • 服务器处理请求,浏览器接收HTTP响应。
  • 渲染页面,构建DOM树。
  • 关闭TCP连接(四次挥手)。

2.跨越解决方案

前端常见跨域解决方案(全)

1、 通过jsonp跨域  // 只能实现get一种请求
2、 document.domain + iframe跨域  // 此方案仅限主域相同,子域不同的跨域应用场景
3、 location.hash + iframe
4、 window.name + iframe跨域
5、 postMessage跨域
6、 跨域资源共享(CORS)// 只服务端设置Access-Control-Allow-Origin即可 若要带cookie请求:前后端都需要设置。
7、 nginx代理跨域
8、 nodejs中间件代理跨域
9、 WebSocket协议跨域

安全

1.CSRF(Cross-site request forgery)跨站请求伪造

1)攻击原理

  • 用户C打开浏览器,访问受信任网站A,输入用户名和密码请求登录网站A;
  • 在用户信息通过验证后,网站A产生Cookie信息并返回给浏览器,此时用户登录网站A成功,可以正常发送请求到网站A;
  • 用户未退出网站A之前,在同一浏览器中,打开一个TAB页访问网站B;
  • 网站B接收到用户请求后,返回一些攻击性代码,并发出一个请求要求访问第三方站点A;
  • 浏览器在接收到这些攻击性代码后,根据网站B的请求,在用户不知情的情况下携带Cookie信息,向网站A发出请求。网站A并不知道该请求其实是由B发起的,所以会根据用户C的Cookie信息以C的权限处理该请求,导致来自网站B的恶意代码被执行。

2)防御措施

  1. Token验证
  2. Referer 验证(简单易行,但 referer 可能被改变)
  3. 隐藏令牌(跟 Token验证差不多,把令牌存到 header 中)

 2.XSS(cross-site scripting)跨域脚本攻击

1)   攻击原理

往 Web 页面里插入恶意Script代码

 2) 防御措施

  1. HTML:对以下这些字符进行转义:&:&amp; <:&alt; >:&gt; ':&#x27; ":&quot; /:&#x2F;
  2. Javascript:把所有非字母、数字的字符都转义成小于256的ASCII字符;
  3. URL:使用Javascript的encodeURIComponent()方法对用户的输入进行编码,该方法会编码如下字符:,      /      ?     :     @     &     =     +     $     #

 3.https

证书验证阶段:

  • 浏览器发起 HTTPS 请求
  • 服务端返回 HTTPS 证书
  • 客户端验证证书是否合法,如果不合法则提示告警

数据传输阶段:

  • 当证书验证合法后,在本地生成随机数
  • 通过公钥加密随机数,并把加密后的随机数传输到服务端
  • 服务端通过私钥对随机数进行解密
  • 服务端通过客户端传入的随机数构造对称加密算法,对返回结果内容进行加密后传输

 性能优化

1.常用提升页面性能

  1. 资源压缩合并,减少 HTTP 请求
  2. 非核心代码异步加载(异步加载的方式,异步加载的区别)
  3. 利用浏览器缓存(缓存的分类,缓存原理)
  4. 使用 CDN
  5. 预解析 DNS
  6. 服务端使用gzip压缩,下载到客户端再解压,减少http传输时间

2.重排 Reflow和重绘 Repaint

1)触发重排 Reflow

  • 增加、删除、修改 DOM 节点时,会导致 Reflow 或 Repaint
  • 移动 DOM 位置,或搞个动画时
  • 修改 CSS 样式时
  • Resize 窗口(移动端没这个问题)或滚动的时候
  • 修改网页默认字体时

2) 触发重绘 Repaint

  • DOM 改动
  • CSS 改动

 3)如何优化

  • 比如要添加多个 DOM 节点,一次性添加,而不要一个个添加。
  • 更改样式,使用js添加类名
  • 将动画效果应用到 position 属性为 absolute 或 fixed 的元素上
  • 避免使用 CSS 表达式(例如:calc())
  • 避免设置多层内联样式

 2. 图片懒加载与节流

 3.react性能优化

React

1.react生命周期

算法

1.  常用算法模板案例

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值