什么是作用域?这是老生常谈的问题了,作用域分为:
- 全局作用域
- 函数作用域
- 块级作用域(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