快速搞定JS前端面试 -- 第四章 JS基础-作用域和闭包

第四章 JS基础-作用域和闭包

一、作用域

二、自由变量

三、闭包

四、this的使用

五、题目解答

1. this在不同场景下应该如何取值?

2. 手写bind函数?

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

4. 场景题 创建10个标签,点击的时候弹出对应序号

六、小结


题目

  1. this在不同场景下应该如何取值?
  2. 手写bind函数?
  3. 实际开发中闭包的应用场景,举例说明?
  4. 创建10个<a>标签,点击的时候弹出对应序号

知识点

  1. 作用域和自由变量
  2. 闭包
  3. This

一、作用域

作用域代表一个变量的合法使用范围

三级作用域:

全局作用域(全局都可以使用,如document对象)

函数作用域(一个函数中定义的只能在当前函数使用)

块级作用域(ES新增)(块:包含if while等包含大括号,在大括号外使用会报错)

// ES6 块级作用域
If ( true ){
Let x = 100
}
Console.log( x )     // 会报错

二、自由变量

一个变量在当前作用域没有定义,但是被使用了

会向上级作用域,一层一层依次寻找,直到找到为止

如果到全局作用域都没有找到,则报错xx is not defined

三、闭包

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

  1. 函数作为参数被传递(函数在一个地方定义好之后,到另一个地方去执行)
  2. 函数作为返回值被返回(函数定义好之后会被返回到另一个地方执行)
// 函数作为返回值
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的使用

使用场景:

  1. 作为普通函数调用
  2. 使用call apply bind被调用
  3. 作为对象方法被调用
  4. 在class方法中被调用
  5. 箭头函数

注意:this取什么样的值,是在函数执行的时候确定的,不是在函数定义的时候决定的

// 作为普通函数调用
function fn1() {
fonsole.log( this )
}    
fn1()    // this是全局变量window

// 使用call调用
fun1.call( { x: 100 })    // this是对象{ x: 100 }

// 使用bind调用
const fn2 = fn1.bind({ x: 200 })    // bind会返回新的函数执行
fn2   // this是对象{ x: 200 }

// 作为对象方法被调用
Const zhangsan = {
    Name: ‘zhangsan’,
    sayHi() {
        // this是当前对象
        Console.log(this)    // 作为对象方法执行
    },
    wait() {
       setTimeout( function () {
           // this === window
          console.log(this)   // 相当于作为普通函数调用
       })
    },
    waitAgain() {
       setTimeout( () => {  
        // 箭头函数永远取上级作用域的this即相当于waitAgain中的this,相当于sayHi中的this,都是指当前对象
          // this是当前对象
          console.log(this)
     })
   }
}	

class People {
    constructor(name) {
        this.name = name
        this.age = 20
    }
    eat() {
        console.log(this)    // this代表xialuo实例
    }
}
const xialuo = new Student('夏洛', 100)
xialuo.sayHi()    

五、题目解答

1. this在不同场景下应该如何取值?

  (1)作为普通函数调用 -- 返回window

  (2)使用call apply bind被调用 -- 传入什么绑定什么

  (3)作为对象方法被调用 -- 返回对象本身(如果是隐式原型的方法 -- undefined)

  (4)在class方法中被调用 -- 返回当前实例本身

  (5)箭头函数 -- 永远会找上级作用域this的值来确定

2. 手写bind函数?

// 模拟 bind
Function.prototype.bind1 = function () {
    // 将参数拆解为数组
    const args = Array.prototype.slice.call(arguments)
    // 获取 this(数组第一项)
    const t = args.shift()     // 拿走数组第一项
    // fn1.bind(...) 中的 fn1
    const self = this
    // bind返回一个函数
    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)

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

隐藏数据,如做一个简单的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)
console.log( c.get('a') )

如果想不通过get和set修改data的值是没有办法的,因为data是在createCache的作用域里的,不会被外界访问到

4. 场景题 创建10个<a>标签,点击的时候弹出对应序号

错误情况:(点击每个标签都是弹出10)

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)
}

因为代码很快就会遍历完成执行,创建a标签时,click事件还没有执行,只有点击才会执行。因此当每个a标签被点击时,i已经变成10了(因为i是全局作用域)

解决:把let i放在里面。则i是块作用域,每次for循环执行的时候都会形成一个相应的块,i不一样

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)
}

因此这里的考点就是:(对于不会立刻执行的函数)全局作用域or块级作用域

六、小结

  1. 作用域和自由变量
  2. 闭包:两种常见方式&自由变量查找规则
  3. This使用
发布了26 篇原创文章 · 获赞 6 · 访问量 1389

猜你喜欢

转载自blog.csdn.net/Sabrina_cc/article/details/105496638