1. var和let、const的区别
- var是ES5语法,let、const是ES6语法;var有变量提升
- var和let是变量,可修改;const是常量,不可修改
- let、const有块级作用域,var没有
2. typeof返回哪些类型?
undefind、string、number、boolean、symbol、object、function
⚠️typeof null === ‘object’
3. 列举强制类型转换和隐式类型转换
- 强制:parseInt、parseFloat、toString等
- 隐式:if、逻辑运算、 ==、 +拼接字符串
[]+[] // ""
[]+{
} // "[object Object]"
{
}+[] // 0
{
}+{
} // "[object Object][object Object]"
true+true // 2
1+{
a:1} // "1[object Object]"
4. 手写深度比较,模拟lodash isEqual
<script>
function isObject(obj){
return typeof obj === 'object' && obj != null
}
function isEqual(obj1, obj2){
if(!isObject(obj1) && !isObject(obj2)){
// 值类型(注意:参与equal的一般不会是函数)
return obj1 === obj2
}
if(obj1 === obj2){
return true
}
// 两个都是对象或数组,并且不相等
// 1. 先取出obj1和obj2的keys,比较个数
const obj1Keys = Object.keys(obj1)
const obj2Keys = Object.keys(obj2)
if(obj1Keys.length !== obj2Keys.length){
return false
}
// 2. 以obj1为基准,与obj2依次递归比较
for(let key in obj1){
//比较当前key的value -- 递归
const res = isEqual(obj1[key], obj2[key])
if(!res){
return false
}
}
// 3. 全相等
return true
}
const obj1 = {
a: 200,
b: {
x: 100,
y: 200
},
c: 300
}
const obj2 = {
a: 100,
b: {
x: 100,
y: 200
},
c: 300
}
console.log(isEqual(obj1, obj2))
</script>
5. split()和join()的区别
- split():以某个字符来拆分字符串为数组
- join():以某种字符将数组拼接成字符串
6. 数组的pop、push、unshift、shift分别是什么?
(功能是什么,返回值是什么,是否会对原数组造成影响)
- pop:删除数组尾部第一个元素,并返回这个元素。
- push:在数组的尾部加入一个元素,并返回修改后数组的长度。
- unshift:在数组的头部加入一个元素,并返回修改后数组的长度。
- shift:删除数组头部的第一个元素,并返回这个元素。
7. 数组的API,有哪些是纯函数?
纯函数:
- 不改变原数组(没有副作用)
- 返回一个数组
纯函数:concat, map, filter, slice
非纯函数:pop, push, unshift, shift, forEach, some, every, reduce
8. 数组slice和splice的区别
功能区别(slice - 切片, splice - 剪接),参数和返回值,是否纯函数
const arr = [10, 20, 30, 40, 50]
// slice()纯函数
const arr1 = arr.slice() // slice()不传参相当于把原来数组深拷贝一份
const arr2 = arr.slice(1, 4) // 20,30,40
const arr3 = arr.slice(2) // 30,40,50
const arr4 = arr.slice(-2) // 40,50
// splice()非纯函数
const spliceRes = arr.splice(1, 2, 'a', 'b', 'c')
console.log(spliceRes) // 10,a,b,c,40,50
console.log(arr) // 20,30
9. [10,20,30].map(parseInt)返回结果是什么?
map的参数和返回值,parseInt参数和返回值
parseInt(string, radix)
string:必需。要被解析的字符串。
radix:可选。表示要解析的数字的基数。该值介于 2 ~ 36 之间。
如果省略该参数或其值为 0,则数字将以 10 为基础来解析。如果它以 “0x” 或 “0X” 开头,将以 16 为基数。
如果该参数小于 2 或者大于 36,则 parseInt() 将返回 NaN。
// 拆解
[10, 20, 30].map((num, index) => {
parseInt(num, index)
})
10. ajax请求get和post的区别
- get一般用于查询操作,post一般用于提交操作
- get参数拼接在url上,post放在请求体内(数据体积可更大)
- 安全性:post易于防止CSRF
11. 函数call和apply的区别
主要是参数上的不同,call后面的参数是一个一个零散传进去的,apply后面的参数是以一个数组或者类数组的方式传进去的。
fn.call(this, p1, p2, p3, p4)
fn,apply(this, aruguments)
12. 事件代理(委托)是什么?
- js中事件冒泡我们知道,子元素身上的事件会冒泡到父元素身上。
- 事件代理就是,本来加在子元素身上的事件,加在了其父级身上。
- 那就产生了问题:父级那么多子元素,怎么区分事件本应该是哪个子元素的?
- 答案是:event对象里记录的有“事件源”,它就是发生事件的子元素。
- 它存在兼容性问题,在老的IE下,事件源是 window.event.srcElement,其他浏览器是 event.target
- 用事件委托有什么好处呢?
- 第一个好处是效率高,比如,不用for循环为子元素添加事件了
- 第二个好处是,js新生成的子元素也不用新为其添加事件了,程序逻辑上比较方便
13. 闭包是什么?有什么特性?有什么负面影响?
作用域和自由变量
闭包应用场景:a. 函数作为参数被传入; b. 函数作为返回值被返回
自由变量的查找,要在函数定义的地方,而非执行的地方!
影响:
- 变量会常驻内存,得不到释放,闭包不要乱用。
// 自由变量示例 - 内存会被释放
let a = 0
function fn1(){
let a1 = 100
function fn2(){
let a2 = 200
function fn3(){
let a3 = 300
return a + a1 + a2 + a3
}
fn3()
}
fn2()
}
fn1()
// 闭包 - 函数作为返回值 - 内存不会被释放
function create(){
let a = 100
return function(){
console.log(a)
}
}
let fn = create()
let a = 200
fn() // 100
// 闭包 - 函数作为参数 - 内存不会被释放
function print(fn1){
let d = 200;
fn1();
}
let d = 100;
function fn1(){
console.log(d);
}
print(fn1);
14. 如何阻止事件冒泡和默认行为?
- event.stopPropagation
- event.preventDefault
15. 查找、添加、删除、移动DOM节点的方法?
16. 如何减少DOM操作?
同上。
17. 解释jsonp的原理,为何它不是真正的ajax?
- ajax是通过XMLHttpRequest()来实现的,jsonp是通过script标签来实现的。
- 浏览器的同源策略(服务端没有同源策略)和跨域
- 哪些html标签能绕过跨域?img标签,script标签
- jsonp原理
// 客户端
<script>
window.abc = funtion(data){
console.log(data)
}
</script>
<script src="http://localhost:8002/jsonp.js?username=xxx&callback=abc"></script>
// 服务器端返回jsonp.js
abc(
{
name: 'xxx'}
)
18. document load和ready的区别?
window.addEventListener('load', funtion(){
// 页面的全部资源加载完才会执行,包括图片、视频等
})
window.addEventListener('DOMContentLoaded', funtion(){
.
// jquery中的ready也是
// DOM渲染完即可执行,此时图片、视频还可能没有加载完
})
19. == 和 === 的区别
- == 会尝试类型转换
- === 严格相等
- 哪些场景采用 == ?
⚠️除了 == null之外,其他都一律用 === ,例如:
const obj = {
x: 100 }
if(obj.a == null){
}
// 相当于
if(obj.a === null || obj.a === undefined){
}
20. 函数声明和函数表达式的区别?
- 函数声明 function fn(){…}
- 函数表达式 const fn = function(){…}
- 函数声明会在代码执行前预加载,而函数表达式不会
21. new Object()和Object.create()的区别
- {}等同于new Object(),原型Object.prototype
- Object.create(null) 没有原型
- Object.create({…})可指定原型
const obj1 = {
a: 10,
b