javascript复习:作用域和自由变量

问题

  • this 的不同应用场景,如何取值
  • 手写 bind 函数
  • 实际开发中闭包的应用场景,举例说明

知识点

  • 作用域和自有变量
  • 闭包
  • this

知识点:作用域

作用域

  • 全局作用域
    代码中写一个变量,不受函数的约束,在全局都可随意使用(window,document)
  • 函数作用域
    受函数的约束,函数内使用,函数外无法使用
  • 块级作用域(ES6新增)
    if,for,while花括号内,let

知识点:自由变量

如我在全局中定义了一个变量a,然后我在函数中使用了这个a,这个a就可以称之为自由变量,可以这样理解,凡sss是跨了自己的作用域的变量都叫自由变量。

1
2
3
4
5
var a = "追梦子";
function b(){
console.log(a); //追梦子
}
b();

如下最内圈,a, a1, a2 就是自有变量
作用域

知识点:闭 包

函数作为返回值

1
2
3
4
5
6
7
8
9
10
function create(fn) {
const a = 100;
return function () {
console.log(a);
}
}

let fn = create();
let a = 200;
fn(); // 100

函数作为参数

1
2
3
4
5
6
7
8
9
10
11
function print (fn) {
const a = 200;
fn();
}

const a = 100;
function fn () {
console.log(a);
}

print(fn); // 100

错误示例:

1
2
3
4
5
6
7
8
9
10
function print (fn) {
const a = 100;
fn();
}

function fn () {
console.log(a);
}

print(fn); // 报错:Uncaught ReferenceError: a is not defined

所有自由变量的查找,实在函数定义的地方向上级组用于查找,不是在执行的地方!!!

知识点:this

使用场景

  • 作为普通函数

    1
    2
    function fn1() { console.log(this) }
    fn1() // Window 
  • 使用call,apply,bind

    1
    2
    3
    4
    function fn1() { console.log(this) }
    fn1.call({ x: 10 }) // { x: 10 }
    const fn2 = fn1.bind({ x: 200 })
    fn2() // { x: 200 }
  • 作为对象方法被调用
    image.png

  • 在class方法调用
    image.png

  • 箭头函数
    箭头函数中的 this 永远取上级作用域的this;

this取什么值是在函数执行的时候确定的,不是定义的确定的;

原题: 创建十个’‘标签,点击的时候弹出对应的序号

1
2
3
4
5
6
7
8
9
for (let i = 0; i < 10; i++) {
a = document.createElement('a');
a.innerHTML = i + '<br/>';
a.addEventListener('click' , (e) => {
e.preventDefault();
console.log(i);
})
document.body.append(a)
}

问题解答:this 的不同应用场景,如何取值

  • 当做普通函数被调用,取window
  • call,apply,bind,this指向传入的对象
  • 作为对象方法调用指向对象本身
  • class 方法中调用,this 指向 实例本身
  • 箭头函数中的 this 永远取上级作用域的this

问题解答:手写 bind 函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
function fn (a, b, c) {
console.log('this:', this);
console.log('a, b, c:', a, b, c);
}

fn() // this: window a, b, c: undefined undefined undefined
const fn1 = fn.bind({x: 200}, 1, 2, 3);
fn1() // this: {x: 200} a, b, c: 1 2 3

Function.prototype.myBind = function () {

// 将参数拆解为数组
let args = Array.prototype.slice.call(arguments);

// 获取 this (数组的第一项)
const t = args.shift();

// 获取 fn1.bind() 的 fn1
const self = this;

// 返回一个函数
return function () {
return self.apply(t, args)
}
}

const fn2 = fn.myBind({ x: 300 }, 1, 2, 3);
fn2() // this: {x: 300} a, b, c: 1 2 3

问题解答:实际开发中闭包的应用场景,举例说明

闭包隐藏数据,只提供 API

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function createCatch () {
const data = {};
return {
set(key, value) {
data[key] = value;
},
get(key) {
return data[key]
}
}
}

const c = createCatch();
c.set('a', 100);
console.log(c.get('a')); // 100