课程来源:coding.imooc.com/learn/list/…
题目
- this的不同应用场景,如何取值?
- 手写bind函数
- 实际开发中闭包的应用场景,举例说明
- 场景题目
// 创建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)
}
知识点
- 作用域和自由变量
- 闭包
- this
一、作用域和自由变量
- 全局作用域
- 函数作用域
- 块级作用域(ES6新增)
// ES6块级作用域
if (true) {
let x = 100
}
console.log(x) // 会报错
自由变量
- 一个变量在当前作用域没有定义,但被使用了
- 向上级作用域,一层一层一次寻找,直至找到为止
- 如果到全局作用域都没找到,则报错 xx is not defined
二、闭包
作用域应用的特殊情况,有两种表现:
- 函数作为参数被传递
- 函数作为返回值被返回
// 函数作为返回值
function create() {
const a = 100
return function () {
console.log(a)
}
}
const fn = create()
const a = 200
fn() // 100
// 函数作为参数
function print(fn) {
const a = 200
fn()
}
const a = 100
function fn() {
console.log(a)
}
print(fn) // 100
所有的自由变量的查找(规则),是在函数定义的地方,向上级作用域查找,不是在执行的地方。
三、this
五种this使用场景:
- 作为普通函数被调用
- 使用call apply bind
- 作为对象方法被调用
- 在class方法中调用
- 箭头函数
this在各个场景中取什么样的值,是在函数执行时候确定,不是在函数定义时候确定的。
function fn1() {
console.log(this)
}
fn1() // window
fn1.call({ x: 100 }) // { x: 100 }
const fn2 = fn1.bind({ x: 200 })
fn2() // { x: 200 }
const zhangsan = {
name: '张三'
sayHi() {
// this 即当前对象
console.log(this)
},
wait() {
setTimeout(function() {
// this === window
console.log(this)
})
}
}
const zhangsan = {
name: '张三'
sayHi() {
// this 即当前对象
console.log(this)
},
waitAgain() {
setTimeout(() => {
// this 即当前对象
console.log(this)
})
}
}
class People {
constructor(name) {
this.name = name
this.age = age
}
sayHi() {
console.log(this)
}
}
const zhangsan = new People('张三')
zhangsan.sayHi() // zhangsan 对象
四、问题补充解答
手写bind函数
// 模拟 bind
Function.prototype.bind1 = function () {
// 将参数解析为数组
const args = Array.prototype.slice.call(arguments)
// 将arguments作为Array.prototype.slice的this赋值
// 获取 this (数组第一项)
const t = args.shift()
// fn1.bind(...) 中的 fn1
const 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)
实际开发中闭包的应用
- 隐藏数据
- 如做一个简单的cache工具
// 闭包隐藏数据,只提供API
function createCache() {
const data = {} // 闭包中的数据,被隐藏,不被外界访问
return {
set: function (key, val) {
data[key] = val;
},
get: function (key) {
return data[key]
}
}
}
const c = createCathe()
c.set('a', 100)
console.log( c.get('a') )
创建10个<a>标签,点击的时候弹出来对应的序号
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)
}
————————————————————————————————————————