前言
又到一波面试准备的时刻,整理了一波前端相关要点内容,配合
chatGPT
完成要点内容整理,有纠正错误和需要补充的小伙伴可以在这里留言,及时更新。
- 跟chatGPT一起复习前端 —— HTML & CSS
- 跟chatGPT一起复习前端 —— JavaScript
- 跟chatGPT一起复习前端 —— Vue
- 跟chatGPT一起复习前端 —— React
- 跟chatGPT一起复习前端 —— Webpack
- 跟chatGPT一起复习前端 —— 浏览器
- 跟chatGPT一起复习前端 —— 计算机网络
- 跟chatGPT一起复习前端 —— Vite
- 跟chatGPT一起复习前端 —— TypeScript
- 跟chatGPT一起复习前端 —— 安全问题
- 跟chatGPT一起复习前端 —— 前端工具
- 跟chatGPT一起复习前端 —— 手写方法
- 跟chatGPT一起复习前端 —— 数据结构与算法
变量声明
以下输出结果:
console.log(name);
console.log(age);
var name = "张三";
let age = 21;
在第一行代码中,name是使用var关键字声明的变量,它会被提升到作用域的顶部,因此在该行代码执行之前,name已经被声明了,但是它还没有被赋值。因此第一行代码的输出结果是undefined。
在第二行代码中,age是使用let关键字声明的变量,它不会被提升到作用域的顶部。由于在该行代码执行之前,age还没有被声明,因此在该行代码执行时会抛出ReferenceError异常。
在第三行代码中,name被赋值为"Lydia"。
在第四行代码中,age被赋值为21。
以下输出结果:
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 1);
}
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 1);
}
在第一段代码中,i是使用var关键字声明的变量,它的作用域是整个函数。在每次循环中,setTimeout函数会被调用,并且会创建一个闭包,该闭包中包含了对i的引用。由于setTimeout函数的回调函数是异步执行的,因此在循环结束后,i的值已经变成了3。因此第一段代码的输出结果为3、3、3。
在第二段代码中,i是使用let关键字声明的变量,它的作用域是块级作用域。在每次循环中,setTimeout函数会被调用,并且会创建一个闭包,该闭包中包含了对i的引用。由于i是一个块级作用域变量,在每次循环中都会重新声明和初始化。因此第二段代码的输出结果为0、1、2。
let d = 13;
const c = 5;
(function() {
a = b = 3;
let d = 2;
})()
e = 5;
console.log(a);
console.log(b);
console.log(c);
console.log(d);
console.log(e);
类型转换
以下输出结果:
+true;
!"张三";
在第一行代码中,+true将true转换为数字1。
在第二行代码中,"张三"是一个非空字符串,因此它的布尔值为true。!运算符将其转换为false。
new操作符
以下输出结果:
function Foo() {
this.a = 1;
return { a: 2,b: 3 };
}
Foo.prototype.a = 4;
Foo.prototype.b = 5;
Foo.prototype.c = 6;
const x = new Foo();
console.log(x.a, x.b, x.c);
在这段代码中,Foo是一个构造函数。在构造函数中,this.a被赋值为1,但是在函数的最后,它返回了一个新的对象{ a: 2,b: 3 }。因此在创建新对象时,this.a的值被覆盖了。
在这个例子中,x是通过new关键字创建的一个新对象。由于Foo.prototype.a、Foo.prototype.b和Foo.prototype.c都是Foo的原型属性,因此它们都可以通过x访问到。x.a的值为2,因为在构造函数中返回的对象中a被赋值为2。x.b的值为3,因为在构造函数中返回的对象中b被赋值为3。x.c的值为undefined,因为它不是在构造函数中定义的属性,并且它也不是通过返回的对象定义的属性。
this指向
以下输出结果:
let obj = {a: function() {
console.log(this)
}}
obj.a()
let b = obj.a
b()
在第一行代码中,obj.a是一个函数,它被调用时,this指向的是obj对象本身,因此第一行代码的输出结果是{ a: [Function: a] }。
在第二行代码中,b是一个函数,它的值等于obj.a。当b被调用时,this指向的是全局对象window(或global),因此第二行代码的输出结果是Window {…}。
这是因为在JavaScript中,函数的this指向取决于函数的调用方式。如果函数作为对象的方法被调用,this指向该对象;如果函数作为普通函数被调用,this指向全局对象window(或global)。
以下输出结果:
let obj = {a: () => {
console.log(this)
}}
obj.a()
let b = obj.a
b()
在第一行代码中,obj.a是一个箭头函数,它没有自己的this,因此它的this指向的是定义时所在的作用域,也就是全局对象window(或global)。因此第一行代码的输出结果是Window {…}。
在第二行代码中,b是一个函数,它的值等于obj.a。由于箭头函数没有自己的this,因此b被调用时,this指向的仍然是定义时所在的作用域,也就是全局对象window(或global)。因此第二行代码的输出结果也是Window {…}。
以下输出结果:
const shape = {
radius: 10,
diameter() {
return this.radius * 2;
},
perimeter: () => 2 * Math.PI * this.radius
};
shape.diameter();
shape.perimeter();
在这段代码中,shape是一个对象,它有一个radius属性和两个方法:diameter和perimeter。
在diameter方法中,this.radius指向的是shape对象的radius属性。因此diameter方法返回的值为20。
在perimeter方法中,this指向的是定义时所在的作用域,也就是全局对象window(或global)。由于在全局对象中并没有定义radius属性,因此this.radius的值为undefined。当undefined乘以2时,返回的结果为NaN。
事件循环
以下输出结果:
const promise = new Promise((resolve, reject) => {
console.log(1);
console.log(2);
});
promise.then(() => {
console.log(3);
});
console.log(4);
当执行到 promise.then(() => {console.log(3);})
; 时,then
方法会被放入微任务队列中,等待主线程执行完毕后再执行。所以,当主线程执行完毕后,会先输出 4,然后再执行微任务队列中的 then
方法,但是,由于没有 resolve
,所以 then
方法不会被执行。 输出1 2 4
以下输出结果:
const promise1 = new Promise((resolve, reject) => {
console.log('promise1')
resolve('resolve1')
})
const promise2 = promise1.then(res => {
console.log(res)
})
console.log('1', promise1);
console.log('2', promise2);
当执行到 console.log('1', promise1);
时,promise1
已经被 resolve
,所以输出结果为 <resolved>: "resolve1"
。
当执行到 console.log('2', promise2);
时,promise2
还没有被 resolve
,所以输出结果为 <pending>
。
当执行到 const promise2 = promise1.then(res => {console.log(res)});
时,then
方法会被放入微任务队列中,等待主线程执行完毕后再执行。所以,当主线程执行完毕后,会先输出 promise1
和 <resolved>: "resolve1"
,然后再执行微任务队列中的 then
方法,输出 resolve1
。
以下输出结果:
const promise = new Promise((resolve, reject) => {
console.log(1);
setTimeout(() => {
console.log("timerStart");
resolve("success");
console.log("timerEnd");
}, 0);
console.log(2);
});
promise.then((res) => {
console.log(res);
});
console.log(4);
当执行到 console.log(1);
时,输出 1
。
当执行到 console.log(2);
时,输出 2
。
当执行到 setTimeout(() => {console.log("timerStart");resolve("success");console.log("timerEnd");}, 0);
时,setTimeout
方法会被放入宏任务队列中,等待主线程执行完毕后再执行。所以,当主线程执行完毕后,会先输出 4
,然后再执行宏任务队列中的 setTimeout
方法,输出 timerStart
和 timerEnd
,并且将 Promise 状态改为 resolved
。
当执行到 promise.then((res) => {console.log(res);});
时,then
方法会被放入微任务队列中,等待主线程执行完毕后再执行。所以,当主线程执行完毕后,会先输出 success
。
以下输出结果:
Promise.resolve().then(() => {
console.log('promise1');
const timer2 = setTimeout(() => {
console.log('timer2')
}, 0)
});
const timer1 = setTimeout(() => {
console.log('timer1')
Promise.resolve().then(() => {
console.log('promise2')
})
}, 0)
console.log('start');
当执行到 console.log('start');
时,输出 start
。
当执行到 Promise.resolve().then(() => {console.log('promise1');const timer2 = setTimeout(() => {console.log('timer2')}, 0)});
时,then
方法会被放入微任务队列中,等待主线程执行完毕后再执行。所以,当主线程执行完毕后,会先输出 promise1
。
当执行到 const timer1 = setTimeout(() => {console.log('timer1')Promise.resolve().then(() => {console.log('promise2')})}, 0)
时,setTimeout
方法会被放入宏任务队列中,等待主线程执行完毕后再执行。所以,当主线程执行完毕后,会先输出 timer1
。
当执行到 Promise.resolve().then(() => {console.log('promise2')})
时,then
方法会被放入微任务队列中,等待主线程执行完毕后再执行。所以,当主线程执行完毕后,会先输出 promise2
。
当执行到 const timer2 = setTimeout(() => {console.log('timer2')}, 0)
时,setTimeout
方法会被放入宏任务队列中,等待主线程执行完毕后再执行。所以,当主线程执行完毕后,会先输出 timer2
。
以下输出结果:
console.log(1)
setTimeout(() => {
console.log(2)
})
new Promise(resolve => {
console.log(3)
resolve(4)
}).then(d => console.log(d))
setTimeout(() => {
console.log(5)
new Promise(resolve => {
resolve(6)
}).then(d => console.log(d))
})
setTimeout(() => {
console.log(7)
})
console.log(8)
代码执行时,会发生以下情况:
- 执行
console.log(1)
,输出1
。 - 执行
setTimeout(() => {console.log(2)})
,将回调函数添加到事件循环中。稍后将执行它。 - 执行
new Promise(resolve => {console.log(3);resolve(4)}).then(d => console.log(d))
。调用 Promise 构造函数,传入一个回调函数,该函数记录3
并解析为值4
。在 Promise 对象上调用then
方法,将回调函数添加到微任务队列中。稍后将执行它。 - 执行
setTimeout(() => {console.log(5);new Promise(resolve => {resolve(6)}).then(d => console.log(d))})
,将回调函数添加到事件循环中。稍后将执行它。 - 执行
setTimeout(() => {console.log(7)})
,将回调函数添加到事件循环中。稍后将执行它。 - 执行
console.log(8)
,输出8
。 - 处理微任务队列,并执行在步骤 3 中添加的回调函数。它记录
4
。 - 事件循环处理步骤 2 中添加的第一个回调函数,并记录
2
。 - 事件循环处理步骤 4 中添加的第二个回调函数,并记录
5
。它还创建一个新的 Promise 对象,该对象解析为值6
。在此 Promise 对象上调用then
方法,并将回调函数添加到微任务队列中。稍后将执行它。 - 再次处理微任务队列,并执行在步骤 9 中添加的回调函数。它记录
6
。 - 事件循环处理步骤 5 中添加的第三个回调函数,并记录
7
。