前端真题【我是来告诉你答案是什么】

「这是我参与11月更文挑战的第15天,活动详情查看:2021最后一次更文挑战

本文内容

  • 搜集网上的高频JS 初级面试题
  • 验证和复习之前学过的知识
  • 补充其他技能,如正则表达式、数组API

阅读前的提示

  • 题目没有按照知识点或者难度排序,混排
  • 只筛选了初级面试题,即本课程知识体系之内的
  • 如您遇到了其他未讲到的面试题,欢迎提供

1. 何为变量提升

1.1 var 和 let const 的区别

  • var 是 ES5语法,let const 是ES6 语法,var 有变量提升
  • var 和 let 是变量,可修改,const 是常量不可修改
  • let const 有块级作用域,var 没有
// 变量提升 ES5
console.log(a) // undefined
var a = 200
复制代码
var a
console.log(a) // undefined
a = 200
复制代码
// 块级作用域
for (let i = 0; i < 10; i++) {
    let j = i + 1
}
console.log(j)

复制代码

1.2 typeof能判断哪些类型

  1. 值类型
  2. 引用类型
  3. function(不作为引用类型的数据来使用,作为工具和方法来使用)

1.3 列举强制类型转换和隐式类型转换

  • 强制: parseInt parseFloat toString 等
  • 隐士: if、逻辑运算、==、+拼接字符串

2. 题目2

2.1 手写深度比较、模拟ladash.isEqual

image.png

// 判断是否是对象或数组
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 的 val —— 递归!!!
        const res = isEqual(obj1[key], obj2[key])
        if (!res) {
            return false
        }
    }
    // 3. 全相等
    return true
}

// 测试
const obj1 = {
    a: 100,
    b: {
        x: 100,
        y: 200
    }
}
const obj2 = {
    a: 100,
    b: {
        x: 100,
        y: 200
    }
}
// console.log( obj1 === obj2 )
console.log( isEqual(obj1, obj2) )

const arr1 = [1, 2, 3]
const arr2 = [1, 2, 3, 4]

复制代码

2.2 split() 和 join() 的区别

image.png

2.3 数组的 pop push unshift shift 分别做什么

  • 功能是什么
  • 返回是什么
  • 是否会对原数组造成影响
// const arr = [10, 20, 30, 40]

// // pop
// const popRes = arr.pop()
// console.log(popRes, arr)

// // shift
// const shiftRes = arr.shift()
// console.log(shiftRes, arr)

// // push
// const pushRes = arr.push(50) // 返回 length
// console.log(pushRes, arr)

// // unshift
// const unshiftRes = arr.unshift(5) // 返回 length
// console.log(unshiftRes, arr)

复制代码

纯函数:

  1. 不改变源数组(没有副作用);
  2. 返回一个数组

concat、map、filter、slice

// const arr = [10, 20, 30, 40]

// // concat
// const arr1 = arr.concat([50, 60, 70])
// // map
// const arr2 = arr.map(num => num * 10)
// // filter
// const arr3 = arr.filter(num => num > 25)
// // slice
// const arr4 = arr.slice()
复制代码

非纯函数

  1. push pop shift unshift
  2. forEach
  3. some every
  4. reduce

// const arr = [10, 20, 30, 40, 50]

// // slice 纯函数 (含头不含尾)
// const arr1 = arr.slice() // 类似拷贝元数组
// const arr2 = arr.slice(1, 4)
// const arr3 = arr.slice(2)
// const arr4 = arr.slice(-3) // [30, 40, 50]

// // splice 非纯函数
// const spliceRes = arr.splice(1, 2, 'a', 'b', 'c')
// // const spliceRes1 = arr.splice(1, 2)
// // const spliceRes2 = arr.splice(1, 0, 'a', 'b', 'c')
// console.log(spliceRes, arr)

复制代码

3. 题目3

3.1 数组slice 和 splice 的区别

  • 功能区别 (slice - 切片, splice - 剪接)
  • 参数和返回值
  • 是否是纯函数?
// const arr = [10, 20, 30, 40, 50]

// // slice 纯函数 (含头不含尾)
// const arr1 = arr.slice() // 类似拷贝元数组
// const arr2 = arr.slice(1, 4)
// const arr3 = arr.slice(2)
// const arr4 = arr.slice(-3) // [30, 40, 50]
复制代码
// // splice 非纯函数
// const spliceRes = arr.splice(1, 2, 'a', 'b', 'c')
// // const spliceRes1 = arr.splice(1, 2)
// // const spliceRes2 = arr.splice(1, 0, 'a', 'b', 'c')
// console.log(spliceRes, arr)
复制代码

image.png

3.2 [10, 20, 30].map(parseInt)返回的结果是什么【网红题】

