• 【进击的JavaScript|高薪面试必看】JS基础-作用域和闭包


    在这里插入图片描述
    一天时间系列文章是博主精心整理的面试热点问题和难点问题,吸收了大量的技术博客与面试文章,总结多年的面试经历,带你快速并高效地审视前端面试知识。直击技术痛点,主动出击,精密打击,这才是面试拿到高薪的秘诀!


    本期介绍

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

    主要内容

    • 什么是作用域?什么是自由变量?
    • 什么是闭包?闭包会用在哪里?
    • this 有几种赋值情况

    关键字

    • 作用域
    • 闭包
    • this

    什么是作用域?

    变量合法的使用范围
    在这里插入图片描述

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

    什么是自由变量?

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

    什么是闭包?

    作用域应用的特殊情况,指有权访问另一个函数作用域中的变量的函数

    有两种情况:

    1. 函数作为参数被传递
    2. 函数作为返回值被返回
    // 函数作为返回值
    function create() {
        let a = 100
        return function () {
            console.log(a)
        }
    }
    let fn = create()
    let a = 200
    fn()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    // 函数作为参数
    function print(fn) {
        let a = 200
        fn()
    }
    let a = 100
    function fn() {
        console.log(a)
    }
    print(fn)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

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

    闭包会用在哪里?

    • 场景一:采用函数引用方式的setTimeout调用
    • 场景二:回调
    • 场景三:函数防抖
    • 场景四:封装私有变量
      实际开发中闭包多用于隐藏数据 ,只提供API进行修改数据

    this 有几种赋值情况

    1. 作为普通函数被调用,指向的是window
    2. 使用call、apply、bind 可以改变this的指向
      apply和call会让当前函数立即执行,而bind会返回一个函数,后续需要的时候再调用执行
      在这里插入图片描述
    3. 作为对象的方法被调用,指向当前对象
    4. 在class方法中调用,指向当前创建的实例constructor
    5. 箭头函数中的this永远是取他上级作用域的this
      在这里插入图片描述
      注意:this取什么值是在函数执行的时候确定的,不是在函数定义的时候确定的

    手写call、apply、bind

    1. 手写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'}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    1. 手写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'}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    1. 手写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'}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    示例:

    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'}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    原理:

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

    补充 - 原型中的 this

    在这里插入图片描述
    注:此原型图解可对照JS基础—原型和原型链中class 实现继承定义的类理解

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

    ✨原 创 不 易 , 还 希 望 各 位 支 持
    👍 点 赞 , 你 的 认 可 是 我 创 作 的 动 力
    ⭐️ 收 藏 , 你 的 青 睐 是 我 努 力 的 方 向
    ✏️ 评 论 , 你 的 意 见 是 我 进 步 的 财 富

  • 相关阅读:
    STM32F4X UCOSIII 消息队列
    信奥要学哪些数学知识 学信奥要不要先学python
    String转JsonObject 再转list<Map<String,Object>>
    业务架构·应用架构·数据架构实战~战略驱动的业务架构设计
    升级版多功能版在线WEB工具箱PHP源码/在线站长工具箱源码/php多功能引流工具箱源码
    【iOS】多线程梳理
    Java SpringBoot VII
    时间复杂度与空间复杂度
    Linux发展史和Linux系统安装
    Smartforms 打印出现的问题
  • 原文地址:https://blog.csdn.net/qq_37215621/article/details/126800197