面试题总结(3)—— JS

模块化

模块化将复杂的程序拆分为一个个独立的模块,有利于重用和维护
参考

闭包以及使用场景

闭包:可以访问并维护其他函数内部变量的函数

使用场景:回调传参,setTimeout传参,ES6模块(类似,不确定实现原理,无法肯定),结果缓存

类和继承

ES5:
属性定义:构造函数
方法定义:原型链
继承:寄生组合继承

function inherit(father, child) {
    
    
    Object.setPrototypeOf(child.prototype, father.prototype)
}

ES6:
class + extends

原型链终点

Function.__proto__ === Function.prototype
Object.prototype = {}

Eventloop

先取微任务队列,再取宏任务队列,每次操作都是这个步骤,至两个队列全部处理完成

注:process.nextTick > promise.then

new 操作符

创建空对象,设置对象的原型为构造函数的原型,执行构造函数,返回对象

this指向

  1. 正常调用默认指向全局
  2. 前缀调用指向紧跟的前缀对象
  3. call,apply,bind指向传参
  4. new 指向返回实例
  5. 箭头指向所在环境外层,且打破上述所有规则

节流和防抖

节流:规定间隔内只触发一次方法
防抖:连续触发只触发最后一次

垃圾回收

标记清除:可达性算法,第一次标记,第二次清除未标记的变量
引用计数:清除引用数为0的变量

扫描二维码关注公众号,回复: 12539890 查看本文章

Ajax防止浏览器缓存

Ajax.setRequestHeader("If-Modified-Since","0")
Ajax.setRequestHeader("Cache-Control","no-cache")
在URL后面加上一个数
"nowtime=" + new Date().getTime()
"fresh=" + Math.random()

事件流

事件流:
捕获阶段 => 目标阶段 => 冒泡阶段

addEventListener接收3个参数,要处理的事件名,回调函数,是否在捕获阶段处理事件

DOM 0级事件:onclick监听,无法定义多个监听,后者覆盖前者
DOM 2级事件:addEventListener监听,可以定义多个监听,同一事件下的同一函数只能被监听一次

先冒泡后捕获:通过分别监听捕获和冒泡事件,捕获时展缓执行,直到冒泡事件执行后再执行捕获事件

事件委托

在事件触发目标的父节点上监听事件,通过事件冒泡来触发事件处理程序,从而统一管理同类事件

数组去重

  • indexOf循环去重
  • Set()
  • Object属性

跨域

参考

箭头函数

  • 简化写法,绑定this
  • 没有自己的thisarguments,supernew.target
  • 不能作为构造函数,用new会报错
  • 没有prototype

webpack用来干什么的

webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个bundle

什么是按需加载

当用户触发了动作时才加载对应的功能。触发的动作,是要看具体的业务场景而言,包括但不限于以下几个情况:鼠标点击、输入文字、拉动滚动条,鼠标移动、窗口大小更改等。加载的文件,可以是JS、图片、CSS、HTML等。

说一下什么是virtual dom

用JavaScript 对象结构表示 DOM 树的结构;然后用这个树构建一个真正的 DOM 树,插到文档当中 当状态变更的时候,重新构造一棵新的对象树。然后用新的树和旧的树进行比较,记录两棵树差异 把所记录的差异应用到所构建的真正的DOM树上,视图就更新了。Virtual DOM 本质上就是在 JS 和 DOM 之间做了一个缓存

typeof,instanceof,isPrototypeOf 的区别

typeof :检查参数的类型,值为JS基本数据类型中的一个,nullobject
instanceof:检查对象与类的关系,检查右参数的原型是否处于左参数的原型链中
isPrototypeOf:检查对象与对象的关系,检查调用对象是否处于传参对象的原型链中

预加载和懒加载的区别

预加载:提前加载图片,用户查看时可以直接从缓存读取
懒加载:展缓加载图片,用户需要查看时再进行加载

两种行为相反,一个是优化用户体验,增加服务器压力。一个是优化页面性能,减轻服务器压力

mouseover和mouseenter的区别

mouseover:鼠标移入目标元素会触发,在子元素以及目标元素之间移入或移出都会再次触发
mouseenter:鼠标移入目标元素时触发,在子元素以及目标元素之间移入或移出不会再次触发

bind,apply,call的区别

都是用于修改函数内部this的指向
bind使用目标函数生成一个新函数
apply立即执行目标函数,传参方式为数组
call立即执行目标函数,传参方式为顺序传参

JS位置的区别

clientHeight:可视区域高度,不包含边框和滚动条
offsetHeight:可视区域高度,包含边框和滚动条
scrollHeight:所有区域高度,包含因滚动隐藏部分
scrollTop:滚动后被隐藏的高度
offsetTop:当前元素距offsetParent顶部内边距的距离,offsetParent为最近具有定位属性的元素,否则为body。当为body时,包含边框和外边距。

== 和 ===、以及Object.is的区别

== :类型转换后比较值
===: 比较类型、值,引用数据类型则比较地址,NAN不等于自身
Object.is:除了NAN等于自身,+0 !== -0以外,其他与===行为一致

定时器和requestAnimationFrame的区别

setTimeout:规定时间后触发回调,只触发一次
setInterval:规定时间后触发回调,触发多次
requestAnimationFrame:解决定时器触发动画时间不准确的问题,由浏览器内部根据显示器刷新频率自动调用回调并优化调用

由于setInterval自身的缺陷,使用setTimeout实现setInterval的功能可以保证两次调用间隔时间和每次回调不会被取消

实现深拷贝函数

function deepCopy(obj) {
    
    
    if (obj && typeof obj === 'object') {
    
    
        let res = obj instanceof Array ? [] : {
    
    }
        for (let item of Object.keys(obj)) res[item] = deepCopy(obj[item])
        return res
    }
    return obj
}

实现once函数

function once(fn, ...rest) {
    
    
    let lock = 0
    return function () {
    
    
        if (!lock++) return fn(...rest)
    }
}

实现属性监听

let obj = {
    
    
    _name: 66
}
Object.defineProperty(obj, 'name', {
    
    
    set(v) {
    
    
        this._name = v
    },
    get() {
    
    
        return this._name
    }
})
let obj = new Proxy({
    
    }, {
    
    
    set(target, p, value) {
    
    
        target[p] = value
    },
    get(target, p) {
    
    
        return target[p]
    }
})

实现私有变量

let obj = {
    
    
    getName: (function () {
    
    
        let name = 'Soraka'
        return function () {
    
    
            return name
        }
    })()
}

实现bind函数

Function.prototype.Bind = function (target) {
    
    
    let that = this
    return function (...rest) {
    
    
        that.apply(target, rest)
    }
}

实现全排列

function permutate(str) {
    
    
    if (str.length === 1) return [str]
    let res = []
    for (let i = 0; i < str.length; i++) {
    
    
        let list = permutate(str.substring(0, i) + str.substring(i + 1))
        list.forEach(val => res.push(str[i] + val))
    }
    return res
}

猜你喜欢

转载自blog.csdn.net/weixin_44844528/article/details/105824236