Hiccup
发布于 2021-03-06 / 30 阅读
0
0

JavaScript-作用域和闭包

作用域和闭包

纲要

产出

  • 学会作用域和闭包

  • 学会 this 的所有用法

主要内容

  • 什么是作用域?什么是自由变量?

  • 什么是闭包?闭包会用在哪里?

  • this 有几种赋值情况?

关键字

  • 作用域

  • 闭包

  • this

1.作用域

let a = 0;
function fn1() {
    let b = 100;
    function fn2() {
        console.log("a:" + a + ",b:" + b);
    }
}
  • 全局作用域

  • 函数作用域

  • 块级作用域(ES6新增)

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

2.自由变量

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

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

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

3.闭包

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

  • 函数作为参数被传递;

  • 函数作为返回值被返回;

// 函数作为返回值
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

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

4. this

  • 作为普通函数 [返回window]

  • 使用 call apply bind [传入什么,绑定什么]

  • 作为对象方法被使用 [返回对象本身]

  • class方法中调用 [返回实例对象本身]

  • 箭头函数 [找它上一级作用域的this的值]

注:this 取值,是在函数执行的时候确认的;

例:

function fn1() {
    console.log(this);
}
// 返回window
fn1(); // window
// 传入什么,绑定什么
fn1.call({x:100}); // {x:100}
const fn2 = fn1.bind({x:200});
fn2(); // {x:200}

注:bind 会返回新的函数

const zhangsan = {
    name: '张三',
    sayHi() {
        // this 即当前对象
        console.log(this);
    },
    wait() {
        setTimeout(function() {
            // this === window
            console.log(this);
        })
    }
}

vs

const zhangsan = {
    name: '张三',
    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函数

Function.prototype.bind1 = function() {
    // 将参数解析为数组
    const args = Array.prototype.call(arguments);
    // 获取 this (数组第一项)
    const t = args.shift();
    // 
    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);
// 执行结果如下
// this {x:100}
// 10, 20, 30
// this is fn1

实际开发中闭包的作用

  • 隐藏数据

  • 如:做一个简单的cache工具

// 闭包隐藏数据,只提供API
function createCache() {
    const data = {};
    return {
        set: function(key, val) {
            data[key] = val;
        },
        get: function(key) {
            return data[key];
        }
    }
}



评论