乐趣区

前端开发常见笔试面试题总结-JavaScript篇

前一篇文章是关于 HTML/CSS 面试题的,链接见这里,今天聊一聊一些高频出现的 JavaScript 面试题。

对原型和原型链是如何理解的?

  1. JavaScript 由对象构成,每一个对象(除 null 外)都和另一个对象相关联(通过__proto__属性),“另一个对象”就是原型。即任何一个对象都有原型这个属性。
  2. 继承原型依靠 ” 原型链 ”(prototype chain)模式来实现继承
  3. 所有 JavaScript 对象都从原型 (prototype) 继承属性和方法,可以尝试打印一下 String.prototype、Array.prototype …
  4. 日期对象继承自 Date.prototype。数组对象继承自 Array.prototype。函数对象继承自 Function.prototype。日期对象、数组对象和函 数对象都继承自 Object.prototype,其位于原型继承链的顶端
  5. 可以用 object.prototype.name = value 修改自己创建的原型,不要修改 JavaScript 标准对象的原型

JavaScript 解释器的执行顺序和原理

  • Js 引擎 (浏览器) 将执行的任务分为 同步任务 异步任务,同步任务就是在主线程上按顺序执行,上一个任务不完成,下一个任务就无法进行,是线程阻塞的。而异步任务则处于“任务队列”中,不会造成阻塞线程。
  • 运行机制:程序开始后,主线程先执行同步任务,碰到异步任务先放到任务队列(TO DO LIST,又称事件队列)中,如 setTimeout(),然后继续执行。等同步任务执行完毕,JS 引擎便去查看任务队列有没有可以执行的异步任务,有的话,将异步任务转为同步任务,开始执行,执行完该同步任务后继续查看任务队列,这个过程是一直循环的,也就是所谓的事件循环。(通过任务队列,单线程的 JS 实现了所谓的 ” 多线程 ”)
  • 加入宏任务,微任务:JS 解释器执行顺序为,同步任务(先执行宏任务,在执行微任务),遍历异步队列,执行异步任务。

    1. 宏任务:由宿主环境发起,如setTimeoutsetInterval
    2. 微任务:由 JavaScript 引擎发起的,如 Promise.then()

基础类型和引用类型在存储方式和拷贝上的区别?

存储方式

  • 基本数据类型:key 和 value 存储在栈内存中
  • 引用数据类型:key 存在栈内存中,value 存在于堆内存中,但是栈内存会提供一个引用的地址指向堆内存中的值

拷贝:

  • 深拷贝与浅拷贝的概念只存在于引用数据类型
  • 浅拷贝只会将对象的各个属性进行依次复制,并不会进行递归复制,也就是说只会赋值目标对象的第一层属性。深拷贝不同于浅拷贝,它不只拷贝目标对象的第一层属性,而是递归拷贝目标对象的所有属性。
  • 浅拷贝对于目标对象第一层为基本数据类型的数据,就是直接赋值,即「传值」;而对于目标对象第一层为引用数据类型的数据,就是直接赋存于栈内存中的堆内存地址,即「传址」, 并没有开辟新的栈,也就是复制的结果是两个对象指向同一个地址,修改其中一个对象的属性,则另一个对象的属性也会改变。而深复制则是开辟新的栈,两个对象对应两个不同的地址,修改一个对象的属性,不会改变另一个对象的属性。

什么是闭包,如何利用闭包?

闭包 是指有权访问父作用域中的变量的函数
用处:可以实现封装,属性私有化 / 防止污染全局变量

数组的 for、forEach 和 map 的区别是什么

  • for 循环可以中途跳出,而 forEach 不可以,break 命令或 return 命令都不能生效
  • 相比普通的 for 循环,forEach 的优势在于对稀疏数组的处理,会跳过数组中的空位
  • forEach 改变原数组,map 不改变原数组而是返回一个新数组

如何写一个数据请求?

  • 传统的 AJAX 请求,利用 XMLHttpRequest 发送请求,获取数据。为了兼容性,应该用 jQuery 的 AJAX
    $.ajax({
      method: 'POST',
      url: '/api',
      data: {username: 'admin', password: 'root'}
    })
    .done(function(msg) {alert( 'Data Saved:' + msg);
    });
  • 在 ES6 中,新增了 fetch 方法:
    fetch(url, {method : 'get',})
    .then(response => response.json())
    .then(res => console.log(res))
    .catch(err => console.log("Oops, error", err))
    
  • 利用第三方 axios 库:
    axios.get('/user', {
      params: {ID: 12345}
    })
    .then(function (response) {console.log(response);
    })
    .catch(function (error) {console.log(error);
    });

用 JavaScript 代码实现斐波那契数列

斐波那契数列的排列是:1,1,2,3,5,8,13,21,34,55,89,144 …
输入任意的 index,返回对应位置的斐波那契数
实现如下:

getFibonacci = (n) => {
  let e1 = 0;
  let e2 = 1;
  let target = 0;
  for(let i=1; i<=n; i++){
    e1 = e2;
    e2 = target;
    target = e2 + e1;
  }
  return target;
}

谈谈你对 MVC、MVP 和 MVVM 的理解,具体在写代码中的体验

Model-View-Controller:M(数据保存)、V(用户界面)、C(业务逻辑)

  • View 传送指令到 Controller
  • Controller 完成业务逻辑后,要求 Model 改变状态
  • Model 将新的数据发送到 View,用户得到反馈
  • 所有的通信都是单向的

Model-View-Presenter

  • 各部分之间的通信,都是双向的
  • View 与 Model 不发生联系,都通过 Presenter 传递
  • View 非常薄,不部署任何业务逻辑,称为 ” 被动视图 ”(Passive View),即没有任何主动性,而 Presenter 非常厚,所有逻辑都部署在那里

Model-View-ViewModel

  • 基本上与 MVP 模式完全一致,只是把 Presenter 变成了 ViewModel

MVVM 的优点

  1. 双向绑定,当 Model 变化时,View 和 ViewModel 会自动更新,保持了数据一致性
  2. 简化了控制器
  3. View 的功能进一步强化,可以像 Model 一样有自己的 ViewModel
  4. 可以对 View 或 ViewController 的数据处理部分抽象出来。减轻 Model 的负担

MVVM 的缺点

  1. 数据绑定使得 bug 很难被调试
  2. 双向绑定不利于代码重用
退出移动版