作用域和自由变量
作用域
- 作用域是在运行时代码中的某些特定部分中变量,函数和对象的可访问性。换句话说,作用域决定了代码区块中变量和其他资源的可见性。
分为:
一个变量在当前作用域没有定义,但是被使用了。
向上级作用域一层层依次寻找,直到找到为止。
在最里面一层里,a a1 a2都没定义,就向外层寻找,找到对应的值。
闭包
作用域应用的特殊情况,有两种表现:
函数作为参数被传递
// 函数作为返回值function create () {let a = 100return function () {// 在这里,a是一个自由变量,向外寻找定义,a=100console.log(a);}}const fn = create()const a = 200fn() // 100
函数作为返回值被返回
// 函数作为参数传递function print (fn) {let a = 200fn()}const a = 100function fn () {// 在这里,a也是一个自由变量,向外寻找定义,a=100console.log(a);}print(fn) // 100
自由变量的查找,是在函数定义的地方,向上级作用域查找,不是在函数执行的地方。
this
场景和取值:
- 作为普通函数——>返回window
- 使用 call apply bind——>传入什么参数绑定什么
- 作为对象方法被调用——>返回对象本身
- 在class方法中调用——>返回实例本身
- 箭头函数——>找上级作用域的值来确定
- this取什么值是在函数运行的时候确定的,不是函数定义的时候确定的。
demo1
function fn1 () {console.log(this);}fn1() // windowfn1.call({ x: 100 }) // { x: 100 }const fn2 = fn1.bind({ x: 200 })fn2() // { x: 200 }
demo2
const zhangsan = {name: 'zs',sayHi () {// this指向当前对象console.log(this);},wait () {setTimeout(function () {// 是window调用的定时器,这里的this是windowconsole.log(this);})}}
demo3
const lisi = {name: 'ls',sayHi () {// this指向当前对象console.log(this);},wait () {setTimeout(() => {// 这里使用了箭头函数。向上级作用域查找,指向当前对象console.log(this);})}}
相关面试题
this的不同应用场景,如何取值?
- 作为普通函数——>返回window
- 使用 call apply bind——>传入什么参数绑定什么
- 作为对象方法被调用——>返回对象本身
- 在class方法中调用——>返回实例本身
- 箭头函数——>找上级作用域的值来确定
手写bind函数
- call bind apply都是定义在Function的prototype上
// 手写bindFunction.prototype.myBind = function () {// 将参数拆解为数组const args = Array.prototype.slice.call(arguments)// 获取fn1.bind({ x: 100 }, 10, 20, 30)中的 { x: 100}// 即bind要绑定的对象。// 即参数第一项,让第一项弹出,剩下的就是参数。const t = args.shift()// fn1.bind({ x: 100 }, 10, 20, 30)中的fn1const self = this// 返回一个函数return function () {return self.apply(t, args)}}
- call bind apply都是定义在Function的prototype上
实际开发中闭包的应用场景,举例说明
- 隐藏数据,如做一个简单的cache工具。
```javascript
// 闭包隐藏数据,只提供API
function createCache () {
// 闭包中的数据,被隐藏,不让外界访问
const data = {}
return {
set: function (key, val) {
}, get: function (key) {data[key] = val
} } }return data[key]
- 隐藏数据,如做一个简单的cache工具。
```javascript
// 闭包隐藏数据,只提供API
function createCache () {
// 闭包中的数据,被隐藏,不让外界访问
const data = {}
return {
set: function (key, val) {
const c = createCache() c.set(‘a’, 100) console.log(c.get(‘a’)); // 100 console.log(c.data); // undefined
```javascript// 创建十个a标签,点击每个a标签的时候弹出相对应的数字let i, afor (i = 0; i < 10; i++) {a = document.createElement('a')a.innerHTML = i + '<br>'a.addEventListener('click', function (e) {e.preventDefault()// 这个函数不是立刻执行,点击的时候执行// 当执行到这行代码的时候,i已经是10了,因为i是全局作用域alert(i)})document.body.appendChild(a)}// 最后发现点击哪个标签都弹出1// 解决方法:在for循环的时候定义i,每次循环都会产生新的块级作用域。

