1

前一篇文章是关于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. 双向绑定不利于代码重用

ERIC
28 声望2 粉丝

Play around with Javascript~