作用域和闭包的知识点和题目

59 阅读3分钟

作用域和闭包的知识点和题目。包括作用域,自由变量,闭包,this 等部分。作用域是 “JS 三座大山” 之二,不知道闭包的话,面试通过概率不大。

主要内容 什么是作用域?什么是自由变量? 什么是闭包?闭包会用在哪里? this 有几种赋值情况 关键字 作用域 闭包 this 什么是作用域? 变量合法的使用范围

全局作用域: 在全局都可以使用 函数作用域: 只能在当前函数内使用 块级作用域(ES6新增): if,for,while语法里 // ES6 块级作用域 if (true) { let x = 100 } console.log(x) // 会报错

什么是自由变量? 一个变量在当前作用域没有定义,但被使用了 向上级作用域一层一层依次寻找,直到找到为止 如果到全局作用域都没找到,则报错 xx is not defind 什么是闭包? 作用域应用的特殊情况,指有权访问另一个函数作用域中的变量的函数

有两种情况:

函数作为参数被传递 函数作为返回值被返回 // 函数作为返回值 function create() { let a = 100 return function () { console.log(a) } } let fn = create() let a = 200 fn()

// 函数作为参数 function print(fn) { let a = 200 fn() } let a = 100 function fn() { console.log(a) } print(fn)

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

闭包会用在哪里? 场景一:采用函数引用方式的setTimeout调用 场景二:回调 场景三:函数防抖 场景四:封装私有变量 实际开发中闭包多用于隐藏数据 ,只提供API进行修改数据 this 有几种赋值情况 作为普通函数被调用,指向的是window 使用call、apply、bind 可以改变this的指向 apply和call会让当前函数立即执行,而bind会返回一个函数,后续需要的时候再调用执行

作为对象的方法被调用,指向当前对象 在class方法中调用,指向当前创建的实例constructor 箭头函数中的this永远是取他上级作用域的this

注意:this取什么值是在函数执行的时候确定的,不是在函数定义的时候确定的 手写call、apply、bind 手写call function myCall() { const content = [].shift.call(arguments) || window; content.fn = this; const result = content.fn(...arguments); delete content.fn; return result; } Function.prototype.myCall = myCall; fn.myCall(obj, 'arg1', 'arg2'); // {a: '这是obj'}

手写apply function myApply() { const content = [].shift.call(arguments) || window; content.fn = this; const result = content.fn(...arguments[0]); delete content.fn; return result; } Function.prototype.myApply = myApply; fn.myApply(obj, ['arg1', 'arg2']); // {a: '这是obj'}

手写bind function myBind() { const content = [].shift.call(arguments) || window; content.fn = this; const args = arguments; return () => { const result = content.fn(...args); delete content.fn; return result; } } Function.prototype.myBind = myBind; fn.myBind(obj, 'arg1', 'arg2')(); // {a: '这是obj'}

示例:

const obj = {a: '这是obj'}; function fn(arg1, arg2) { console.log(this); } fn.call(obj, 'arg1', 'arg2'); // {a: '这是obj'} fn.apply(obj, ['arg1', 'arg2']); // {a: '这是obj'} fn.bind(obj, 'arg1', 'arg2')(); // {a: '这是obj'}

原理:

3个方法第一个参数为新的执行环境,所以是一个对象 将当前执行环境赋值给新环境的某个属性 使用新环境调用当前执行环境,相当于一个对象调用方法,方法的this就是这个对象 新环境是一个对象所以为引用类型,新增一个属性会改变自身,所以调用之后获得结果需要删除新增的属性 补充 - 原型中的 this

注:此原型图解可对照JS基础—原型和原型链中class 实现继承定义的类理解

解释: 直接xiaoluo。sayhai,调用对象是xiaoluo,所以this是能找到的 用__proto__原型去访问的话,调用对象是__proto__,所以name和number是未定义的