前言
继续整理八股文——JS篇,实习上岸!!!
JavaScript篇
1. JS的数据类型有哪些?
undefined、null、boolean、string、number、object、symbol、bigint(ES10)
基本数据类型:undefiend, null, boolean, string, number, symbol, bigint
引用数据类型:Object, Function, Array, Date, RegExp
2. undefined和null有什么区别
undefined代表未定义,null代表控对象
当变量声明了没有被赋值就会返回undefined
null主要用于给对象作初始化
3. var、let、const的区别
- 块级作用域
function a() {
var b;
}
console.log(b) // Uncaught ReferenceError: b is not defined
function a() {
var b;
console.log(b)
}
a() // undefined
If 也存在块级作用域,在if外部使用变量不会报错
console.log(b) // 不输出
if(false) {
var b
console.log(b) // undefined
}
- 变量提升
变量只能在声明之后使用,否则就会报错
console.log(a) // Uncaught ReferenceError: a is not defined
console.log(a) // undefined
var a
- 暂时性死区
不声明变量之前,该变量不可用
总结
| 区别 | var | let | const |
|---|---|---|---|
| 块级作用域 | 无 | 有 | 有 |
| 变量提升 | 有 | 无 | 无 |
| 全局添加属性 | 有 | 无 | 无 |
| 重复声明 | 有 | 有 | 无 |
| 暂时性死区 | 无 | 有 | 有 |
| 初始值 | 无 | 无 | 有 |
| 指针指向 | 有 | 有 | 无 |
4. const属性可以修改吗
可以修改。
对于引用类型的数据来说,const保存的是变量的内存地址。
而我们修改const指向的对象中的属性,是可以修改的。
5. 数据检测方法
- typeof
typeof 1 // 'number'
typeof '1' // 'string'
typeof undefined // 'undefined'
typeof true // 'boolean'
typeof Symbol() // 'symbol'
typeof null // 'object'
typeof [] // 'object'
typeof {} // 'object'
typeof console // 'object'
typeof console.log // 'function'
- instanceof
- constructor
- Object.prototype.toString.call()
后面三种常用于判断所有的引用数据类型
6. ==, ===, Object.is() 有什么区别
== 只判断值是否相同。如果两边的类型不同,会强制转换后再比较
=== 先判断类型是否相同,再判断值是否相同,全满足才为 true
Object.is() 弥补全等操作符的不准确运算。在判断 +0 和 -0 为false,两个NaN为true
7. 作用域和作用域链
作用域
作用域是变量(变量作用域又称上下文)和函数生效的区域或集合。决定了代码区块中变量和其他资源的可见性。
分类
- 全局作用域
不再函数中或是大括号中声明的变量。全局作用域是在window的对象上
var greeting = 'hello'
function greet() {
console.log(greeting)
}
greet() // hello
- 函数作用域
函数作用域也叫局部作用域。如果一个变量在函数内部声明,这个变量只能在函数内部访问。
function greet() {
var greeting = 'hello'
console.log(greeting)
}
greet() // hello
console.log(greeting) // 报错: Uncaught ReferenceError: greeting is not defined
- 块级作用域
let和const声明的变量存在块级作用域,在括号之外不能访问这些变量
{
let greeting = 'hello'
var lang = 'en'
console.log(greeting) // hello
}
console.log(lang) // en
console.log(greeting) // 报错: Uncaught ReferenceError: greeting is not defined
词法作用域
词法作用域,又叫静态作用域,变量被创建时就确定好了,而非执行阶段确定的。
var a = 2
function foo() {
console.log(a)
}
function bar() {
var a = 3
foo()
function log() {
console.log(a)
}
log() // 3
}
bar() // 2
foo() // 2
因为foo和bar处于相同的层级,按声明顺序判断
作用域链
当我们使用一个变量,会在当前作用域寻找该变量,如果找不到,就会到他的上层作用域寻找,以此类推,知道全局作用域。如果到全局作用域也没有找到就会报错 xxx is not defined
// 最外层作用域(全局作用域 window)
var a = '1'
function b() {
// 中间层作用域 (函数b的作用域)
var c = '2'
function d() {
// 最内层的作用域 (函数d的作用域)
var f = '3'
// 在函数d的作用域使用变量a, c
console.log(c) // 此层没有c - 去上一层找 - 找到了,输出
console.log(a) // 此层没有a - 去上一层找 - 没有 - 再去上一层找 - 找到了
}
d()
// 在函数b的作用域使用变量f
console.log(f) // 此层没有f - 去上一层找 - 没有,报错
}
b()
8. 深拷贝和浅拷贝
区别 浅拷贝——只复制指向某个对象的指针,新旧对象共享同一内存,不会改变原数据的基本数据,但可以改变子对象。
深拷贝——创造一个一模一样的对象,新旧对象不共享内存,修改也不会改变原对象。
实现方式
-
浅拷贝
-
Object.assign()
如果obj只有一层时,是深拷贝
- Array.prototype.concat()
- Array.prototype.slice()
-
-
深拷贝
- JSON.parse( JSON.stringify( ) )
- 递归克隆
- 函数库 lodash.cloneDeep( obj )
9. 原型和原型链
数组和对象是没有原型的,原型是函数特有的
原型链是数组、对象、函数共有的
原型: prototype
原型链: [[Prototype]] && __proto__
原型链继承
原型链的根部都是 Object -> null
当我们给一个函数创造实例时,新创建的变量指向的原型是实例的对象
let Person = function() {}
Person.prototype.name = 'kk'
Person.prototypr.fn = function() {
console.log(this.name)
}
ler p1 = new Person()
console.log(p1)
p1.fn() // p1自身没有fn函数,就会去原型链中去找
自身的原型怎么判断?
item.hasOwnProperty(age)
10. JS闭包
理解:函数内返回一个函数
优点
- 延长变量的生命周期
函数内部的变量会在函数运行结束后被垃圾回收机制回收掉,闭包的目的就是使函数内部的变量不被回收
- 创建私有环境
函数内的变量会存在函数作用域中,函数外部是无法使用的,这样就创建了一个私有环境,不会产生数据污染
- 沟通内外部方法的桥梁
缺点
- 会造成内存泄漏
因为使用闭包后,闭包内部的变量无法被回收,就会一直占用着内存
11. JS防抖和节流
防抖
当我们连续触发事件,一定时间内不触发则事件处理函数执行一次
节流
当我们连续触发事件,每一段时间执行一次事件处理函数
应用场景
防抖(debounce)
- Search搜索联想
- 触发resize事件
节流(throttle)
- 不断点击触发
- 监听滚动时间, 比如底部自动加载,上拉刷新
12. for in和for of的区别
for-in 是遍历索引 for-of 是遍历值
for-in
- for-in返回来的索引的类型是string
let arr = [1, 2, 3]
for (item in arr) {
console.log(typeof item) // string * 3
}
- for-in更适合遍历对象的属性,因为对象的属性是不可枚举的,无法使用for循环来遍历对象。
我们可以使用for-in和hasOwnProperty()搭配,判断某属性是不是该对象的实例属性
遍历对象的键还可以使用Object.keys(obj),生成一个对象全部属性的数组
for-of
- for-of适合遍历数组、字符串、map、set拥有迭代器对象的集合。
- for-of无法遍历对象Object,因为对象内没有迭代器iterator
let arr = [1,'2', function() {}, {}]
for (item of arr) {
console.log(typeof item) // number string function object
}
13. Map
Map是一种新的集合类型,和对象Object相似,也是键/值的存储机制
Map可以作为构造函数,用new关键字可以创建一个空映射
Map的键可以是任何类型
基本API
set()添加键/值对get()查找键的值has()判断键是否存在sizemap的大小delete()删除键/值对clear()清除map内全部的键/值对
let m = new Map()
m.set('a', 'b') // Map(1) { 'a' => 'b' }
m.get('a') // b
m.has('a') // true
console.log(m.size) // 1
m.delete('a') // Map(0) {}
m.clear() // Map(0) {}
14. Set
set在很多方面是加强的map,因为大多数API和行为是共有的
set存储的格式和数组相似,但是set存储的所有数据是不重复的
基本API
-
set()添加值 -
has()判断值是否存在 -
sizeset的大小 -
delete()删除值 -
clear()销毁集合实例的所有值