前端面试题总结

事件委托的优缺点

  • 优点:
    • 减少事件注册,节省内存
    • 减少对dom更新的操作,只需关注委托的元素就行
  • 缺点
    • 基于冒泡事件,对于onfoucsonblur等事件不支持
    • 层级过多,冒泡过程中,可能会被某层阻止掉(建议就近委托)

DOM和BOM区别

  • DOM是文档对象模型,DOM的最根本对象是document:
  • BOM是浏览器对象模型,BOM的最核心对象是window对象:window上的方法(open、size);location; history; screen

JavaScript原型,原型链 ? 有什么特点?

  • 每个对象都会在其内部初始化一个属性,就是prototype(原型),存放共有属性和方法,当我们访问一个对象的属性时;
    • prototype对象默认会开一个对内存,对内存自带constructor,指向当前函数
  • 如果这个对象内部不存在这个属性,那么他就会去prototype里找这个属性,这个prototype又会有自己的prototype,于是就这样一直找下去,也就是我们平时所说的原型链的概念
  • 原型链是由原型对象组成; __proto__ 是每个实例上都有的属性,prototype 是构造函数的属性,这两个并不一样,但 __proto__prototype 指向同一个对象
    • 关系:instance.constructor.prototype = instance._proto

🔔: jquery,zepto的插件机制就是放方法放在他们的原型上($.fn)

prototype

箭头函数和普通(function)函数的区别

箭头函数是普通函数更优雅的简写,和普通函数的区别是:

  1. 函数体内的this对象是函数定义式所在作用域的对象,而不是执行是的对象
  2. 函数内没有指向当前函数的arguments对象,在浏览器环境下输入arugments会报错,
  3. 不能使用new命令,因为new的实现open in new window
    • 没有自己的this,所以无法调用call,apply
    • 没有prototype属性,因为在new命令执行是需要讲函数的prototype指向新对象的_proto_

ES6 class和普通构造函数的区别?

  • Class类似于不同构造函数的语法糖
  • Class不用new时无法调用的,会报错
  • Class不存在变量提升(hoist),这一点与ES5完全不同
  • Class实现继承更易读易理解

ES5和ES6继承的区别

  • es5:Sub.__proto__ === Super.prototype;es6:Sub.__proto__ === Super,在babel对es6对转换let Sub = Object.create(Super)
  • ES5 和 ES6 子类 this 生成顺序不同;es5是先生成子对象实例;es6是先生成父类实例

为什么文件转base64,体积会增加大概1/3?

原文open in new window;总结:

  1. 将每三个字节作为一组,一共是24个二进制位。
  2. 将这24个二进制位分为四组,每个组有6个二进制位。
  3. 在每组前面加两个00,扩展成32个二进制位,即四个字节。
  4. 最后在将二进制转换为对应的编码,这就是Base64的编码值

堆中垃圾回收算法参考open in new window

  • 引用计数法的算法
    • 优点:立即回收
    • 缺点:时间复杂度比较高、无法回收循环引用的对象
  • 标记清除算法
    • 优点:可以解决循环引用问题
    • 缺点:不会立即回收垃圾对象,产生空间碎片化,不能得到空间最大化效率的使用
  • V8引擎的垃圾回收策略主要基于分代式垃圾回收机制;根据存活时间分为新生代老生代
    • 新生代即存活时间较短的对象,使用副垃圾回收器,
    • 老生代即存活时间较长或者占用空间较大的对象(25%),使用主垃圾回收器
    • 新生代Scavenge算法,即采用复制的方式实现的垃圾回收算法;当一个对象通过多次复制或生命周期较长或to空间不足时则会被分配到老生代中
    • 老生代应用标记清除的方式进行垃圾回收
      • 清理后会产生不连续的空间,此时会进行标记-整理
      • 由于老生代要处理的数据比较多,会总成页面卡顿;所以会进行增量标记算法,及将任务分成多个小人物,穿插进js中去执行

ES6 模块与 CommonJS 模块的差异

  • CommonJS 模块输出的是一个值的浅拷贝,首次执行后就会缓存,再次加载只返回缓存结果,ES6 模块输出的是值的引用。
  • CommonJS 模块是运行时加载,可以实现动态引入;ES6 模块是编译时输出接口,因为es6是静态解析,所有可以实现tree-shaking功能
  • ES6 输入的模块变量是只读的,无法进行重新赋值,
  • CommonJs 动态语法,可以写在判断里面,ES6模块只能放在顶部

AMD与CMD区别

  1. AMD推崇依赖前置,在定义模块的时候就要声明其依赖的模块 (requireJS)
