面试题第七期

205 阅读11分钟

10月11日

对执行上下文的理解

什么是执行上下文?

js在执行语句前,经过了一系列的“准备”,为代码执行创造一个“教室”,这就是执行上下文,执行上下文里有一个叫文本环境 用来把js所有代码里面的变量名 函数名 类名等放在文本环境 js在执行代码过程中 就可以在文本环境来查的

执行栈

  • 执行栈栈顶的执行上下文称为当前执行上下文
  • js代码总是在当前上下文中执行
  • 意思是js代码中需要用到的资源 到当前执行上下文上查找
4种情况会创建新的执行上下文

(1)进入全局代码
(2)进入function函数体代码
(3)进入eval函数参数指定的代码
(4)进入module代码

文本环境

var和function声明创建在全局对象 而let const class声明的变量创建在全局scope中 先到全局scope中找变量 查找不到再去全局对象找

名字重复的处理

  1. let const class声明的名字之间不能重复
  2. let const class和var function的名字不能重复
  3. var和function名字重复的 function声明的函数名优先

全局执行上下文

  1. 创建全局执行上下文 并加入栈顶
  2. 找到所有的非函数中的var声明 找到所有的顶级函数声明 就是不包括在大括号之内的函数声明 不是函数表达式 找到顶级的let const class声明
  3. 把收集到的let const class声明做名字重复的处理
  4. 创建绑定
    • 登记并初始化var为undefined
    • 顶级函数声明 登记function名字 并初始化为新创建函数对象
    • 块级中函数声明 登记名字 初始化为undefined
    • 登记let const class。但未初始化
  5. 执行语句

这个就是为什么会有变量提升


  1. 作用域是解析变量名的一个变量 就是当前运行的上下文

    • 全局作用域就是全局执行上下文
    • 函数作用域就是函数运行上下文
  2. 函数调用时的执行上下文看地方 函数在哪里创建 就保存哪里的运行上下文

    • 函数的作用域是在函数创建的时候决定的 而不是调用的时候决定的

函数运行上下文

  1. 创建执行上下文 并加入栈顶
  2. 找到所有的非函数中的var声明 找到所有的顶级函数声明 找到顶级的let const class声明
  3. var function和let const class名字不重复 let const class之间名字不重复
  4. 创建绑定
    • 登记并初始化var为undefined
    • 顶级函数声明 登记function名字 并初始化为新创建函数对象
    • 登记let const class。但未初始化、
  5. 执行语句

词法作用域

  • 并非根据调用嵌套形成作用域 而是根据函数创建嵌套形成作用域链 也就是函数的书写位置形成作用域链 因此称为词法作用域

块级作用域

  1. 创建新的记录环境 链接在原来的记录之前
  2. 所有的顶级函数声明 找到let const 声明
  3. function和let const名字不重复 let const之间名字不重复
  4. 创建绑定
    • 登记function名字 并初始化为新创建函数对象
    • 登记let const ,但未初始化、
  5. 执行语句

10月12日

1 对this对象的理解

this 是执行上下文中的一个属性,它指向最后一次调用这个方法的对象。在实际开发中,this 的指向可以通过四种调用模式来判断。

  • 第一种是函数调用模式,当一个函数不是一个对象的属性时,直接作为函数来调用时,this 指向全局对象。
  • 第二种是方法调用模式,如果一个函数作为一个对象的方法来调用时,this 指向这个对象。
  • 第三种是构造器调用模式,如果一个函数用 new 调用时,函数执行前会新创建一个对象,this 指向这个新创建的对象。
  • 第四种是 apply 、 call 和 bind 调用模式

这四种方式,使用构造器调用模式的优先级最高,然后是 apply、call 和 bind 调用模式,然后是方法调用模式,然后是函数调用模式。

2.call() 和 apply() 的区别?

它们的作用一模一样,区别仅在于传入参数的形式的不同。

  • apply 接受两个参数,第一个参数指定了函数体内 this 对象的指向,第二个参数为一个带下标的集合,这个集合可以为数组,也可以为类数组,apply 方法把这个集合中的元素作为参数传递给被调用的函数。
  • call 传入的参数数量不固定,跟 apply 相同的是,第一个参数也是代表函数体内的 this 指向,从第二个参数开始往后,每个参数被依次传入函数。

3 this 关键字含义是什么?

this总是返回一个对象,this就是属性或方法“当前”所在对象。由于对象的属性可以赋值给另一个对象,所以属性所在的当前对象是可变的,即this指向是可变的

4 为什么需要this指向属性和方法“当前”所在对象?

在函数体内部获得当前函数的运行环境(context),this出现了,它的设计目的就是在函数体内部,指代函数当前的运行环境。

5 cookie、session、localStorage、sessionStorage区别

(1). 区分cookie、session与localStorage、sessionStorage

cookie和session都是参与服务器通信的,而localStorage和sessionStorage不参与服务器通信。

(2) 区分cookie与session

cookie的作用是在客户端保持状态,比如登录状态。它被存储在本地硬盘或内存里,并且在发送http请求的时候会被放进请求头中参与通信。每个cookie最大为4k,每个域名可以拥有的cookie数量在不同浏览器中是不同的,但都多于20个,早期的20个限制已经不存在了。

session的作用是在服务器端保持状态,它被存储在服务器上。session被创建的时候会生成一个sessionid,它被存储在cookie中用来访问session。由于关闭浏览器不会导致session被删,迫使服务器为session设置了失效时间。

(3) 区分localStorage与sessionStorage

localStorage和sessionStorage都属于webStorage本地存储,不参与服务器通信。而且它们都属于window对象,最大存储都在5M左右。

