当前位置: 首页 / 技术干货 / 正文
JS面试题总结一

2020-07-23

web前端培训

  好程序员web前端培训分享JS面试题总结一,准备参加面试的小伙伴们一起看一看吧,希望本篇文章能够对从事web前端工作的小伙伴们有所帮助。

web前端

  一、说说你对闭包的认识

  ()什么是闭包

  一句话解释:

  能够读取其他函数内部变量的函数。

  稍全面的回答:

  在js中变量的作用域属于函数作用域, 在函数执行完后,作用域就会被清理,内存也会随之被回收,但是由于闭包函数是建立在函数内部的子函数, 由于其可访问上级作用域,即使上级函数执行完, 作用域也不会随之销毁, 这时的子函数(也就是闭包),便拥有了访问上级作用域中变量的权限,即使上级函数执行完后作用域内的值也不会被销毁。

  这里涉及到对函数作用域的认识: js变量分为全局变量和局部变量;函数内部可以直接读取全局变量,而在函数外部自然无法读取函数内的局部变量

  ()闭包解决了什么问题

  1. 可以读取函数内部的变量

  2. 让这些变量的值始终保持在内存中。不会在函数调用后被清除

  可以通过下面的代码来帮助理解上面所说的:

  function addCounter() {

  let counter = 0

  const myFunction = function () {

  counter = counter + 1

  return counter

  }

  return myFunction

  }

  const increment = addCounter()

  const c1 = increment()

  const c2 = increment()

  const c3 = increment()

  console.log('increment:', c1, c2, c3);

  // increment: 1 2 3

  在这段代码中increment实际上就是闭包函数myFunction, 它一共运行了三次,diyi次的值是1,第二次的值是2,第三次的值是3。这证明了,函数addCounter中的局部变量counter一直保存在内存中,并没有在addCounter调用后被自动清除。

  ()闭包的应用场景

  在开发中, 其实我们随处可见闭包的身影, 大部分前端 JavaScript 代码都是“事件驱动”的,即一个事件绑定的回调方法; 发送ajax请求成功|失败的回调;setTimeout的延时回调;或者一个函数内部返回另一个匿名函数,这些都是闭包的应用。

  下面是具体应用的栗子:

  1. 老掉牙的取正确值问题

  for (var i = 0; i < 10; i++) {

  setTimeout(function () {

  console.log(i) //1010

  }, 1000)

  }

  怎么取到每一次循环的正确值呢? 闭包这样用:

  for (var i = 0; i < 10; i++) {

  ((j) => {

  setTimeout(function () {

  console.log(j) //1-10

  }, 1000)

  })(i)

  }

  声明了10个自执行函数,保存当时的值到内部

  2.使用闭包模拟私有变量

  私有变量在java里使用private声明就可以了, 但是在js中还没有,但是我们可以使用闭包模拟实现。

  var counter = (function () {

  var privateCounter = 0;

  function changeBy(val) {

  privateCounter += val

  }

  return {

  increment: function () {

  changeBy(1)

  },

  decrement: function () {

  changeBy(-1)

  },

  value: function () {

  return privateCounter

  }

  }

  })();

  counter.value() //0

  counter.increment() //1

  counter.increment() //2

  counter.decrement() //1

  匿名函数已经定义就立即执行, 创建出一个词法环境包含counter.incrementcounter.decrementcounter.value三个方法,还包含了两个私有项:privateCounter变量和changeBy函数。这两个私有项无法在匿名函数外部直接访问,必须通过匿名包装器返回的对象的三个公共函数访问。

  ()闭包的缺点

  1. 由于闭包会是的函数中的变量都被保存到内存中,滥用闭包很容易造成内存消耗过大,导致网页性能问题。解决方法是在退出函数之前,将不再使用的局部变量全部删除。

  2. 闭包可以使得函数内部的值可以在函数外部进行修改。所有,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。

  二、跨域问题有哪些处理方式

  跨域解决方案

  1. 通过jsonp跨域

  2. 跨域资源共享(CORS)

  3. nodejs中间件代理跨域

  4. nginx反向代理中设置proxy_cookie_domain

  .通过jsonp跨域

  通常为了减轻web服务器的负载,我们把jscssimg等静态资源分离到另一台独立域名的服务器上,在html页面中再通过相应的标签从不同域名下加载静态资源,而被浏览器允许,基于此原理,我们可以通过动态创建script,再请求一个带参网址实现跨域通信。

  1. 原生实现

  <script>

  var script = document.createElement('script');

  script.type = 'text/javascript';

  // 传参一个回调函数名给后端,方便后端返回时执行这个在前端定义的回调函数

  script.src = 'http://www.daxihong.com:8080/login?user=admin&callback=jsonCallback';

  document.head.appendChild(script);

  // 回调执行函数

  function jsonCallback(res) {

  alert(JSON.stringify(res));

  }

  </script>

  服务器端返回如下(返回即执行全局函数)

  jsonCallback({"status": 0, "user": "admin"})

  2. jquery方式实现

  $.ajax({

  url: 'http://www.domain2.com:8080/login',

  type: 'get',

  dataType: 'jsonp', // 请求方式为jsonp

  jsonpCallback: "handleCallback", // 自定义回调函数名

  data: {}

  });

  .跨域资源共享(CORS)

  CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)跨域资源共享 CORS 详解。看名字就知道这是处理跨域问题的标准做法。CORS有两种请求,简单请求和非简单请求。

  · 简单请求

  只要同时满足以下两大条件,就属于简单请求:

  1. 请求方法是以下三种方法之一:

  · HEAD

  · GET

  · POST

  2. HTTP请求头的信息不超出以下几种字段:

  · Accept

  · Accept-Language

  · Content-Language

  · Last-Event-ID

  · Content-Type:只限于三个值application/x-www-form-urlencodedmultipart/form-datatext/plain

  如果是简单请求, 后端处理即可, 前端什么也不用干; 这里注意的是如果前端要带cookie, 前端也需要单独设置

  · 原生ajax (前端)

  var xhr = new XMLHttpRequest();

  // 前端设置是否带cookie

  xhr.withCredentials = true;

  ...

  · jquery (前端)

  $.ajax({

  ...

  xhrFields: {

  withCredentials: true // 前端设置是否带cookie

  },

  crossDomain: true, // 会让请求头中包含跨域的额外信息,但不会含cookie

  ...

  });

  · vue中使用axios (前端)

  axios.defaults.withCredentials = true

  · 后端node

  可以借助koa2-cors快速实现

  const path = require('path')

  const Koa = require('koa')

  const koaStatic = require('koa-static')

  const bodyParser = require('koa-bodyparser')

  const router = require('./router')

  const cors = require('koa2-cors')

  const app = new Koa()

  const port = 9871

  ...

  // 处理cors

  app.use(cors({

  origin: function (ctx) {

  return 'http://localhost:9099'

  },

  credentials: true,

  allowMethods: ['GET', 'POST', 'DELETE'],

  allowHeaders: ['t', 'Content-Type']

  }))

  // 路由

  app.use(router.routes()).use(router.allowedMethods())

  // 监听端口

  ...

  .nodejs中间件代理跨域

  跨域原理: 同源策略是浏览器的安全策略, 不是HTTP协议的一部分。服务器端调用HTTP接口只是使用HTTP协议, 不会执行js脚本, 不需要检验同源策略,也就不存在跨域问题。

  实现思路:通过起一个代理服务器, 实现数据的转发,也可以通过设置cookieDomainRewrite参数修改响应头cookie中域名,实现当前域下cookie的写入

  · 在vue框架下实现跨域

  利用node + webpack + webpack-dev-server代理接口跨域。在开发环境下,由于vue渲染服务和接口代理服务都是webpack-dev-server同一个,所以页面与代理接口之间不再跨域,无须设置headers跨域信息了。后台可以不做任何处理。

  webpack.config.js部分配置

  module.exports = {

  entry: {},

  module: {},

  ...

  devServer: {

  historyApiFallback: true,

  proxy: [{

  context: '/login',

  target: 'http://www.daxihong.com:8080', // 代理跨域目标接口

  changeOrigin: true,

  secure: false, // 当代理某些https服务报错时用

  cookieDomainRewrite: 'www.daxihong.com' // 可以为false,表示不修改

  }],

  noInfo: true

  }

  }

  .nginx反向代理中设置

  和使用node中间件跨域原理相似。前端和后端都不需要写额外的代码来处理, 只需要配置一下Ngnix

  server{

  # 监听9099端口

  listen 9099;

  # 域名是localhost

  server_name localhost;

  #凡是localhost:9099/api这个样子的,都转发到真正的服务端地址http://localhost:9871

  location ^~ /api {

  proxy_pass http://localhost:9871;

  }

  }

  对于跨域还有挺多方式可以实现, 这里就不一一列举了。

  三、for...in for...of的区别

  1. for...of ES6新引入的特性,修复了ES5引入的for...in的不足

  2. for...in 循环出的是keyfor...of循环出的是value

  3. for...of不能循环普通的对象,需要通过和Object.keys()搭配使用

  4. 推荐在循环对象属性的时候,使用for...in,在遍历数组的时候的时候使用for...of

  四、new一个对象,这个过程中发生了什么

  var obj = new Object("name","sansan");

  1. 创建一个新对象,如:var obj = {};

  2. 新对象的_proto_属性指向构造函数的原型对象。

  3. 将构造函数的作用域赋值给新对象。(也所以this对象指向新对象)

  4. 执行构造函数内部的代码,将属性添加给obj中的this对象。

  5. 返回新对象obj

  五、js的防抖和节流是什么

  · 防抖: 在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。

  使用场景:

  1. 给按钮加函数防抖防止表单多次提交。

  2. 对于输入框连续输入进行AJAX验证时,用函数防抖能有效减少请求次数。

  简单的防抖(debounce)代码:

  function debounce(fn, wait) {

  var timeout = null;

  return function () {

  if (timeout !== null) clearTimeout(timeout)

  timeout = setTimeout(fn, wait)

  }

  }

  // 处理函数

  function handle() {

  console.log(Math.random())

  }

  //滚动事件

  window.addEventListener('scroll', debounce(handle, 2000));

  · 节流: 就是指连续触发事件但是在 n 秒中只执行一次函数。节流会稀释函数的执行频率。

  function throttle(func, delay) {

  var prev = Date.now();

  return function () {

  var context = this;

  var args = arguments;

  var now = Date.now();

  if (now - prev >= delay) {

  func.apply(context, args);

  prev = Date.now();

  }

  }

  }

  function handle() {

  console.log(Math.random());

  }

  window.addEventListener('scroll', throttle(handle, 2000));

  区别:

  函数节流不管事件触发有多频繁,都会保证在规定时间内一定会执行一次真正的事件处理函数,而函数防抖只是在最后一次事件后才触发一次函数。 比如在页面的无限加载场景下,我们需要用户在滚动页面时,每隔一段时间发一次Ajax请求,而不是在用户停下滚动页面操作时才去请求数据。这样的场景,就适合用节流技术来实现。

好程序员公众号

  • · 剖析行业发展趋势
  • · 分享大厂面试心得
  • · 汇聚企业项目源码
  • · 下载全套高精尖教程

好程序员开班动态

More+
  • HTML5大前端 <高端班>

    开班时间:2020-11-16(北京)

    开班盛况

    开班时间:2020-12-07(深圳)

    预约报名
  • 大数据+人工智能 <高端班>

    开班时间:2020-09-14(北京)

    开班盛况

    开班时间:2020-11-09(北京)

    开班盛况
  • JavaEE分布式开发 <高端班>

    开班时间:2021-01-04(北京)

    预约报名

    开班时间:2020-07-20(北京)

    开班盛况
  • Python人工智能+数据分析 <高端班>

    开班时间:2020-07-20(上海)

    开班盛况

    开班时间:2020-09-21(上海)

    开班盛况
  • 云计算开发 <高端班>

    开班时间:2019-07-22(北京)

    开班盛况

    开班时间:2019-07-15(深圳)

    开班盛况
在线咨询
免费试听
入学教程
立即报名

Copyright 2011-2020 北京千锋互联科技有限公司 .All Right 京ICP备12003911号-5 京公安网11010802011455号