前端JS面试题-基础-作用域和闭包

时间:2021-07-11
本文章向大家介绍前端JS面试题-基础-作用域和闭包,主要包括前端JS面试题-基础-作用域和闭包使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
写在前面:本文内容主要根据慕课网双越老师的付费课程“一天时间迅速准备前端面试 快速构建初级前端知识体系 ”进行编写,主要是为了自己在面试前总结学习,欢迎留言指教。

本文包括如下内容:

每一部分包括题目知识点两部分。

作用域和闭包

题目

  1. this的不同应用场景,如何取值
  2. 手写bind函数
  3. 实际开发中闭包的应用场景,举例说明
  4. 场景题

1. this的不同应用场景,如何取值

有5种应用场景,如下:

  • 作为普通函数——返回window
  • 使用 call apply bind——传入什么绑定什么
  • 作为对象方法被调用——返回对象本身
  • 在class方法中调用——当前实例本身
  • 箭头函数——上级作用域

2. 手写bind函数

bind() 方法会创建一个新函数,当这个新函数被调用时,它的 this 值是传递给 bind() 的第一个参数, 它的参数是 bind() 的其他参数和其原本的参数。

//模拟 bind
Function.prototype.bind1 = function () {
  // 将参数拆解为数组
  const args = Array.prototype.slice.call(arguments)

  //获取 this (数组第一项)
  const t = args.shift()

  // fn1.bind(···)中的 fn1
  const self = this

  //返回一个函数
  return function () {
    return self.apply(t, args)
  }
}

// 使用
function fn1(a, b, c) {
  console.log('this', this)
  console.log(a, b, c)
  return 'this is fn1'
}

const fn2 = fn1.bind1({x: 100}, 10, 20, 30)
console.log(fn2())

// 结果
this {x: 100}
10 20 30
this is fn1

3. 实际开发中闭包的应用场景,举例说明

闭包的应用场景

  • 函数作为返回值,以cache缓存为例:
function createCache() {
  const data = {} //闭包中的数据被隐藏,不被外界访问
  return {
    set: function (key, val) {
      data[key] = val
    },
    get: function (key) {
      return data[key]
    }
  }
}

const c = createCache()
c.set('a', 100)
console.log(c.get('a'))
  • 函数作为参数被传递,以setTimeout定时器为例:
function fn() {
	alert()
}
const func = fn()
// 第一个参数是一个函数,或者是一段执行的js代码,第二参数是第一个参数执行的时间间隔。
setTimeout(func, 1000)
被面试官问到什么是闭包,最好的回答就是把两个 demo 写一遍,然后说出闭包的使用场景【cache缓存 setTimeout定时器 异步操作 等】。不用说什么概念。

4. 场景题

这个代码打印出来的序号都是 10,应该在for里定义let i,这样需要都是递增的。

知识点

1. 作用域

  • 全局作用域
  • 函数作用域
  • 块级作用域(ES6新增)【大括号内是一个块级作用域】

2. 自由变量【当前作用域未定义的变量】

  • 一个变量在当前作用域没有定义,但被使用了
  • 向上级作用域,一层一层一次寻找,直至找到为止
  • 如果到全局作用域都没找到,则报错 xx is not defined

所有的自由变量的查找,是在函数定义的地方,向上级作用域查找,不是在执行的地方!!!

3. 闭包

作用域引用的特殊情况,有两种表现:

  • 函数作为参数被传递
  • 函数作为返回值被返回

4. this

有5种应用场景,如下:

  • 作为普通函数——返回window
  • 使用 call apply bind——传入什么绑定什么
  • 作为对象方法被调用——返回对象本身
  • 在class方法中调用——当前实例本身
  • 箭头函数——上级作用域
// 普通函数:返回window
function fn1() {
	console.log(this)
}
fn1() //window
// call apply bind:传入什么绑定什么
fn1.call({x: 100}) //{x: 100}
const fn2 = fn1.bind({x:200})
fn2() //{x:200}

// 作为对象方法被调用:返回对象本身
const zhangsan = {
  name: '张三',
  sayhi(){
    console.log(this)
  }
}
zhangsan.sayhi() //{name: "张三", sayhi: ƒ}

// 在class方法中调用:返回实例本身
class People{
  constructor(name){
    this.name = name
  }
  sayhi(){
    console.log(this)
  }
}
const zhangsan = new People('张三')
zhangsan.sayhi() //People {name: "张三"}

// 箭头函数:上级作用域
const zhangsan = {
  name: '张三',
  wait(){
    setTimeout(()=>{
      console.log(this)
    })
  },
  waitAgain(){
    setTimeout(function () {
      console.log(this)
    })
  }
  // 两个函数进行对比
}
zhangsan.wait() //{name: "张三", wait: ƒ, waitAgain: ƒ}
zhangsan.waitAgain() //window

this取什么值,是在函数执行的时候确认的,不是在函数定义的时候确认的

原文地址:https://www.cnblogs.com/wumengcheng/p/14998066.html