区别在于localStorage是永久存储。而sessionStorage的存储时间是当前会话,关闭页面或浏览器就会被清除。localStorage可以用来长期保存登陆信息。而sessionStorage可以用来一次性保存登陆信息,而且不同浏览器不共享。

(4) 为什么要用sessionStorage,用全局js对象不行吗?

一旦刷新页面全局js对象就不在了,而sessionStorage还在。

10月13日

1 DOM事件模型和事件流?

DOM事件模型包括事件捕获(自上而下触发)与事件冒泡(自下而上触发,ie用的就是冒泡)机制。基于事件冒泡机制可以完成事件代理
DOM事件流包括三个阶段事件捕获阶段、处于目标阶段、事件冒泡阶段

2 require/import之间的区别

(1)require是CommonJS语法,import是ES6语法;
(2)require只在后端服务器支持,import在高版本浏览器及Node中都可以支持;
(3)require引入的是原始导出值的复制,import则是导出值的引用;
(4)require时运行时动态加载,import是静态编译;
(5)require调用时默认不是严格模式,import则默认调用严格模式.

3. 什么是AJAX?如何实现?

   ajax是一种能够实现局部网页刷新的技术,可以使网页异步刷新。
ajax的实现主要包括四个步骤:
(1)创建核心对象XMLhttpRequest;
(2)利用open方法打开与服务器的连接;
(3)利用send方法发送请求;("POST"请求时,还需额外设置请求头)
(4)监听服务器响应,接收返回值。

4. 回流和重绘

  • 重绘:重新绘制 比如:字体颜色和背景色发生变化

  • 回流 :比如元素位置或大小发生变化
    例子 有一个重新装修的活 想改墙的颜色 这就叫重绘 又想改一下房子的结构 在改墙的颜色 这就叫回流 也就是说 回流之后一定会经过重绘的过程

  • 性能方面 回流的性能开销一定大于重绘
    很明显 同样是返工 重绘相当于一面墙重新刷漆 而回流相当于从新砌墙在刷漆 显然性能开销更大

  • 性能优化

  1. 能重绘尽量不要回流
  2. 能少回流就少
  3. 能小区域不大区域回流
  4. 避免无效回流
  5. 利用GPU资源

5. 防抖和节流

  • 防抖
    频繁去触发一个事件,但是只触发最后一次。以最后一次为准
    使用场景
  1. 电脑息屏时间,每动一次电脑又重新计算时间
  2. input框变化频繁触发事件可加防抖
  3. 频繁点击按钮提交表单可加防抖
  • 节流
    频繁去触发一个事件,但是只能每隔一段时间触发一次
    使用场景
  1. 滚动频繁请求列表可加节流
  2. 游戏里长按鼠标,但是动作都是每隔一段时间做一次

6.什么是高阶函数

如果一个函数接受另一个函数作为参数,那么我们称该函数为高阶函数 ,像数组的map、reduce、filter这些都是高阶函数

10月14日

1 什么是函数柯里化?

它将一个接收多参数的函数转化为接 收部分参数的函数。柯里化后的函数只传 递部分参数来调用,并返回一个新的函数 去处理剩余的参数,是逐步传参的过程

  • 例子
function add(a){
  return function(b,c){
    return a+b+c
  }
}
const a =add(1)
console.log(a(2,2));
console.log(a(2,2));

2 AMD 和 CMD 的区别?

模块化代表应用特点
AMDrequire.js1、AMD的api默认一个当多个用 2、依赖前置,异步执行
CMDsea.js1、CMD的api严格区分,推崇职责单一 2、依赖就近,按需加载,同步执行

3 JS中如何将页面重定向到另一个页面?

4 函数 f2 执行后为什么返回了 undefined

let f1 = () => '前端自习课';
f1(); // -> '前端自习课'

let f2 = () => {};
f2(); // -> undefined

这本质原因是因为箭头函数返回的 {} 是箭头函数语法的一部分

5、绑定点击事件有几种方式?

三种

  • xxx.onclick = function (){}
  • <xxx onclick=""></xxx>
  • xxx.addEventListener('click', function(){}, false)

6、addEventListener的第三个参数是干嘛的?

第三个变量传一个布尔值,需不需要阻止冒泡,默认是false,不阻止冒泡

数组的常用方法有哪些?

方法作用是否影响原数组
push在数组后添加元素,返回数组长度
pop删除数组最后一项,返回被删除项
shift删除数组第一项,并返回被删除项
unshift数组开头添加元素,返回新数组长度
reserve反转一个数组,返回修改后的数组
sort排序一个数组,返回修改后的数组
splice截取数组,返回被截取的区间
join将一个数组所有元素连接成字符串并返回这个字符串
concatarr1.concat(arr2, arr3) 连接数组
joinarr.join(x)将arr数组元素连接成字符串并返回这个字符串
map操作数组每一项并返回一个新数组
forEach遍历数组,没有返回值
filter对数组所有项进行判断,返回符合规则的新数组
some数组有符合规则的一项就返回true
reduce接收上一个return和数组的下一项
slice截取数组,返回被截取的区间

7 函数声明和函数表达式的区别?

  • 函数声明:享受函数提升
  • 函数表达式:归类于变量声明,享受变量提升
  • 函数提升优先级 > 变量提升优先级
console.log(fun) // fun () {}
// 函数表达式
var fun = function(name) {}
// 函数声明
function fun () {}
console.log(fun) // fun (name) {}

8.说一下图片的懒加载和预加载

什么是图片懒加载

  • 图片懒加载又叫图片延迟(按需)加载
  • 在需要的时候加载图片
  • 更好的加载页面的首屏内容 无需考虑整个页面

什么是图片预加载

  • 提前加载将来可能会用到的图片