6 - 作用域和闭包

252 阅读2分钟

题目

  • this的不同应用场景,如何取值?

    • 作为普通函数
    • 使用call apply bind
    • 作为对象方法被调用
    • 在class方法中调用
    • 箭头函数
    • (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)    
}

知识点

  • 作用域和自由变量
    • 全局作用域、函数作用域、块局作用域(ES6新增)
  • 闭包
  • this

作用域和自由变量

image.png

//ES6块级作用域
if(true){
    let x = 100
}
console.log(x) //会报错

自由变量

  • 一个变量在当前作用域没有定义,但被使用了
  • 向上级作用域,一层一层依次寻找,直至找到为止
  • 如果到全局作用域都没有找到,则报错 xx is not defined

闭包

闭包:自由变量的查找,是在函数定义的地方,向上级作用域查找,不是在执行的地方!

//函数作为返回值
function create(){
    let a = 100
    return function(){
        console.log(a)
    }
}
let fn = create()
let a = 200
fn() //100
//函数作为参数
function print(fn){
    let a = 200
    fn()
}
let a = 100
function fn(){
    console.log(a)
}
print(fn) //100

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:'zs',
    sayHi(){
        //this即当前对象
        console.log(this)
    },
    wait(){
        setTimeout(function(){
            //this === window 
            console.log(this)
        })
    }
}

const lili = {
    name:'lili',
    sayHi(){
        //this即当前对象
        console.log(this)
    },
    waitAgain(){
        setTimeout(()=>{
            //this 即当前对象
            console.log(this)
        })
    }
}
class People{
    constructor(name){
        this.name = name,
        this.age = 20
    }
    sayHi(){
        console.log(this)
    }
}
const zhangsan = new People('张三')
zhangsan.sayHi() //zhangsan对象

手写bind函数

bind 基本用法

function fn1(a,b,c){
    console.log(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);
//打印:
//{x:100}
//10 20 30
//this is fn1

手写bind

//模拟bind
Function.prototype.bind1 = function(){
    //将参数拆解为数组
    const args = Array.prototype.slice.call(arguments)
    //获取this(数组第一项)
    const _this = args.shift();
    //fn1.bind(...)中的fn1
    const self = this;
    //返回一个函数
    return function(){
        return self.apply(_this,args)
    }
}

function fn1(a,b,c){
    console.log(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);
//打印:
//{x:100}
//10 20 30
//this is fn1