首页 JavaScript作用域
文章
取消

JavaScript作用域

什么是作用域?这是老生常谈的问题了,作用域分为:

  • 全局作用域
  • 函数作用域
  • 块级作用域(es6)

this指针

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const obj = {
    f1() {
        const fn = () => {
            console.log('this1', this)
        }
        fn()
        fn.call(window)
    },
    f2: () => {
        function fn() {
            console.log('this2', this) 
        }
        fn()
        fn.call(this)
    }
}

obj.f1()  // 两次输出this指向obj对象
obj.f2()  // 两次输出window
  • obj.f1() 调用时输出两次,f1方法有两次调用 fn() fn.call(window),fn我们看到它是一个箭头函数,箭头函数this指向父级作用域(f1方法),所以第一次调用fn()时this指向obj对象。 fn.call(window)使用call改变fn方法this指针传递了winodw,我们要清楚一点,fn方法在定义时使用的是箭头函数,箭头函数与普通函数有很多区别比如:无法实例化没有arguments没有自己的this无法改变this指向不能作为构造函数(不能使用new)。其中就是有无法改变this指向,因为它没有自己的this故无法改变。所以第二次输出打印this指向依然是obj对象

  • obj.f2() 中f2的方法是箭头函数,上面我们讲到箭头函数this指向父级作用域(window)。fn.call(this)因为f2()this指向了window,所以fn.call(this)传递this等于就是传递了window。所以最终输出的两次结果都是window。

this在class中

1
2
3
4
5
6
7
8
9
10
11
12
class Foo {
    f1() { console.log('this1', this) }
    f2 = () => { console.log('this2', this) }
    f3 = () => { console.log('this3', this) }
    static f4() { console.log('this4', this) }
}

const f = new Foo()
f.f1()              // this指向类FOO实例化后对象
f.f2()              // this指向类FOO实例化后
f.f3.call(this)     // this指向类FOO实例化后
Foo.f4()            // this指向class Foo 本身
  • 箭头函数在class类中this指向的类Foo实力化后的对象,所以f.f1() f.f2() f.f3.call(this)输出的this执行实例化的对象,其中f.f3.call(this)无法改变this指向,因为f3方法是一个箭头函数。 Foo.f4()输出是类本身,我们看到f4方法在定义时使用了static这是一个静态方法声明,静态方法是不需要实例化就可以直接调用的,它调用时使用的是类Foo.f4()所以指向类本身。注意:静态方法不可以被实例化对象调用。

块级作用域

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
for (var index = 0; index < 10; index++) {
    const button = document.createElement('button')
    button.innerHTML = index
    button.addEventListener('click', function() { alert(index)})
    document.body.appendChild(button)
}
// 点击输出结果都是 10

// 使用var声明的index只有两种作用域,全局及函数作用域,所以在for循环结束后index会累积加到10,alert弹出时取值10


or

for (let index = 0; index < 10; index++) {
    const button = document.createElement('button')
    button.innerHTML = index
    button.addEventListener('click', function() { alert(index)})
    document.body.appendChild(button)
}

// 依次点击输出结果为 0、1、2、3、4、5、6、7、8、9

// 使用let声明的变量index具有块级作用域,每次迭代都会创建一个新的index变量,并且该变量会被绑定到当前块级作用域。因此,每个按钮的点击事件都会捕获到相应迭代时的index值。

严格模式 use scritc

  • 全局变量必须先声明
  • 禁止使用 with
  • 创建 eval 作用域
  • 禁止 this 指向 window
  • 函数参数不能重名

for in 与 for of 区别

  • for...in 用于可枚举数据,如对象、数组、字符串
  • for...of 用于可迭代数据,如数组、字符串、Map、Set
转摘分享请注明出处

WeakMap和weakSet

vue自定义v-model