JavaScript 前端面试 4(作用域链、this)

八、作用域链的理解

1:作用域

变量或者函数能生效或者被访问的区域或集合

作用域分为:

|-------|
| 全局作用域 |
| 函数作用域 |
| 块级作用域 |

1.1:全局作用域

任何不在函数或是大括号中声明的变量,都是在全局作用域下,全局作用域下声明的变量可以在程序的任意位置访问

1.2:函数作用域

在函数内部声明智能在函数内部访问

1.3:块级作用域

ES6添加了let 、 const关键字与var(函数作用域)不同,在大括号中使用let 、 const声明的变量存在于块级作用域中,在大括号外不可访问

特性 var let const
作用域 函数作用域或全局作用域 块级作用域 块级作用域
提升 会提升,但不执行初始化 会提升,但存在暂时性死区 会提升,但存在暂时性死区
重复声明 允许重复声明 不允许重复声明 不允许重复声明
重新赋值 允许重新赋值 允许重新赋值 不允许重新赋值(*)
1. 作用域(Scope)
  • var

    声明的变量具有**函数作用域(Function Scope)**或全局作用域。如果在函数外部使用 var,变量将具有全局作用域;在函数内部使用 var,变量将属于函数作用域。

    JavaScript复制

    复制代码
    function testVar() {
        var a = 10;
        if (true) {
            var a = 20; // 在函数作用域里重写 a
            console.log(a); // 输出:20
        }
        console.log(a); // 输出:20
    }
    testVar();
  • letconst

    声明的变量具有块级作用域(Block Scope) ,即在 {} 包围的块(如条件语句、循环、函数等)内部有效。

    JavaScript复制

    复制代码
    function testBlock() {
        let b = 10;
        if (true) {
            let b = 20; // 在块级作用域里重新定义 b
            console.log(b); // 输出:20
        }
        console.log(b); // 输出:10
    }
    testBlock();
    
    const c = 30;
    // 在块外访问 c 有效
    if (true) {
        const c = 40; // 重新定义 c,仅在块内有效
        console.log(c); // 输出:40
    }
    console.log(c); // 输出:30
2. 变量提升(Hoisting)
  • var

    声明的变量会被提升到其作用域的顶部,但初始化不会被提升 。这会导致变量在声明前可以访问(但值为 undefined)。

    JavaScript复制

    复制代码
    console.log(x); // 输出:undefined
    var x = 10;
  • letconst

    声明的变量也会被提升,但它们在声明前访问会抛出 ReferenceError,因为它们存在"暂时性死区"(Temporal Dead Zone)。

    JavaScript复制

    复制代码
    console.log(y); // 抛出 ReferenceError
    let y = 20;
    
    console.log(z); // 抛出 ReferenceError
    const z = 30;
3. 重复声明(Redeclaration)
  • var

    允许重复声明同一个变量。

    JavaScript复制

    复制代码
    var a = 10;
    var a = 20; // 不会报错,值被覆盖
    console.log(a); // 输出:20
  • letconst
    不允许重复声明同一个变量。

    JavaScript复制

    复制代码
    let b = 10;
    let b = 20; // 抛出 SyntaxError: Identifier 'b' has already been declared
    
    const c = 30;
    const c = 40; // 抛出 SyntaxError
4. 是否可修改(Reassignment)
  • varlet

    声明的变量可以重新赋值。

    JavaScript

    复制代码
    var a = 10;
    a = 20; // 允许
    console.log(a); // 输出:20
    
    let b = 10;
    b = 20; // 允许
    console.log(b); // 输出:20
  • const

    声明的变量是一个常量,不能重新赋值

    JavaScript复制

    复制代码
    const c = 10;
    c = 20; // 抛出 TypeError: Assignment to constant variable.

    例外情况 :如果 const 声明的值是对象或数组,其属性或元素可以修改,但不能重新赋值整个变量。

JavaScript

复制代码
  const obj = { name: 'Alice' };
  obj.name = 'Bob'; // 允许,修改对象属性
  console.log(obj.name); // 输出:Bob

  const arr = [1, 2];
  arr.push(3); // 允许,修改数组
  console.log(arr); // 输出:[1,2,3]

  arr = [4,5]; // 抛出 TypeError

2:词法作用域

又叫作静态作用域,变量被创建时就确定好了,而非执行阶段确定的

