1.1 运行题
var name = 'window'
var person1 = {
name: 'person1',
foo1: function () { //形成作用域
console.log(this.name)
},
foo2: () => console.log(this.name), //外层作用域是window,对象不属于作用域
foo3: function () {
return function () { //所调用的是哪个函数,call所指向的this对象会有所不同的答案
console.log(this.name)
}
},
foo4: function () {
return () => {
console.log(this.name) //被函数包裹着形成作用域,要是foo4函数里面没有相关name值,就继续向上一级作用域继续找nane变量,所以是找到person1.name 为止
}
}
}
var person2 = { name: 'person2' }
person1.foo1() //person1
person1.foo1.call(person2) //person2
person1.foo2() //window
person1.foo2.call(person2) //window
person1.foo3()() //window
person1.foo3.call(person2)() //window
person1.foo3().call(person2) //person2
person1.foo4()() //person1
person1.foo4.call(person2)() //person2 指向person2对象 其里面有name变量
person1.foo4().call(person2) //person1 与调用函数位置没有关系,与函数所在位置执行上下文有关系
1.2 运行题
var name = 'window'
function Person(name) {
this.name = name
this.foo1 = function () {
console.log(this.name)
},
this.foo2 = () => console.log(this.name),
this.foo3 = function () {
return function () {
console.log(this.name)
}
},
this.foo4 = function () {
return () => {
console.log(this.name)
}
}
}
var person1 = new Person('person1')
var person2 = new Person('person2')
person1.foo1()//person1 .foo1的前面是person1,所以this指向person1对象
person1.foo1.call(person2)//person2 通过call改变this指向成为person2对象
person1.foo2()//person1 箭头函数的this执行上下文
person1.foo2.call(person2)//person1 箭头函数的this不可以直接通过call、bind、apply直接进行修改
person1.foo3()()//window
person1.foo3.call(person2)()//window person1.foo3.call(person2)虽然执行person2的函数,但是返回的仍是function(){console.log(this.name)} this指向的是window作用域
person1.foo3().call(person2)//person2 最后的函数进行调用的时候通过call改变this指向成为person2对象
person1.foo4()()//person1 箭头函数,执行上下文,向上级作用域查找变量
person1.foo4.call(person2)()//person2 第一个()是函数(非箭头函数)时通过call改变this指向成为person2对象,其有name变量
person1.foo4().call(person2)//person1 箭头函数不能直接通过call改变this指向
1.3 运行题
var name = 'window'
function Person(name) {
this.name = name
this.obj = {
name: 'obj',
foo1: function () {
return function () {
console.log(this.name)
}
},
foo2: function () {
return () => {
console.log(this.name)
}
}
}
}
var person1 = new Person('person1')
var person2 = new Person('person2')
person1.obj.foo1()()// window
person1.obj.foo1.call(person2)() //window 第一个()函数调用通过call改变this指向成为person2对象,但返回 function(){console.log(this.name)} 其this指向还是window
person1.obj.foo1().call(person2) //person2 第二个()函数(非箭头函数)的this通过call改变成为person2对象
person1.obj.foo2()()//obj 箭头函数,执行上下文,向上级作用域进行查找
person1.obj.foo2.call(person2)()// person2 第一个()函数(非箭头函数)通过call改变this指向成为person2对象,其里面箭头函数的上级作用域就是person2
person1.obj.foo2().call(person2)//obj 第二个()箭头函数执行,不能直接通过call来改变this指向,其箭头函数执行上下文向上级作用域进行查找
1.4 运行题
运行结果:输出 2
备注:var a = 2 改为 let a = 2,输出为 undefined
2.1 运行题
2.2 运行题
2.3 运行题
答案依次是: ‘resolve1’ ‘finally’ undefined ‘timer1’ Promise{
: undefined}
注意的知识点:
Promise的状态一旦改变就无法改变
finally不管Promise的状态是resolved还是rejected都会执行,且它的回调函数是接收不到Promise的结果的,所以finally()中的res是一个迷惑项。
最后一个定时器打印出的p1其实是.finally的返回值,我们知道.finally的返回值如果在没有抛出错误的情况下默认会是上一个Promise的返回值, 而这道题中.finally上一个Promise是.then(),但是这个.then()并没有返回值,所以p1打印出来的Promise的值会是undefined,如果你在定时器的下面加上一个return 1,则值就会变成1
2.4 运行题
答案依次是:(使用的是浏览器chrome v80出现的结果) ‘test start…’ ‘执行testSometing’ ‘promise start…’
‘test end…’
‘testSometing’
‘执行testAsync’
‘promise’
‘hello async’
‘testSometing’ ‘hello async’
//知识点:
//紧跟着await后面的语句相当于放到了new Promise中,下一行及之后的语句相当于放在Promise.then中
//正常情况下,async中的await命令是一个Promise对象,返回该对象的结果。但如果不是Promise对象的话,就会直接返回对应的值,相当于Promise.resolve()
//后面的数字代表出现的顺序
async function testSometing() {
console.log("执行testSometing"); //2
return "testSometing";//5
}
async function testAsync() {
console.log("执行testAsync"); //6
return Promise.resolve("hello async");//8
}
async function test() {
console.log("test start..."); //1
const v1 = await testSometing();
console.log(v1);//进入微任务1 --- 5
const v2 = await testAsync(); //6
console.log(v2); // 进入微任务1-1 --- 8
console.log(v1, v2);// 9
}
test();//从这个开始
var promise = new Promise(resolve => {
console.log("promise start..."); //3
resolve("promise");//进入微任务2 ---7
});
promise.then(val => console.log(val));//7
console.log("test end..."); //4
2.5 运行题
答案依次是: 0 ‘Error: 0’ 1 2 3
Promise.all()的作用是接收一组异步任务,然后并行执行异步任务,并且在所有异步操作执行完后才执行回调。
.race()的作用也是接收一组异步任务,然后并行执行异步任务,只保留取第一个执行完成的异步操作的结果,其他的方法仍在执行,不过执行结果会被抛弃。
Promise.all().then()结果中数组的顺序和Promise.all()接收到的数组顺序一致。
all和race传入的数组中如果有会抛出异常的异步任务,那么只有最先抛出的错误会被捕获,并且是被then的第二个参数或者后面的catch捕获;但并不会影响数组中其它的异步任务的执行。
2.6 运行题
答案依次是: ‘promise1里的内容’ ‘promise1’ Promise{
} ‘promise2’ Promise{ } ‘timer1’ test5.html:102 Uncaught (in promise) Error: error!!! at test.html:102 ‘timer2’ ‘promise1’ Promise{ : “success”} ‘promise2’ Promise{ : Error: error!!!}
//后面的数字是执行的顺序
const promise1 = new Promise((resolve, _reject) => {
setTimeout(() => {//宏任务1 ---先执行
resolve("success");//传递给下一then函数执行的命令
console.log("timer1");//4
}, 1000);
console.log("promise1里的内容");//1
});
const promise2 = promise1.then(() => {//等待resolve()的调用才可以执行,微任务1
throw new Error("error!!!");// 直接进行报错 Error: error!!! --- 5
});
console.log("promise1", promise1);//2
console.log("promise2", promise2);//3
setTimeout(() => {//宏任务2
console.log("timer2");//6
console.log("promise1", promise1);//7
console.log("promise2", promise2);//8
}, 2000);
2.7 运行题
答案依次是: 1
finally2
finally
inally2后面的then函数 2
需要注意的 知识点
.finally()
方法不管Promise
对象最后的状态如何都会执行.finally()
方法的回调函数不接受任何的参数,也就是说你在.finally()
函数中是没法知道Promise
最终的状态是resolved
还是rejected
的- 它最终返回的默认会是一个上一次的Promise对象值,不过如果抛出的是一个异常则返回异常的
Promise
对象。3.1 运行题
答案是 “” 空字符串
此时打印出来的结果function fn() {
console.dir(this)
console.log(this.name);
}
//...
打开控制台上的window后查找name
属性:3.2 运行题
```javascript var obj = { a: 1, foo: function (b) {
} } var a = 2 var obj2 = { a: 3 }b = b || this.a //前面是undefined和unll的时候取后面的数值
console.log(b)//2 3
return function (c) {
console.log(this.a + b + c)
}
//讲解:obj.foo(a[此时实参a的值为2,赋值形参b数值为2]) === 此时的函数 function (c) {console.log(this.a + b + c)} 此时.call(obj2,1) this指向obj2,传入参数1 this.a为3(this指向obj2对象,其属性a值为3) b向上级作用域查找得2 传入参数1赋值给形参c 所以总共是6 obj.foo(a).call(obj2, 1) // 6
//讲解:obj.foo.call(obj2) obj.foo函数的this指向obj2对象 没有传入实参给形参b,此时b为undefined 经过 b=b||this.a 重新赋值为 3(obj2对象里面有a值为3) === function (c) {console.log(this.a + b + c)} 后又传输参数1,此时形参c被赋值为1 b通过上级作用域查找得到值为3 此时函数内的this指向window,所以this.a的值为2 所以总共是6 obj.foo.call(obj2)(1)// 6
<a name="IDkZ2"></a>
## 3.3 运行题

```javascript
var i = 20;
function fn() {
i -= 2; // i = 18
return function (n) {//传入参数1
console.log(++i - n); // 18+1-1=18 此时i值是19
};
}
var f = fn();
f(1);//此时i值是19
function fn() {
// 经过f(1)函数的调用,此时i是19
i -= 2;
return function (n) {// 传入参数 n=2
console.log(++i - n); //19+1-2=18 此时i值是20
};
}
var f = fn();
f(1);
f(2);//直接调用这个函数 function (n) {console.log(++i - n);}
function fn() {
// 经过f(2)函数的调用,此时i是20
i -= 2; //i=18
return function (n) {// 传入参数3
console.log(++i - n); //18+1-3=16 此时i值是19
};
}
var f = fn();
f(1);
f(2);
fn()(3);//此时i值是19
function fn() {
// 经过fn()(3)函数的调用,此时i是19
i -= 2; //i=17
return function (n) {// 传入参数4
console.log(++i - n); //17+1-4=14 此时i值是18
};
}
var f = fn();
f(1);
f(2);
fn()(3);
fn()(4);//此时i值是18
var i = 20;
function fn() {
// 经过fn()(4)函数的调用,此时i是18
i -= 2;
return function (n) {// 传入参数5
console.log(++i - n); //18+1-5=14 此时i值是19
};
}
var f = fn();
f(1);
f(2);
fn()(3);
fn()(4);
f(5);//直接调用function (n) { console.log(++i - n) };
console.log(i);//19
//答案:18 18 16 14 14 (函数内部打印的结果)
// 19(i 最后的值)
3.4 运行题
3.5 运行题
使用 var: 每一次for循环的时候,setTimeout都执行一次, 但是里面的函数没有被执行,而是被放到了任务队列里面,等待执行, for循环了4次,就放了4次,当主线程执行完成后,才进入任务队列里面执行。使用 let:for循环头部的let不仅将i绑定到for循环块中, 它也将其重新绑定到 循环体的每一次迭代 中,确保上一次迭代结束的值重新被赋值。 setTimeout里面的function()属于一个新的域, 通过 var 定义的变量是无法传入到这个函数执行域中的, 而通过使用 let 来声明块变量,这时候变量就能作用于这个块, 所以 function就能使用 i 这个变量了; 这个匿名函数的参数作用域 和 for参数的作用域 不一样。