老规矩,我们这一知识点今天的讲解还是通过先看题,看了题后去思考该题考察的知识点,然后再讲解知识点,最后又回归到我们的例题中
题目
- this的不同应用场景,如何取值?
- 手写bind函数,改变this指向的方法之一
- 实际开发中闭包的应用场景,举例说明
知识点
- 作用域和自由变量
- 闭包
- this
作用域
一个变量的合法使用范围
- 全局作用域
- 函数作用域
- 块级作用域(ES6新增)
自由变量
- 一个变量在当前作用域没有定义,但被使用了,就是没有声明
- 向上级作用域,一层一层依次寻找,直到找到为止
- 如果全局都没找到,会报错说没有这个变量
闭包
作用域应用的特殊情况,有两种表现:
- 函数作为参数被传递
- 函数作为返回值被返回
从定义的时候去寻找变量取值,向上寻找~
不熟悉的小伙伴,还是自己手敲一下
所有的自由变量的查找,是在函数定义的地方,向上级作用域查找,不是在执行的地方
this
应用场景:
- 作为普通函数
- 使用call apply bind (bind会返回一个新的函数)
- 作为对象方法被调用
- 在class方法中调用
- 箭头函数
this的取值是在执行上下文执行/函数执行的时候确定的
普通函数调用,是看调用方
function fn1 (){
console.log(this)
}
fn1() // window
call改变了调用函数
fn1.call({x:100}) // {x:100}
bind返回了一个新函数,需要重新调用才会执行
const fn2 = fn1.bind({ x:200 })
fn2() // {x:200}
复制代码
const zhangsan = {
name:"张三",
sayHi(){
console.log(this)
},
wait(){
setTimeout(function(){
console.log(this)
})
}
}
zhangsan.sayHi() //this是当前对象
zhangsan.wait() // 因为是setTimeout触发的执行,this指向的是window
复制代码
const zhangsan = {
name:"张三",
sayHi(){
console.log(this)
},
waitAgain(){
setTimeout(()=>{
// this即当前对象
console.log(this)
})
}
}
zhangsan.waitAgain() // 箭头函数内的this指向父级,这里指向当前对象
复制代码
class People {
constructor(name) {
this.name = name
this.age = 20 // this指向当前实例
}
sayHi() {
console.log(this)// this指向当前实例
}
}
const zhangsan = new People('张三')
zhangsan.sayHi() // zhangsan对象
复制代码
手写bind函数
我们先看一般我们bind的使用方法和使用效果
function fn1 (a, b, c){
console.log('this', this)
console.log(a, b, c)
return 'this is fn1'
}
const fn2 = fn1.bind({x:100},10,20,30)
const res = fn2()
console.log(res)
// this {x:100} 10 20 30 this is fn1
fn1.hasOwnProperty('bind') // false
fn1._proto_ // f(){...}
fn1._proto_ === Function.prototype
// 说明Function.prototype上有bind,call,apply这些API
复制代码
// 模拟bind 自己手写bind函数,可以在原型上增加这个方法
Function.prototype.bind1 = function(){
// bind方法不确定内部会给它传多少个参数,所以我们将参数拆解成数组
// arguments可以拿到所有的参数,它是一个列表,但不是一个数组
// 将arguments拆解成数组
const args = Array.prototype.slice.call(arguments)
// 获取 this (第一个参数,也就是数组第一项)
// const arr = [1,2,3,4,5] arr.shift() => 1 且 arr = [2,3,4,5]改变了原数组
const t = args.shift()
// fn1.bind1(...)中的fn1
const self = this
// 返回一个函数
return function (){
return self.apply(t,args)
}
}
const fn2 = fn1.bind1({x:100},10,20,30)
const res = fn2()
console.log(res)
// 手写 apply call bind 都要会
复制代码
闭包的应用
- 隐藏数据
- 做一个cache工具
// 闭包的隐藏,这里只提供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)//只能通过set修改数据或者新增数据
console.log(c.get('a'))//只能通过get拿到数据
复制代码
// 创建10个<a>, 点击弹出的序号
let a
for (let i = 0, i< 10;i++){
// let i 是for内绑定的i,块级作用域,每循环一次就会新增一个块级作用域
a = document.createElement('a')
a.innerHTML = i + '<br>'
a.addEventListener('click',function(e){
// click事件不会立马执行
e.preventDefault()
alert(i)
})
document.body.appendChild(a)
}
复制代码
小结
- 作用域和自由变量
- 闭包:两种常见方式&自由变量查找规则
- this,执行的时候确定的;使用场景
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END