前言:大家好,我是忆白,本文根据慕课网双越老师《一天时间迅速准备前端面试 快速构建初级前端知识体系》课程整理的面试常考题目以及相应知识扩展,持续更新。
1. 值类型和引用类型
常见值类型:
- undefined
- String字符串
- Number
- Boolean
- Symbol(ES6)新增
常见引用类型:
- 对象Object
- Array数组
- null (特殊引用类型,指针指向为空地址)
- function 函数(特殊引用类型,但不用于存储数据)
2. typeof运算符
- 能识别所有的值类型(输出类型字符串如:"string")
- 识别函数(输出'function')
- 判断是否是引用类型(只输出object,不可再细分)
3. 手写深拷贝
function deepClone(obj = {}) {
if (typeof obj !== 'object' || obj == null) {
// obj 是 null,或者不是引用类型,直接返回
return obj;
}
// 初始化返回结果
let result;
if (obj instanceof Array) {
result = []
} else {
result = {}
}
for (let key in obj) {
// 保证 key 不是原型的属性,hasOwnProperty判断自身是否有指定的属性,因为for...in会遍历原型上的属性
if (obj.hasOwnProperty(key)) {
// 递归
result[key] = deepClone(obj[key]);
}
}
// 返回结果
return result;
}
4. 三种发生类型转换的情况
-
字符串拼接
-
==运算符,==会尝试类型转换之后再判断相等
-
if判断语句,实际是执行两次非运算判断是否是turly变量
以下是falsely变量(除此之外都是 truly 变量):
!!0 === false !!NaN === false !!'' === false !!null === false !!undefined === false !!false === false
5. 如何判断一个变量是不是数组
a instanceof Arraya.__proto__ === Array.prototypeArray.isArray()
instanceof本质也是基于原型链
a instanceof B,本质是如果a沿着原型链能够找到B.prototype,那么就返回true,否则返回false。因此,以上第一二种方法如果修改了原型链,则判断出错。
手写instanceof
const instanceOf = (A, B) => {
let p = A;
while (p) {
if (p === B.prototype) {
return true;
}
p = p.__proto__;
}
return false;
}
console.log(instanceOf(1, Number)); // true
console.log(instanceOf([], Array)); // true
console.log(instanceOf([], Object)); // true
6. class的本质,如何理解
class是一种语法糖
- class是ES6的新特性,用来定义一个类。
- class有构造方法constructor、属性、方法
- 子类可以通过extends继承父类,通过super调用父类构造方法
class本质也是通过原型来实现的
比如定义一个类Person,定义一个类Student继承自Person,通过Student创建一个实例zhangsan。
则zhangsan.__proto__ === Student.prototype、Student.prototype.__proto__ === Person.prototype。
有关原型链,可以参考我的另一篇文章:JS原型与原型链
7. 作用域和自由变量
作用域
- 全局作用域
- 函数作用域
- 块级作用域(ES6新增)
自由变量
自由变量的值:现在本级作用域查找,如果未找到,向上级作用域依次查找,直到找到为止,如果到全局作用域都未找到,则报错 xxx is not defined。
8. this 的不同应用场景,如何取值?
this的取值,是在函数执行的时候确定的,不是在函数定义的时候确定的。
- 全局作用域或者普通函数中this指向全局对象window(注意定时器中的this指向window)
- 对象调用方法时,指向调用方法的对象本身
- 构造函数中this指向构造函数实例
- 箭头函数的this指向它声明时作用域的this
- 定时器中的this指向window(但如果定时器回调是使用箭头函数声明,则指向声明时作用域的this)
- 事件绑定方法的回调,this指向绑定对象
- 使用
call、apply、bind改变this指向,传入什么,this就绑定什么
9. 手写bind函数
// 模拟 bind
Function.prototype.mybind = function () {
// 将参数拆解为数组
const args = Array.from(arguments);
// 获取 this(第一个参数,即数组第一项)
const t = args.shift();
// 此时this是fn1.bind(...)中的 fn1
const self = this;
// 返回一个函数
return function() {
return self.apply(t, args)
}
}
10. 什么是闭包?闭包会用在哪里?
闭包
-
作用域应用的特殊情况,有两种表现:
-
函数作为参数被传递
function print(fn) { let a = 200; fn(); } let a = 100; function fn() { console.log(a); } print(fn); // 打印100 -
函数作为返回值被返回
function create() { let a = 100; return function() { console.log(a); } } let fn = create(); let a = 200; fn(); // 打印100
所有自由变量的查找,是在函数定义的位置向上级作用域查找,不是在函数执行的位置!!
实际开发中闭包的应用场景
- 设置私有变量
- 函数节流、防抖
- 循环中拿到正确的值
写在最后
如果你觉得我写的还不错,可以给我点个赞哦,如果有写错的地方,也欢迎大家评论指出,谢谢。