欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 房产 > 建筑 > javaScript-系统知识点【作用域 和 闭包】

javaScript-系统知识点【作用域 和 闭包】

2025/5/3 6:32:16 来源:https://blog.csdn.net/qq_39234910/article/details/145894651  浏览:    关键词:javaScript-系统知识点【作用域 和 闭包】

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

this 的五种情况, 在下面知识点已经解释了

2. 手写 bind 函数

// 模拟 bind
Function.prototype.bind1 = function () {// 将参数拆解为数组 (列表 变成 数组)// arguments 可以直接获取, 传进来的所有参数const args = Array.prototype.slice.call(arguments);// 获取 this(数组第一项)const t = args.shift();// fn1.bind(...) 中的 fn1const 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);
const res = fn2();
console.log(res);

[扩展] - bind、apply、call 的使用场景

  • call 用于继承比较多
  • apply 用于获取数组最大最小值
  • bind 改变定时器 this 的指向

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

什么是闭包?

函数的内部函数运行访问外部上下文,这就是闭包

应用:

  1. 防抖、节流
  2. 柯里化 (电商购物车,不常见)

应用场景: 隐藏数据

// 闭包隐藏数据,只提供 API
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') )

4. 读代码

// 创建 10 个 `<a>` 标签, 点击的时候弹出对应的序号
let i, a
for (i = 0; i < 10; i++) {a = document.createElement('a')a.innerHTML = i + '<br>'a.addEventListener('click', function (e) {e.preventDefault()alert(i)})document.body.appendChild(a)
}
// 输出结果 点击弹出窗 弹出都是 10
// 如何 改写成  点击的时候弹出对应的序号, 如 点击1, 弹出 1
let a
for (let i = 0; i < 10; i++) {a = document.createElement('a')a.innerHTML = i + '<br>'a.addEventListener('click', function (e) {e.preventDefault()alert(i)})document.body.appendChild(a)
}
// 现在点击的时候弹出对应的序号

下面就是相关知识点


知识点:

  • 作用域和自由变量

  • 闭包

  • this

(一)

作用域

  • 全局作用域
  • 函数作用域
  • 块级作用域 ( ES6新增 let )

作用域代表了一个变量或者说某个变量的合理使用范围

请添加图片描述

自由变量

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

(二)

闭包

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

  • 函数作为参数 被传递
  • 函数作为返回值 被返回
// 函数作为返回值
function create() {let a = 100return function () {a += 1console.log(a)}
}// const fn = create()
// fn() // 101
// fn() // 102
// fn() // 103// 函数作为参数被传递
function print(fn) {const a = 200fn()
}
const a = 100
function fn() {console.log(a)
}
print(fn) // 100// 所有的自由变量的查找,是在函数定义的地方,向上级作用域查找
// 不是在执行的地方!!!

闭包的产生原因:内部的函数存在外部作用域的引用就会导致闭包

JS 闭包经典使用场景和含闭包必刷题

总结: 闭包就是一种特殊的函数, 分两种形式的闭包

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

(三)

this

this 取什么值, 是在执行的时候确定的, 不是在函数定义时确定的, 适用于以下五种

  • 作为普通函数 (返回 window)
  • 使用 call、apply、bind (传入什么就绑定什么)
  • 作为对象方法被调用 (返回对象本身)
  • 在 class 方法中调用 (返回实例本身)
  • 箭头函数 (由它的上级作用域决定)

call、apply、bind

call、bind 都会改变 this 的指向, 但是 bind 会返回一个函数, 需要重新运行这个函数

// call
function fn1() {console.log(this)
}
fn1() //windowfn1.call({ x: 100 }) // { x: 100 }// bind
const fn2 = fn1.bind({ x: 200 })
fn2() // { x: 200 }// apply
const numbers = [5, 6, 2, 3, 7];
const max = Math.max.apply(null, numbers);console.log(max);
// Expected output: 7
const min = Math.min.apply(null, numbers);
console.log(min);
// Expected output: 2

箭头函数

箭头函数 this 的值取它上级作用域的值

// 使用 普通函数异步中 this 指向 window
const zhangsan = {name: ’张三‘,sayHi() {// this 即当前对象console.log(this)},wait() {setTimeout(function() {// this === windiowconsole.log(this)})}
}
// 使用 箭头函数异步中 this 即当前对象
const zhangsan = {name: '张三',sayHi() {// this 即当前对象console.log(this)},waitAgain() {setTimeout(() => {// this 即当前对象console.log(this)})}
}

class 方法中

class People {constructor(name) {this.name = namethis.age = 20}sayHi() {console.log(this)}
}
const zhangsan = new People('张三')
zhangsan.sayHi() // zhangsan 对象

5. 防抖、节流

防抖

概念

多次触发,在规定时间内,只有最后一次执行

如何实现

应用场景

窗口调整、搜索框实时联想、按钮频繁点击

节流

概念

每隔一段时间,执行一次

如何实现

应用场景

页面滚动、DOM 元素拖拽、播放事件算进度

6. 闭包中变量如何释放?

let fn = function(){let sum = 0return function(){sum++console.log(sum);}
}
fn1 = fn() 
fn1()   // 1
fn1()   // 2
fn1()   // 3
fn1 = null // fn1的引用fn被手动释放了
fn1=fn()  // num再次归零
fn1() // 1

7. 闭包是什么, 有什么特征? 有什么负面影响?

闭包:

在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁

特征:

作用域和自由变量

重点:

自由变量的查找, 要在函数定义的地方 (而非执行的地方)

影响:

变量会常驻内存, 得不到释放, 闭包不要乱用

可能会造成内存泄漏, 但是闭包中的数据, 我们不知道什么时候会被释放, 所以不算内存泄漏

内存泄漏是指, 内存中的变量一直没被使用, 常驻在内存中

// 自由变量示例 —— 内存会被释放
let a = 0
function fn1() {let a1 = 100function fn2() {let a2 = 200function fn3() {let a3 = 300return a + a1 + a2 + a3}fn3()}fn2()
}
fn1()// 闭包 函数作为返回值 —— 内存不会被释放
function create() {let a = 100return function () {console.log(a)}
}
let fn = create()
let a = 200
fn() // 100

开发过程中什么时候用到闭包?

  1. 使用异步请求的时候, 异步请求以函数作为参数进行传递, 这就是一个闭包
  2. 还有就是 我们写防抖节流函数, 也是需要使用保存局部变量进行计数, 然后返回回调函数, 这也是闭包的使用
  3. 函数柯里化, 也是一种闭包的使用, 函数作为返回值

任何闭包的使用场景的目的:

  • 创建私有变量
  • 延长变量的生命周期

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词