作用域和自由变量
作用域
- 作用域是在运行时代码中的某些特定部分中变量,函数和对象的可访问性。换句话说,作用域决定了代码区块中变量和其他资源的可见性。
分为:
一个变量在当前作用域没有定义,但是被使用了。
向上级作用域一层层依次寻找,直到找到为止。
在最里面一层里,a a1 a2都没定义,就向外层寻找,找到对应的值。
闭包
作用域应用的特殊情况,有两种表现:
函数作为参数被传递
// 函数作为返回值
function create () {
let a = 100
return function () {
// 在这里,a是一个自由变量,向外寻找定义,a=100
console.log(a);
}
}
const fn = create()
const a = 200
fn() // 100
函数作为返回值被返回
// 函数作为参数传递
function print (fn) {
let a = 200
fn()
}
const a = 100
function fn () {
// 在这里,a也是一个自由变量,向外寻找定义,a=100
console.log(a);
}
print(fn) // 100
自由变量的查找,是在函数定义的地方,向上级作用域查找,不是在函数执行的地方。
this
场景和取值:
- 作为普通函数——>返回window
- 使用 call apply bind——>传入什么参数绑定什么
- 作为对象方法被调用——>返回对象本身
- 在class方法中调用——>返回实例本身
- 箭头函数——>找上级作用域的值来确定
- this取什么值是在函数运行的时候确定的,不是函数定义的时候确定的。
demo1
function fn1 () {
console.log(this);
}
fn1() // window
fn1.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是window
console.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上
// 手写bind
Function.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)中的fn1
const 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, a
for (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,每次循环都会产生新的块级作用域。