define(['dep'], function(dep) {
  // your_export;
});
  1. CMD推崇就近依赖,只有在用到某个模块的时候再去require (seajs)
define(function(require, exports, module) {
  const dep= require('dep');
  exports.your_export = /* your_export */;
})

npm 模块安装机制

npm
参考open in new window

  • 发出npm install命令
  • 查询node_modules目录之中是否已经存在指定模块
    • 若存在,不再重新安装
    • 若不存在
      • npm 向 registry 查询模块压缩包的网址
      • 下载压缩包,存放在根目录下的.npm目录里
      • 解压压缩包到当前项目的node_modules目录

宏任务&微任务

  1. 宏任务
#I/OsetTimeoutsetIntervalsetImmediaterequestAnimationFrameUI Rendering
浏览器
node
  1. 微任务
#process.nextTickMutationObserverpromise
浏览器
node

为什么Promise要引入微任务?

问题的本身就是promise的回掉什么时候执行;

  • 如果放在同步任务中则会造成阻塞,造成cpu利用率低
  • 如果放在宏任务队列则当任务队列非常长;则会造成回掉迟迟无法执行;导致应用卡顿
  • 而放在微任务中则可以解决cpu浪费和回掉函数执行的实时性

堆和栈的区别

  • 申请方式不同
    • 栈是系统自动分配,而堆则是程序员自己申请空间
  • 申请大小不同
    • 栈是在系统自动分配后大小就固定好了的,能从栈获得的空间较小。而堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大

纯函数介绍参考open in new window

满足以下调教的函数:

  • 相同输入总是会返回相同的输出
  • 不产生副作用
  • 不依赖于外部状态

cmemoize函数及使用

memoize简单讲就是将计算结果缓存起来;对于需要大量的计算和递归操作来说,可以加快速度;比如:阶乘、斐波那契数组

代码执行

1.输出结果

const a = {}
const b = { key: 'b' }
const c = { key: 'c' }

a[b] = 123
a[c] = 456

console.log(a[b])
答案

答案: 456
原因:对象的键被自动转换为字符串,然而,当字符串化一个对象时,它会变成 "[Object object]"。因此这里说的是,a["Object object"] = 123。然后,c 是另外一个对象,这里也有隐式字符串化,于是,a["Object object"] = 456。, 所以最后输出结果就是456

2.单击该段落时,日志输出结果

<div onclick="console.log('div')">
  <p onclick="console.log('p')">
    Click here!
  </p>
</div>
答案

答案: p,div
原因:在事件传播期间,有三个阶段:捕获、目标和冒泡。默认情况下,事件处理程序在冒泡阶段执行(除非将 useCapture 设置为 true)。它从嵌套最深的元素向外传播

3.JavaScript里什么情况下a==!a为true呢

答案

答案: []
原因:比较规则如下:

  • 如果一边是布尔值,则转成数值
  • 如果一边是字符串则转成数值
  • 如果一边是对象,则转成原始值(例如:[] == false判断);步骤(内置的[ToPrimitive]函数)
    • 调用valueOf(),如果是原始值则进行比较
    • 调用toString(),如果是原始值则进行比较
    • 否则最后则抛出TypeError异常
      比较时还要遵循以下规则
  • null 和 undefined 是相等的。
  • 要比较相等性之前,不能将null和undefined转换成其他任何值
  • 如果有一个操作数是NaN,则相等操作符返回false, 而不相等操作符则返回true, NaN != NaN

4. arguments相关运行结果

var length = 10;
function fn() {
  console.log(this.length);
}
var obj = {
  length: 2,
  show: function(fn) {
    this.length = 3;
    fn();
    // arguments.number = 1000
    arguments[0]();
  }
};
obj.show(fn);
答案

答案: 10、1
原因: 可以将arguments[0]()看成arguments.0();所以这里的this其实是函数的参数,也就是 arguments的个数;

5.打印输出结果

function foo() {
  getName = function() {console.log(1);}
  return this
}
foo.getName = function(){console.log(2);}
foo.prototype.getName = function(){console.log(3);}
var getName = function(){console.log(4);}
function getName() {
  console.log(5);
}
foo.getName()
getName()
foo().getName()
getName()
new foo.getName()
new foo().getName()
new new foo().getName()

答案

答案: 2,4,1,1,2,3,3
原因:无

小红包免费领
小礼物走一走
Last Updated:
Contributors: slbyml, 邵礼豹
部分内容来源于网络,如有侵权,请留言或联系994917123@qq.com;访问量:waiting;访客数:waiting