const res = [10, 20, 30].map(parseInt)
console.log(res)

// 拆解
[10, 20, 30].map((num, index) => {
    return parseInt(num, index)
})
复制代码

image.png

3.3 ajax 请求get 和 post 的区别

  • get用于查询操作
  • post用于提交操作
  • get参数拼接在URL中
  • post参数放在请求体中
  • 安全性: post 易于预防CSRF

post 的参数也会比 get 长一些 get 请求参数过长 接口会返回413 状态码

4. 题目4:再学闭包

4.1 函数call 和 apply 的区别

image.png

4.2 事件代理(委托)是什么?

image.png

4.3 闭包是什么,有什么特性?有什么负面影响?

  • 回顾作用域和自由变量
  • 回顾闭包的应用场景:作为参数被传入,作为返回值被返回
  • 回顾:自由变量的查找,要在函数定义的地方(而非执行的地方)

4.3.1 闭包的影响

变量会变成常驻内存,得不到释放。闭包不要乱用

4.3.2 自由变量示例 —— 内存会被释放

// 自由变量示例 —— 内存会被释放
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()
复制代码

4.3.3 闭包 函数作为返回值 —— 内存不会被释放

//闭包 函数作为返回值 —— 内存不会被释放
function create() {
    let a = 100
    return function () {
        console.log(a)
    }
}

let fn = create()
let a = 200

fn() // 100
复制代码
function print(fn) {
    let a = 200
    fn()
}

let a = 100
function fn() {
    console.log(a)
}
print(fn) // 100
复制代码

5. 题目5:回顾 DOM 操作和优化

5.1 如何阻止事件冒泡的默认行为

  • 阻止事件冒泡:event.stopPropagation
  • 阻止默认行为:event.preventDefault

5.2 查找、添加、删除、移动DOM 节点的方法

查找元素、修改样式、修改属性

// const div1 = document.getElementById('div1')
// console.log('div1', div1)

// const divList = document.getElementsByTagName('div') // 集合
// console.log('divList.length', divList.length)
// console.log('divList[1]', divList[1])

// const containerList = document.getElementsByClassName('container') // 集合
// console.log('containerList.length', containerList.length)
// console.log('containerList[1]', containerList[1])

// const pList = document.querySelectorAll('p')
// console.log('pList', pList)

// const pList = document.querySelectorAll('p')
// const p1 = pList[0]

// // property 形式
// p1.style.width = '100px'
// console.log( p1.style.width )
// p1.className = 'red'
// console.log( p1.className )
// console.log(p1.nodeName)
// console.log(p1.nodeType) // 1

// // attribute
// p1.setAttribute('data-name', 'imooc')
// console.log( p1.getAttribute('data-name') )
// p1.setAttribute('style', 'font-size: 50px;')
// console.log( p1.getAttribute('style') )

复制代码

新建节点、插入节点、移动节点、获取父元素、获取子元素列表

const div1 = document.getElementById('div1')
const div2 = document.getElementById('div2')

// 新建节点
const newP = document.createElement('p')
newP.innerHTML = 'this is newP'
// 插入节点
div1.appendChild(newP)

// 移动节点
const p1 = document.getElementById('p1')
div2.appendChild(p1)

// 获取父元素
console.log( p1.parentNode )

// 获取子元素列表
const div1ChildNodes = div1.childNodes
console.log( div1.childNodes )
const div1ChildNodesP = Array.prototype.slice.call(div1.childNodes).filter(child => {
    if (child.nodeType === 1) {
        return true
    }
    return false
})
console.log('div1ChildNodesP', div1ChildNodesP)

div1.removeChild( div1ChildNodesP[0] )

复制代码

5.3 如何减少DOM 操作

  • 缓存DOM 查询结果
  • 多次DOM操作,合并到一次插入
  • ...

image.png

更加详细内容--->传送门:

6. 题目6

6.1 解释 jsonp 的原理,为何它不是真正的 ajax

6.1.1 浏览器的同源策略(服务端没有同源策略)和跨域

- 后端Nginx 配置称之为转发,没有同源策略
- 同源策略 是浏览器的安全措施
复制代码

6.1.2 哪些标签可以绕过跨域?

- `<img />` `<sctipt></sctipt>`
复制代码

6.1.3 jsonp展示

image.png

image.png

6.2 document load 和 ready 的区别

image.png

6.3 == 和 === 的不同

  • == 会尝试类型转换
  • === 严格相等

# JS基础-变量类型和计算【不会变量,别说你会JS】

7. 题目7

7.1 函数声明和函数表达式的区别

7.2 new Object() 和 Object.create()的区别

7.3 关于 this的场景

猜你喜欢

转载自juejin.im/post/7035803948204163079