foo 和 bar相同层级无法访问彼此的变量,所以输出2

3:作用域链

JavaScript使用一个变量时,首先会在当前作用域寻找,如果没有找到就去上层作用域寻找,以此类推直到找到该变量,或者是到全局作用域

如果全局作用域仍然找不到,就会在全局范围内隐式声明该变量或者直接报错

作用域就是一个建筑,这份建筑代表程序的嵌套作用域链,第一层代表当前的执行作用域,顶层代表全局作用域,变量的引用顺着当前楼层想上找一旦到达顶层查找过程都会停止

九、谈谈对this对象的理解

1:this对象的定义

this关键字是函数运行时自动生成的一个内部对象,只能在函数内部使用,总指向它的对象

this在函数执行过程中,this一旦被确定了就不可以再更改了。

2:绑定规则

|-------|
| 默认绑定 |
| 隐式绑定 |
| new绑定 |
| 显示绑定 |

2.1:默认绑定
输出jenny的原因是在调用函数的对象在浏览器中位于window,因此this指向window

注:严格模式下不能将全局对象用于默认绑定,this会绑定到undefined,只有在非严格模式下,默认绑定才能绑定到全局对象

2.2:隐式绑定

函数还可以作为某个对象的方法调用,这时this就指这个上级对象

这个函数中包含多个对象,尽管这个函数是被最外层的对象所调用,this指向的也只是它上一级的对象

this的上一级对象是b,b内部没有没有变量a的定义,所以输出undefined

this指向window ,this最终指向的是最后调用它的对象,虽然fn是对象b的方法,但是fn赋值给j时候并没有执行,最终指向window

2.3:new绑定

通过构建函数new关键字生成一个实例对象,此时this指向这个实例对象

new关键字改变this的指向

new过程遇到return一个对象,此时this指向为返回的对象

如果返回一个简单类型的时候,则this指向实例对象

虽然null也是对象,但是new也只指向实例对象

2.4:显示修改

apply()、call()、bind()是函数的一个方法,作用是改变函数的调用对象。它的第一个参数就表示改变后的调用这个函数的对象。因此,这时this指的就是协这第一个参数

最后输出1

3 :箭头函数

在代码书写的时候就能确定this的指向

4 : 优先级

4.1:隐式绑定和显示绑定

显示绑定的优先级更高

4.2 :new绑定和隐式绑定

new绑定的优先级大于隐式绑定

4.3 :显示绑定和new绑定

因为new和apply、call无法一起使用,所以换成硬绑定(也是显示绑定的一种)

bar被绑定到obj1上但是new bar(3)并没有像我们预计的那样帮obj1.a修改为3.但是new修改了绑定调用bar()中的this,我们任务new绑定的优先级>显示绑定

综上所述:new绑定的优先级>显示绑定的优先级>隐式绑定的优先级

相关推荐
集成显卡几秒前
Bun.js + Elysia 框架实现基于 SQLITE3 的简单 CURD 后端服务
开发语言·javascript·sqlite·bun.js
不如摸鱼去24 分钟前
从 Wot UI 出发谈 VSCode 插件的自动化发布
前端·vscode·开源·自动化
im_AMBER36 分钟前
JavaScript 03 【基础语法学习】
javascript·笔记·学习
IT_陈寒1 小时前
Python开发者必看:这5个鲜为人知的Pandas技巧让你的数据处理效率提升50%
前端·人工智能·后端
豆苗学前端1 小时前
写给女朋友的第一封信,测试方法概论
前端·后端·设计模式
半桶水专家2 小时前
Vue 3 插槽(Slot)详解
前端·javascript·vue.js
袁煦丞2 小时前
本地AI绘画神器+全局访问——Stable Diffusion WebUI 成功突破:cpolar内网穿透实验室第462个成功挑战
前端·程序员·远程工作
一枚前端小能手2 小时前
🏗️ JavaScript类深度解析 - 从构造函数到现代特性的完整指南
前端·javascript
袁煦丞2 小时前
家用NAS+云盘自由NanoPi R4S+iStoreOS:cpolar内网穿透实验室第460个成功挑战
前端·程序员·远程工作
浏览器API调用工程师_Taylor2 小时前
日报自动化实战:告别手动复制粘贴
前端·javascript·node.js