前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >javascript你必须要知道的——作用域和闭包

javascript你必须要知道的——作用域和闭包

作者头像
江拥羡橙
修改2023-06-09 11:30:52
3600
修改2023-06-09 11:30:52
举报
文章被收录于专栏:前端二次元前端二次元

介绍

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

主要内容

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

什么是作用域?

变量合法的使用范围

  • 全局作用域:在全局都可以使用
  • 函数作用域:只能在当前函数内使用
  • 块级作用域(ES6新增):if,for,while语法里
代码语言:javascript
复制
// ES6 块级作用域
if (true) {
    let x = 100
}
console.log(x) // 会报错
什么是自由变量?
  • 一个变量在当前作用域没有定义,但被使用了
  • 向上级作用域一层一层依次寻找,直到找到为止
  • 如果到全局作用域都没找到,则报错 xx is not defind 什么是闭包? 作用域应用的特殊情况,指有权访问另一个函数作用域中的变量的函数

有两种情况:

  1. 函数作为参数被传递
  2. 函数作为返回值被返回
代码语言:javascript
复制
// 函数作为返回值
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 有几种赋值情况
  1. 作为普通函数被调用,指向的是window
  2. 使用call、apply、bind 可以改变this的指向apply和call会让当前函数立即执行,而bind会返回一个函数,后续需要的时候再调用执行
  1. 作为对象的方法被调用,指向当前对象
  2. 在class方法中调用,指向当前创建的实例constructor
  3. 箭头函数中的this永远是取他上级作用域的this

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

手写call、apply、bind

手写call

代码语言:javascript
复制
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

代码语言:javascript
复制
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

代码语言:javascript
复制
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'}

示例:

代码语言:javascript
复制
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基础—原型和原型链](https://blog.csdn.net/qq_37215621/article/details/126790301)中class 实现继承定义的类理解

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

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-11-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 ELSE前端 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 主要内容
    • 什么是作用域?
      • 闭包会用在哪里?
        • 手写call、apply、bind
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档