前端自己整理的学习面试笔记

简介

以下是本人一年多整理的前端学习笔记,现汇总分享给大家,很多问题都是面试必问的
更多学习资源,可以点击我获取更多

1 js数据类型

原始类型: null undefined number string boolean Symbol BigInt
引用类型: 对象

2 判断一个对象属性是否存在

本身属性判断: obj.hasOwnProperty(key)
包括了上级属性判断: key in obj
Reflect.get(obj, ‘key’) 没有返回undefined
Reflect.has(obj, ‘key’)

3 把 10000000 格式化成 10,000,000

// 1  把  10000000  格式化成  10,000,000
let str = '10000000'
str = str.replace(/(?=\B(\d{3})+$)/g, ',')
console.log(str)

4 平滑滚动

div{
    scroll-behavior: smooth
}

5 禁止函数new方式调用

function fn(){
    if (new.target){
        throw new Error("can't invoke with 'new'")
    }
    console.log('fn call')
}
new fn() // error

6 零宽字符以及应用场景

var account1 = '我\u200d是\u200d中\u200d国\u200d人',
    account2 = '我是中国人';
console.log(account1.length, account2.length)
// 打印 9  5
console.log(account1, account2)
// 打印 我‍是‍中‍国‍人 我是中国人

/u200d 是零宽度字符,不会具体显示出来,作用如下
1 起到水印,防止文章盗版,别人拷贝文字,也会把零宽字符也会一起盗版
2 实现隐藏信息加密传递和解密处理

7 js可迭代器理解

可迭代协议:就是任何一个对象,只要包含Symbol.iterator, 且返回一个迭代器,就表示可以迭代

{
    [Symbol.iterator]: function () {
        return '迭代器'
    }
}

比如如下数组,就是可迭代对象

var arr = [1,2,3]
undefined
var iter = arr[Symbol.iterator]()
undefined
iter.next()
{value: 1, done: false}
iter.next()
{value: 2, done: false}
iter.next()
{value: 3, done: false}
iter.next()
{value: undefined, done: true}

面试题: 比如实现如下
const [a, b] = {a: 1, b: 2}
运行上面代码会报出如下错误

caught TypeError: {(intermediate value)(intermediate value)} is not iterable
    at <anonymous>:1:16

原因是{a: 1, b: 2} 不是一个可迭代的对象,那么如何实现迭代呢,是要让对象实现Symbol.iterator就可以

Object.prototype[Symbol.iterator] = function(){
  return Object.values(this)[Symbol.iterator]()
}

8 null 和 undefined区别

null 表示是一个对象,但是此时没有对象就是null
undefined 表示是任何一个值,但是此时没有值就是undefined
以下这些都是undefined

  1. 变量被声明,但没有赋值
  2. 调用函数,参数没有提供
  3. 对象属性没有赋值
  4. 函数没有返回值
    另外解释
  • null 是一个表示"无"的对象(空对象指针),转为数值时为0;
  • undefined 是一个表示"无"的原始值,转为数值时为NaN。

9 标记模板字符串

const fontSize = 20
const color = '#00ff00'
const hi = style`
    font-size: ${fontSize}px,
    color: ${color}
``aaaaaa`
function style () {
    console.log(arguments)
    return style
}

style 是一个函数,会把模板值作为参数传给函数

10 promise终极面试

Promise.resolve().then(() => {
    console.log(0)
    return Promise.resolve(4)
}).then((res) => {
    console.log(res)
});

Promise.resolve()
    .then(() => {
        console.log(1)
    }).then(() => {
        console.log(2)
    }).then(() => {
        console.log(3)
    }).then(() => {
        console.log(5)
    }).then(() => {
        console.log(6)
    })

print 0 1 2 3 4 5 6

11 微软经典算法面试,9宫格输入法排列组合

function keyboardMap(digits) {
    var map = ['', '', 'abc', 'def', 'ghi', 'jkl',
    'mno', 'pqrs', 'tuv', 'wxyz'];
    var result = []
    for (var i = 0 ; i < digits.length; i++) {
        // result = result 组合map[digits[i]]
        result = _compose(result, map[digits[i]])
    }

    function _compose(arr1, arr2) {
        if (arr1.length === 0) return arr2
        if (arr2.length === 0) return arr1
        var r = []
        for (var i = 0 ; i < arr1.length; i++) {
            for (var j = 0 ; j < arr2.length; j++) {
                r.push(arr1[i] + arr2[j])
            }
        }
        return r
    }
    return result
}

console.log(keyboardMap('2345678'))

12 并发请求

/**
 * 并发请求
 * @param {*} urls   待请求的url数组
 * @param {*} maxNum 最大并发数
 * @returns 
 */
function concurRequest(urls, maxNum) {
    return new Promise((resolve) => {
        if (urls.length === 0){
            resolve([])
            return
        }
        const results = []
        let count = 0 // 当前请求完成数量
        let index = 0 // 下一个请求下标
        async function request() {
            if(index === urls.length) return
            const i = index
            const url = urls[index]
            index++
            console.log(url)
            try{
                const resp = await fetch(url)
                results[i] = resp
            }catch(err) {
                results[i] = err
            } finally{
                count++
                if (count === urls.length) {
                    console.log('over')
                    resolve(results)
                }
                request()
            }
            // console.log(results)
        }
        const times = Math.min(maxNum, urls.length)
        for (let i = 0 ; i < times; i++) {
            request()
        }
    })
}

const urls = []
for (let i = 1 ; i <= 10; i++) {
    urls.push('https://www.baidu.com/?a=' + i)
}
concurRequest(urls, 1)

13 如何将class转换为function

class Example{
    constructor(name){
        this.name = name
    }
    func(){
        console.log(this.name)
    }
}
// 开始转化为function
'use strict';
function Example(name) {
    // 只能用new的方式执行
    if (!(this instanceof Example)) {
        throw new TypeError('Class consturctor cannot be invoked without new');
    }
    this.name = name
}
// 设置func不可枚举
Object.defineProperty(Example.prototype, 'func', {
    value: function () {
        // func 不能通过new
        if (!(this instanceof Example)) {
            throw new TypeError(' new func is error');
        }
        console.log(this.name)
    },
    enumerable: false
})
Example.prototype.func = function (){
    console.log(this.name)
}

14 可以重试的请求方法

function  request(url, maxCount = 5) {
    return fetch(url).catch(err => 
        maxCount <= 0 ? Promise.reject(err) : 
        request(url, maxCount - 1))
}

request('https://www.baidu.com', 6)
.then((resp) => {
    console(resp)
}).catch((err) => {
    console.log(err)
})

15 let 和 var区别

1 污染全局
2 块级作用
3 重复生命
4 暂时性死区 TDZ

16keyof基础进阶

const cat = {
    name: 'jiang',
    age: 3
}

const user = {
    loginId: '123'
}

function <T extends object, K extends keyof T> getValue(obj: T, name: K): T[K] {
    return obj[name]
}

getValue(cat, 'name')
getValue(user, 'loginId')

17 大整数相加

function sum(a, b){
    let result = ''
    const len = Math.max(a.length, b.length)
    //a和b位数补齐
    a = a.padStart(len, '0')
    b = b.padStart(len, '0')
    let carry = 0 
    for (let i = len - 1; i >= 0; i--) {
        const n = +a[i] + +b[i] + carry
        carry = Math.floor(n / 10)
        result = (n % 10) + result
    }
    if (carry){
        result = '1' + result
    }
    return result
}

console.log(sum('1112222222222222222222222222222222222222222233333333333333333333333', '2'))

18 粘性定位

    .box{
        position: sticky;
        top: 0;
    }

19 文本溢出处理

1 单行文本溢出

    .txt{
        width: 200px;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }

2 多行文本溢出

    .txt{
        width: 200px;
        height: 150px;
        line-height: 30px;
        overflow: hidden;
        display: -webkit-box;
        -webkit-line-clamp: 5;
        -webkit-box-orient: vertical;
    }

20 获取鼠标位置的各种方式

1 e.x
鼠标到视口窗口左侧距离,忽略滚动条
2 e.clientX
同e.x
3 e.pageX
鼠标到页面左侧距离,包含滚动条的距离
4 e.screenX
鼠标到电脑整个屏幕左侧距离
5 e.movementX
鼠标到上一次位置的横向距离
6 e.offsetX
鼠标到目标元素(e.target)左侧距离

21 flip 动画思想

https://www.imgeek.net/article/825358760

22 让事件只触发一次

XXX.addEventListener('XXXX', () => {},
{
    once: true
})

23 模拟new操作

// 模仿new操作
function newFun(Fun, ...args) {
    // 1 创建一个空对象
    let newObj = {}
    // 2 把空对象和构造函数通过原型链进行链接
    newObj.__proto__ = Fun.prototype
    // 3 把构造函数的this绑定到新的对象上
    const result = Fun.apply(newObj, args)
    return result instanceof Object ? result : newObj
}

function Person (name) {
    this.name  = name
}

Person.prototype.say = function (){
    console.log(this.name + 'say')
}

var p1 = newFun(Person, 'jiang')
p1.say()

24 js关于this指向的问题

1.全局对象中的this指向指向的是window
2.全局作用域或者普通函数中的this指向全局window 3.this永远指向最后调用它的那个对象在不是箭头函数的情况下
4.new 关键词改变了this的指向
5.apply,call,bind可以改变this指向,不是箭头函数
6.箭头函数中的this它的指向在定义的时候就已经确定了箭头函数它没有this,看外层是否有函数,有就是外层函数的this,没有就是window
7.匿名函数中的this永远指向了window匿名函数的执行环境具有全局性,因此this指向window

25 js何如实现继承

1.原型链继承
缺点:无法调用父类构造函数
2.借用构造函数维承
缺点:无法电泳父类原型函数
3.组合式继承
缺点:会调用两次构造方法
4.ES6的class类继承

26 scripte标签里的async和defer有什么区别

当没有async和defer这两个属性的时候:
浏览器会立刻加载并执行指定的脚本
normal情况

parse dom -> fetch script -> exec -> parse dom

有async:
加载和渲染后面元素的过程将和script的加载和执行并行进行(异步)

parse dom -> parse dom -> exec -> parse dom  
          -> fetch script  

有defer:
加载和渲染后面元素的过程将和script的加载并行进行(异步),但是它的执行事件要等所有元素解析完成之后才会执行

parse dom -> 全部解析完 parse dom -> exec 
          -> fetch script  

扩展link 的preload 和 prefetch区别
preload 先加载,后面请求不会再加载,只要碰到link就是立即加载
prefetch 先获取,只是现在用不用,碰到link不会立即获取,会等到空闲时候才会获取

27 函数箭头特点

不能作为构造函数使用,不能new
箭头函数就没有原型
箭头函数没有arguments
箭头函数不能使用call, apply,bind去噶便this的执行
this指向外层第一个函数的this

28 js判断类型方式

// 1 typeof() 对于基本数据类型没问题,遇到引用数据类型无效
console.log(typeof(666)) // number
console.log(typeof([1,2,3]))// object
// 2 instanceof() 只能判断引用数据类,不能判断基本数据类型
console.log([] instanceof Array) // true
console.log('abc' instanceof String) // false
// 3 constructor 几乎可以判断基本数据类型和引用类型
// 但是如果改变的原型,就不能使用了
console.log(('abc').constructor === String) // true
// 4 Object.prototype.toString.call()
// 可以判断任何数据类型
var opt = Object.prototype.toString
console.log(opt.call(2)) //[object Number]
console.log(opt.call(true)) //[object Boolean]
console.log(opt.call('abc')) //[object String]
console.log(opt.call([])) // [object Array]

29 Proxy比defineProperty好在哪里

defineProperty实现, 无法监听新增的属性

const obj = {
    a: 1,
    b: 2,
    c: {
        a: 1,
        b: 2
    }
}
let v = obj.a
Object.defineProperty(obj, 'a', {
    get(){
        console.log('a', '读取')
        return v
    },
    set(val) {
        console.log('a', '赋值')
        v = val
    }
})

obj.a = 10
console.log(obj.a)
// 不生效 definePropert 无法深度遍历
obj.c.a = 20

defineProperty递归实现多层级监听

const obj = {
    a: 1,
    b: 2,
    c: {
        a: 1,
        b: 2
    }
}

 // 手写递归遍历,达到多层级监听的问题
 function _isObject(v) {
    return typeof v === 'object' && v != null
 }

 function observe(obj) {
    for (const k in obj) {
        let v = obj[k]
        if (_isObject(v)) {
            observe(v)
        }
        Object.defineProperty(obj, k, {
            get(){
                console.log(k, '读取')
                return v
            },
            set(val) {
                console.log(k, '赋值')
                v = val
            }
        })
    }
 }

 observe(obj)
 obj.a = '江'
 obj.c.a = '华'
 console.log(obj.c.a)

proxy简单实现

const proxy = new Proxy(obj, {
    get(target, k) {
        let v = target[k]
        console.log(k, '读取')
        return v
    },
    set(target, k , val) {
        if (target[k] !== val) {
            target[k] = val
            console.log(k, '更改')
        }
    }
})

proxy递过实现多层级监听

const obj = {
    a: 1,
    b: 2,
    c: {
        a: 1,
        b: 2
    }
}

function _isObject(v) {
    return typeof v === 'object' && v != null
 }

function observe(obj) {
    // proxy实现
    const proxy = new Proxy(obj, {
        get(target, k) {
            let v = target[k]
            if (_isObject(v)) {
                v = observe(v)
            }
            console.log(k, '读取')
            return v
        },
        set(target, k , val) {
            if (target[k] !== val) {
                target[k] = val
                console.log(k, '更改')
            }
        }
    })
    return proxy
}

const proxy = observe(obj)
proxy.a = 'aaa'
proxy.c.a = 'bbbbb'
proxy.cccc

console.log(proxy.c.a)

20 宽度适应内容

width: fit-content

21 对象数组去重

const arr = [
    {a: 1, b: 2},
    {b: 2, a: 1},
    {a: 1, b: 2, c: {a: 1, b: 2}},
    {b: 2, a: 1, c: {b: 2, a: 1}}
]
//错误做法
// const newArr = [...new Set(arr)]
// console.log(newArr)

const isObject = (val) => typeof val === 'object' && val != null
const newArr = [...arr]
for (let i = 0; i < newArr.length; i++) {
    for (let j = i + 1; j < newArr.length; j++) {
        // if (newArr[j] === newArr[i]) {
        //     newArr.splice(j, 1)
        //     j--
        // }
        if (equals(newArr[i],    newArr[j])) {
            newArr.splice(j, 1)
            j--
        }
    }
}

function equals(val1, val2) {
    if (isObject(val1) && isObject(val2)) {
        const keys1 = Object.keys(val1),
        keys2 = Object.keys(val2)
        if (keys1.length !== keys2.length) {
            return false
        }
        for (const k of keys1) {
            if (!keys2.includes(k)) {
                return false
            }
            if (!equals(val1[k], val2[k])) {
                return false
            }
        }
        return true
    } else {
        return val1 === val2    
    }
}

console.log(newArr)

22 文字颜色和背景混合

    .title{
        font-size: 3em;
        transition: 0.5s,
        mix-blend-mode: difference
    }

23 并发任务控制

function timeout(time) {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve();
        }, time)
    });
}

class SuperTask{
    constructor(paralleCount){
        // 并发数量
        this.paralleCount = paralleCount
        this.runningCount = 0 ; // 正在运行任务数
        this.tasks = []
    }

    add(task){
        return new Promise((resolve, reject) => {
            this.tasks.push({task, resolve, reject})
            this._run()
        })
    }

    _run(){
        while(this.runningCount < this.paralleCount && this.tasks.length){
            const {task, resolve, reject} = this.tasks.shift()
            this.runningCount++
            task().then(resolve, reject).finally(() => {
                this.runningCount--
                this._run()
            })
        }
    }
}
const superTask = new SuperTask(2);

function addTask(time, name){
    superTask.add(() => timeout(time))
    .then(() => {
        console.log(`任务${name}完成`)
    })
}
// 同一时段,最多只能执行两个
addTask(10000, 1)  // 10000 输入 1
addTask(5000, 2) // 5000 输入 1
addTask(3000, 3) // 8000 输入 1
addTask(4000, 4) // 12000 输入 1 
addTask(5000, 5) // 15000 输入 1

24 消除异步传染性

因为getUser是异步,导致以下全部函数都是异步

async function getUser(){
    return await fetch('').then((resp) => resp)
}

async function m1(){
    return await getUser()
}

async function m2(){
    return await m1()
}

async function m3(){
    return await m2()
}


async function main(){
    const user = await m3()
    console.log(user)
}

main()
 function getUser(){
    return fetch('https://www/baidu.com')
}
 function m1(){
    return getUser()
}

function m2(){
    return m1()
}

function m3(){
    return m2()
}


function main(){
    const user = m3()
    console.log(user)
}

function run(func){
    const cache = []
    let i = 0;
    const _originalFetch = window.fetch
    window.fetch = (...args) => {
        if(cache[i]){
            if (cache[i].status === 'fulfilled') {
                return cache[i].data
            } else if (cache[i].status === 'rejected') {
                throw cache[i].err
            }
        }
        const result = {
            status: 'pending',
            data: null,
            err: null
        }
        cache[i++] = result
        const prom = _originalFetch(...args).then(resp=>resp).then(
            resp=>{
                result.status = 'fulfilled'
                result.data = resp
            }, err=> {
                result.status = 'rejected'
                result.data = err
        })

        throw prom
        
    }

    try{
        func()
    }catch(err) {
        if (err instanceof Promise){
            const reRun = () => {
                i = 0
                func()
            }
            err.then(reRun, reRun)
        }
    }
}

run(main)

25 文字环绕设置

    img{
        width: 50%;
        height: 50%;
        border-radius: 50%;
        shape-outside: circle(50%)
    }

26 Promise like 判断

function isPromiseLike(value) {
    return (value !== null && (typeof value === 'object' || typeof value === 'function') && typeof value.then === 'function')
}

27 认识Symbol.toStringTag

function A(){}
const aa = new A()
Object.prototype.toString.call(aa)
'[object Object]'
A.prototype[Symbol.toStringTag] = 'A'
'A'
Object.prototype.toString.call(aa)
'[object A]'

38 具名导入和结构

// import导入只是标记一下变量,ESM符号绑定
import {n, increase} from './a'
// 结构是具体赋值
const {n, increase} = a

39 模拟一个微队列

function asyncRun(func){
    if (typeof Promise !== 'undefined') {
        Promise.resolve().then(func)
    } else if (typeof MutationObserver !== 'undefined') {
        const ob = new MutationObserver(func)
        const textNode = document.createTextNode('0')
        ob.observe(textNode, {
            characterData: true
        })
        textNode.data = '1'
    } else {
        setTimeout(func)
    }
}

40 js实现单例

方案一:缺点,原型链上追加属性无效

function singleton(className){
    let ins;
    return class {
        constructor(...args){
            if (!ins) {
                ins = new className(...args)
            }
            return ins
        }
    }
}


class Video {
    constructor(){
        console.log('video created')
        this.name = 'jiang'
    }

}

const SingleVideo = singleton(Video)

const video1 = new SingleVideo()
const video2 = new SingleVideo()
console.log(video1 === video2)
console.log(video1)

方案二:proxy代理方式,完美方案

function singleton(className){
    let ins;
    // 使用代理,并挟持构造器
    return new Proxy(className, {
        construct(target, args) {
            if (!ins) {
                ins = new target(...args)
            }
            return ins
        }
    })
}


class Video {
    constructor(){
        console.log('video created')
        this.name = 'jiang'
    }

}

const SingleVideo = singleton(Video)

const video1 = new SingleVideo()
const video2 = new SingleVideo()
console.log(video1 === video2)
console.log(video1)

41 冻结对象提升效率

有时候vue2在频繁给数组对象赋值,会很消耗性能,因为要执行Object.defineProterty
冻结对象

this.datas = Object.freeze(this.getDatas())

42 js函数重载

const searcher= {}

function addMethod(object, name, fn) {
    const old = object[name]
    object[name] = function (...args) {
        if (args.length === fn.length) {
            return fn.apply(this, args)
        } else {
            return old.apply(this, args)
        }
    }
}
addMethod(searcher, 'find', () => {
    console.log('查询所有用户')
})

addMethod(searcher, 'find', (name) => {
    console.log('按照用户名查询')
})

addMethod(searcher, 'find', (firstname, lastname) => {
    console.log('按照姓和名查询')
})

searcher.find()
searcher.find('jiang')
searcher.find('hua', 'jiang')

42 vue一次性渲染列表太大,出现白屏,依次延迟加载方案

import {ref} from 'vue'
export function useDefer(maxFrameCount = 1000) {
    const frameCount = ref(0)
    const refreshFrameCount = () => {
        requestAnimationFrame(() => {
            frameCount.value++;
            if (frameCount.value < maxFrameCount) {
                refreshFrameCount()
            }
        })
    }
    refreshFrameCount();
    return function (showInFrameCount) {
        return frameCount.value >= showInFrameCount
    }
}

使用

const defer = useDefer()

43 对象属性筛选

const pick = (obj, ...props) => {
    return Object.fromEntries(
        Object.entries(obj).filter(([k]) => props.includes(k))
    )
}
let obj = {
    name: 'jiang',
    age: 35
}
console.log(pick(obj, 'name'))
// { name: 'jiang' }

44 随机颜色

const randomColor = () => 
    '#' + 
    Math.floor(Math.random() * 0xffffff)
    .toString(16)
    .padEnd(6, '0')
console.log(randomColor())

45 随机字符串

const randomString = () => Math.random().toString(36).slice(2)
console.log(randomString())

46 从html获取纯文字

const removeTag = (fragment) => 
     new DOMParser().parseFromString(fragment, 'text/html').body.textContent | ''
console.log(removeTag('
你哈
'
))

47 什么数据响应

数据变化后,会自动重新运行依赖该数据的函数

48 let和var区别

  1. 是否污染全局
  2. 是否是块级作用域
  3. 是否能重复声明
  4. 是否有暂时性死区

48 无限递归是否栈溢出

function foo(){
    // setTimeout(foo, 0) // 不会栈溢出
    setTimeout(foo(), 0) // 会栈溢出
}
foo()

49 可以重试的请求方式

function request(url, maxCount = 5) {
    return fetch(url).catch(err => maxCount <= 0? Promise.reject(err) : request(url, maxCount--))
}
request('http://wwww', 5)

50 apply作用

修改this指向,等同call,但不一样的是call参数不是数组
函数.apply(参数1, …参数2)
等价于
参数1.函数(…参数2)

console.log.call.call.call.call.apply((a) => a, [1,2])
// 不输入任何值

51 js真正私有字段

class A{
    #name; // 定义私有字段
    constructor(){
        this.#name = 'jiang'
    }
    #method(){
        console.log('私有方式,外面不能访问')
        console.log(this.#name)
    }
}

const a = new A()
A.#name // 无法访问

52 Math.floor 和 parseInt区别

Math.floor 是向左取整
parseInt 是向靠近0的一侧取整

console.log(Math.floor(2.5)) // 2
console.log(parseInt(2.5))   // 2
console.log(Math.floor(-2.5))  // -3
console.log(parseInt(-2.5))   // -2

53 控制动画停止与运行

.container{
    animation: rotate 20s linear paused infinite;
}

.container:hover{
    animation-play-state: running;
}

54 磨砂玻璃特效

元素背后的div模糊

   .mark{
    backdrop-filter: blur(5px)
   }

55 元素缩放方式

  1. zoom
  2. scale
    span{
        font-size: 12px;
        transform: scale(0.5);
        display:inline-block;
        transform-origin: left center
    }

56 智能弹幕不遮挡人脸方案

    .danmu{
        -webkit-mask-image: url(./mark.svg);
        -webkit-mask-position: center;
        -webkit-mask-repeat: no-repeat;
    }

57 js滚动元素到可视区域

    elm.scrollIntoView({
        behavior: "smooth",
        block: "center"
    })

58 块级函数

var a;
console.log(b)
if (true){
    console.log(a)
    console.log(b)
    a = 5
    function a() {}
    function b() {}
    a = 0
    console.log(a)
}

console.log(a)
console.log(b)

// 函数不管在哪里声明,都会提升到顶层,
// 如果是判断里面,提升到顶部会赋值undefine
// 当代码hi行到判断里面,函数a和b会生成块级作用域,值是本身

59 transform

.item{
    width: 100px;
    height: 100px;
    transform: rotate(120deg) translate(100px, 100px)
}
transform 执行顺序是从右往左,先平移,在旋转,且旋转都是按照平移钱为中心旋转

60 保持宽高比

    .container{
        width: 90%;
        margin: 0 auto;
        aspect-ratio: 16/9.0
    }

61 元素的尺寸

参考:https://www.douyin.com/user/MS4wLjABAAAAi2oukRVcHpgD-HbVdzsxE7tYykr91YuIKukR_X_Yy08EFWRQhRrECDF6FvbvT8Xa?is_search=1&list_name=follow&modal_id=7124153340170112268&nt=0

  1. clientWidth clientHeight
    边框以内的尺寸,四舍五入的整数, 不包含滚动条
  2. offsetWidth offsetHeight
    布局尺寸,包含滚动条
  3. scrollWidth scrollHeight
    内容尺寸,包含边距和溢出部分,不需滚动且没有溢出等同于clientXXX
  4. getBoundingClientRect(),包含小数
    const rect = dom.getBoundingClientRect()
    如果盒子没有旋转变形等情况下
    rect.width 和 rect.height 等同于scrollXXXX
    如果盒子旋转或变形
    rect 是最小矩形去框住这个盒子

62 this指向问题

  1. 通过new调用,指向新对象
  2. 直接函数调用, 指向全局对象
  3. 对象调用 obj.func 指向obj
  4. call,apply,bind 指向第一个参数

63 经典面试题[‘1’, ‘2’, ‘3’].map(parseInt)

console.log(['1', '2', '3'].map(parseInt))
// 得到结果 [ 1, NaN, NaN ]
/**
 * [
 *  函数('1', 0),
 *  函数('2', 1),
 *  函数('3', 2)
 * ]
 */

64 设置阴影方式

  1. box-shadow
    根据外面盒子来做阴影
  2. filter: drop-shadow
    根据盒子像素点来做阴影,透明的地方不管

65 flex + margin 简化布局

    .parent{
        display: flex
    }
    .item{
        margin: auto; // 整体居中
        margin-left: auto; // 居右
        margin-right: auto; //  居左边
    }

66 数据分组

const people = [
    {name: 'jiang', age: 20},
    {name: 'mao', age: 22},
    {name: 'han', age: 30},
]

function groupBy(arr, generateKey){
    // 参数归一化
    if (typeof generateKey === 'string') {
        const propName = generateKey
        generateKey = (item) => item[propName]
    }
    const result = []
    for (const item of arr) {
        const key = generateKey(item)
        if (!result[key]) {
            result[key] = [item]
        } else {
            result[key].push(item)
        }
    }
    return result
}

console.log(groupBy(people, (item) => item.age))

console.log(groupBy(people, (item) => item.name))

console.log(groupBy(people, 'name'))

const arr = [1,2,3,4,5,6,7,8]
console.log(groupBy(arr, (item) => item % 2 === 0 ? '偶' : '奇'))

67 css 属性默认值设置

initial:主动将某一css属性设为默认值
unset:清除浏览器默认样式(全部清除all:unset)
revert:恢复浏览器默认样式 (全部恢复all:revert)

68 原型链prototype作用

概念:每个对象都有一个原型(prototype),并从愿原型上继承属性和方法,原型本身也是一个对象,它也有自己的原型,形成一个链式结构
对象寻找属性过程:
假设 p 是对象,p.name

  1. 先从p对象找有没有name属性
    如果没有
  2. p.proto(指向Parent.protorype)上有没有name属性
    如果没有
  3. Object.prototype上有没有name属性
    如果没有
  4. 返回null

69 块级格式化上下文

全称:Block Formatting Context
简称: BFC
概念: 它是一块独立的渲染区域, 它规定了在该区域钟,常规流块盒的布局

  • 常规流块盒在水平方向,必须撑满包含块
  • 常规流块盒在包含块的垂直方向一次摆放
  • 常规流盒若外边距无缝相邻,则进行外边距合并
  • 常规流块盒的自动高度和摆放位置,无视浮动元素
    BFC渲染区域: 这个区域是由某个HTML元素创建,以下元素会在其内部创建BFC区域:
  • 根元素,意味着html元素创建的BFC区域,覆盖网页所有的元素
  • 浮动和绝对定位元素
  • overflow不等于visable的块盒
1. float: left
2. position: absolute
3. overflow: hidden

BFC具体规则:

  • 创建BFC元素,它的自动高度需要计算浮动元素
  • 创建BFC元素,它的边框盒不会与浮动元素重叠
  • 创建BFC元素,不会和它的子元素进行外边距合并

70 高度塌陷,清除浮动办法

    .clearfix::after{
        content: '';
        display: block;
        clear: both
    }
    或则
    position: absolute
    或则
    float: left
    或则
    overflow: auto , scroll, hidden
    或则
    display: flow-root

71 vue3效率提升主要表现在哪些方面

参考https://www.douyin.com/user/MS4wLjABAAAAeIIkCgELXG6XdUxuE9nQ6W4AfS-aoPFbtmnBL8ytcYtBSyurgePBYZXJpB0LJBCT?modal_id=7214297604476112188

  • 静态元素或则静态属性会被提升
  • 预字符串化
  • 缓存事件处理函数
  • Block Tree
  • PatchFlag

72 随机数

const  randomNum = (min, max) => Math.random()*(max - min) + min 

73 事件循环

  • 主线程
    主线程是执行代码的地方,遇到函数,会把该函数放入执行栈

  • 执行栈
    执行结构,有函数就会从栈取出,直接执行

  • 任务队列
    在执行栈中,遇到比如setTimeout,会放入任务队列,等到计时结束,会任务队列放入执行栈判断是否要执行
    任务分为宏任务和微任务,优先检查微任务是否有执行,如果没有,在检查宏任务是否有执行
    微任务是在当前事件循环的尾部去执行;宏任务是在下一次事件循环的开始去执行

  • 宏任务
    有明确的异步任务需要执行和回调;需要其他异步线程支持。
    setTimeout
    setInterval
    setImmediate

  • 微任务
    没有明确的异步任务需要执行,只有回调;不需要其他异步线程支持。
    promise.then promise.catch
    new MutaionObserver()
    promise.nextTick()

    74 浏览器缓存策略

    • 强缓存,本地缓存
      不发起请求,直接从缓存里面内容,浏览器会把js,css,image存入内存,下次直接从内存取
    • 协商缓存,弱缓存
      需要向后台发请求,通过判断来决定是否协商缓存如果内容没有变化,返回304,历览器就用缓存里面的内同
    • 触发条件
      强缓存:
      http1.0: 时间戳响应标头
      http1.1: Cache-control 响应标头
      弱缓存:
      http1.0: 请求头:if-modified-since 响应头: last-modified
      http1.1:请求头:if-none-match 响应头: Etag

75 为什么需要虚拟dom

  • 框架设置
  • 跨平台

76 ES6 结构基本使用

// 对象结构
const user = {
    name: 'jiang',
    sex: '男'
}
const {name = '默认值', sex: gender = '男'} = user
console.log(name, gender)

// obj存放了不包含name的剩下字段
const {name: name1, ...obj} = user

// 数组结构
const numbers = ['0', '1', '2']
const [a, , b] = numbers
const {0: a1, 2: b2} = numbers
const[a3, b3, ...num] = numbers
console.log(a, b)

//参数结构
function ajax({method = 'get', url = '/'} = {})
ajax({
    method: 'aaa',
    url:'http'
})

77 vue3 自定义指令

自定义指令

const map = new WeakMap()
const ob = new ResizeObserver((entries) => {
    for (const entry of entries) {
        const handler = map.get(entry.target)
        if (handler) {
            const box = entry.borderBoxSize[0]
            handler({
                width: box.inlineSize,
                height: box.blockSize
            })
        }
    }
})

export default {
    mounted(el: HTMLElement, binding: any) {
        ob.observe(el)
        map.set(el, binding.value)
    },
    unmounted(el: HTMLElement) {
        ob.unobserve(el)
    },
}

注册指令main.js

import sizeDirect from './directive/sizeDirect'
...
app.directive('size-ob', sizeDirect)

使用

<div class="desktop-main" v-size-ob="handlerSize"></div>
...
const handlerSize = ((size: any) =>{
    console.log('handlerSize', size.width, size.height)
})

78 实现memoize缓存函数

function memoize(func, resolver) {
    const memoized = function (...args) {
        const key = resolver ? resolver.apply(this, args) : args[0];
        if (memoized.cache.has(key)) {
            return memoized.cache.get(key)
        }
        const result = func.apply(this, args)
        memoized.cache.set(key, result)
        return result;
    }
    memoized.cache = new WeakMap()
    return memoized
}

var object = {a: 1, b: 2}

var values = memoize((obj) => Object.values(obj))
console.log(values(object))

79 模拟实现lodash的get函数

function get(object, path, defaultValue) {
    let obj = object
    if (typeof path === 'string') {
        const reg = /[^\[\].]+/g
        path = path.match(reg)
    }
    for (const key of path) {
        if (!obj) {
            return defaultValue
        }
        obj = obj[key]
    }
    return obj === undefined ? defaultValue : obj
}

const object = {a: [{b: {c: 1}}]}
console.log(get(object, ['a', '0', 'b'], null))
console.log(get(object, ('a[0].b.c'), null))

80 给fetch添加超时功能

function createFetchWithTimeout(timeout = 1000) {
    return function (url, options) {
        return new Promise((resolve, reject) => {
            const signalController = new AbortController();
            fetch(url, {
                ...options,
                signal: signalController.signal
            }).then(resolve, reject);
            setTimeout(() => {
                reject(new Error('fetch timeout'))
                // 取消请求
                signalController.abort()
            }, timeout)
        })
    }
}

const request = createFetchWithTimeout(3000)
request("http:****")

81. 主流浏览器有哪些

  • Navigator(Gecko)
  • Opera(Preston/Blink)
  • IE(Trident) / Edge(Chromium)
  • Firfox(Gecko)
  • Safari(Webkit)
  • Chrome(Webkit, chromium, Blink)

82. 浏览器有哪些进程和线程

  1. 进程
    1. 浏览器主进程(只有一个)
    2. GPU进程(3D渲染)
    3. 第三方插件进程
    4. 浏览器渲染进程(内核)
  2. 线程
    1. GUI渲染线程(html + css)
    2. js解析引擎线程
    3. 事件触发线程(事件队列)
    4. 定时器触发线程(setTimeout)
    5. 异步网络请求线程(Ajax)

83. canvas转成file

canvas.toBlob((blob) => {
    const file = new File([blob], 'avatar.jpg', {
        type: 'image/jpeg'
    })
}, 'image/jpeg')

84. dataURL转blob

dataURLToBlob: function (dataurl) {
    let arr = dataurl.split(',')
    let mime = arr[0].match(/:(.*?);/)[1]
    let bstr = atob(arr[1])
    let n = bstr.length
    let u8arr = new Uint8Array(n)
    while (n--) {
    u8arr[n] = bstr.charCodeAt(n)
    }
    return new Blob([u8arr], { type: mime })
}

85. 盒子水平居中方式

方式1:

  .parent{
            position: relative;
            width: 800px;
            height: 800px;
            background: red;    
        }

        .children{
            width: 100px;
            height: 100px;
            background: blue;
            position: absolute;
            left: 50%;
            top: 50%;
            transform: translate(-50%, -50%);
        }

方式2:

.parent{
            position: relative;
            width: 800px;
            height: 800px;
            background: red;    
        }

        .children{
            width: 100px;
            height: 100px;
            background: blue;
            position: absolute;
            left: 0px;
            right: 0px;
            top: 0px;
            bottom: 0px;
            margin: auto;
        }

方式3:flex方式

方式4:
文本居中: line-height : height
图片居中 vertical-align: middle
flex定位: display: flex; margin: auto

86. 隐藏元素方式

1 visibility: hiddn, 占用空间
2 opacity: 0 不会改变布局,也会触发事件
3 display: none 不占用空间, 改变布局
4 transform: scale(0) 缩放无限小,元素所在的位置保留

87. Symbol

作用: 保证每个属性都是独一无二的,防止属性冲突
参考: ![https://blog.csdn.net/wsz123456wsz/article/details/127598604]

88. js 安全性

  1. XSS 跨站脚本攻击
    攻击者通过注入恶意代码来利用网络漏洞,从而在受害者浏览器与逆行代码,分为三种,存储型,反射型,DOM型
    1. 存储型XSS:攻击者向目标网站的数据库注入恶意脚本,当用户访问,这些脚本会被执行
      解决办法:过滤输入数据,并编码输出数据
    2. 反射型XSS:攻击者向目标网站发生恶意链接,当用户点击,脚本被执行
      解决办法:校验数据数据,编码输出数据
    3. DOM型XSS:攻击者将恶意脚本注入到网页中,用户交互时脚本被执行
      解决办法:使用安全的js库,避免使用eval函数
  2. CSRF 跨站请求伪造
    攻击者通过欺骗用户到目标网站上执行某些操作来发起伪造请求,比如一个攻击者可能会发送一个包含修改用户密码的请求,而这个请求看起来是来自用户自己的浏览器,因此网站可能会对请求进行处理并修改用户密码。由于这个请求来自攻击者而不是用户,因此这种攻击被称为跨站请求伪造。
    解决办法:
    1. 使用令牌,CSRF令牌是一种随机生成的值,用于验证用户的请求是否来自合法来源。服务器会将CSRF令牌包含在生成的表单中,然后在处理表单提交时验证该令牌。如果请求中没有正确的CSRF令牌,服务器将拒绝请求。
    2. 另一种防止CSRF攻击的方法是使用SameSite属性。SameSite属性是一种cookie属性,可以控制cookie是否可以被跨站点请求访问。当设置SameSite属性为“strict”时,浏览器将禁止跨站点请求访问该cookie,从而防止CSRF攻击。
  3. CORS 跨源资源共享
    跨域请求是指来自不同域的资源请求,例如从一个网站向另一个网站发出AJAX请求。由于浏览器的同源策略,一般情况下,跨域请求是不允许的。CORS是一种通过HTTP头来授权浏览器允许特定的跨域请求的机制。
    解决办法:配置CORS:为了配置CORS,服务器需要向响应添加一些特定的HTTP头。这些头告诉浏览器哪些跨域请求是允许的,哪些不允许。常见的CORS头包括Access-Control-Allow-Origin、Access-Control-Allow-Methods和Access-Control-Allow-Headers等。

89. js安全最佳实战

  1. 禁用不必要的js功能
  2. 使用https
  3. 使用密码哈希,密码不能明文存储
  4. 定期更新js库

90. vue 通讯方式

  1. props和$emit
  2. 父组件provide,子组件inject来注入变量
  3. $refs获取组件实例
  4. eventBus
  5. vuex状态管理

91. vue生命周期

  1. beforCreate 无法访问data,methods,computed
  2. created 可以访问无法访问data,methods,computed,不能访问dom
  3. beforeMounte render首次调用
  4. mounted 真实dom挂在完成
  5. beforeUpdate 数据修改,但是页面未修改
  6. updated 页面修改完成
  7. beforeDestory 可以做销毁前的一些工作
  8. destoryed

92. vue事件指令

  1. v-once - 定义它的元素或组件只渲染一次,包括元素或组件的所有节点,首次渲染后,不再随数据的变化重新渲染,将被视为静态内容。
  2. v-cloak - 这个指令保持在元素上直到关联实例结束编译 – 解决初始化慢到页面闪动的最佳实践。
  3. v-bind - 绑定属性,动态更新HTML元素上的属性。例如 v-bind:class。
  4. v-on - 用于监听DOM事件。例如 v-on:click v-on:keyup
  5. v-html - 赋值就是变量的innerHTML – 注意防止xss攻击
  6. v-text - 更新元素的textContent
  7. v-model - 1、在普通标签。变成value和input的语法糖,并且会处理拼音输入法的问题。2、再组件上。也是处理value和input语法糖。
  8. v-if / v-else / v-else-if。可以配合template使用;在render函数里面就是三元表达式。
  9. v-show - 使用指令来实现 – 最终会通过display来进行显示隐藏
  10. v-for - 循环指令编译出来的结果是 -L 代表渲染列表。优先级比v-if高最好不要一起使用,尽量使用计算属性去解决。注意增加唯一key值,不要使用index作为key。
  11. v-pre - 跳过这个元素以及子元素的编译过程,以此来加快整个项目的编译速度。

93. vue computed 和watch区别

  1. computed 有缓存值,可以设置setter 和 getter,一般用在模板渲染中
  2. watch 监听值变化,适合用户监听值变化然后去做一些复杂的业务逻辑

94. vue v-if 和v-for为什么不能同时使用

  1. 会先解析v-for,再解析v-if, 会带来性能消耗
  2. 可以使用template先判断if
<template v-if="isShow">
  <p v-for="item in items">
template>
  1. 可以使用计算属性, 过滤掉不需要显示的
computed: {
  items: function() {
   return this.list.filter(function (item) {
    return item.isShow
   })
  }
}

95. vue2 响应数据原理

思路: 数据劫持 + 观察者模式

  1. 数据劫持, 利用Object.defineProperty劫持对象属性的set和get,数据变化时候,触发消息给订阅者。
  2. vue 双向绑定整合了Observer,Complile和Watcher
    1. Observer 监听器,对数据对象遍历,包括子鼠星,利用defineProperty监听setter和getter,来监听数据变化,
    2. Compile 解析器 解析编译Vue模板数据, 渲染视图,同时将每个执行对应的绑定更新数据,监听数据变化,添加到监听数据订阅者,同步更新函数
    3. Watcher 订阅者, 订阅observer属性变化的消息,当发生变化,来通知complie来更新函数 来搭建Observer 和Compile通信桥廊
    4. Dep 订阅器,采用发布,订阅模式,用来手监听阅者watcher,对监听observice和watcher进行统一管理
      https://img-blog.csdnimg.cn/20190920152632212.png

96 vue 检测数组变化

vue将data中的数组进行了原型链重写,指向了自己的原型方法,如果数组包含了引用类型,会再次遍历依赖,实现了数组变化监听,有以下两种情况无法监听到变化

  1. 利用索引设置项 vm.items[index] = newValue
  2. 修改数组长度 vm.items.length = newLength
    以上解决办法
vm.$set(vm.items, indexOfItem, newValue)

97. vue 父子组件生命周期函数执行顺序

  1. 渲染过程
    父beforeCreate -> 父created -> 父beforeMount
    -> 子beforeCreate -> 子created ->子beforeMount ->子Mounted
    -> 父 mounted
  2. 更新过程
    父 beforeUpdate ->
    子 beforeUpdate -> 子 updated ->
    父 updated
  3. 销毁过程
    父 beforeDestroy ->
    子 beforeDestroy -> 子 destroyed ->
    父 destroyed
    总结:父组件先开始,子组件先结束

98. vue v-model双向绑定的原理

  1. model 更新视图,使用数据劫持+观察者模式 参考 95
  2. 视图更新model,v-model本质是value+input的语法糖,用户输入,监听input变化,从而更新value

相当于

如果在自定义组件中,会利用名为value的prop和input事件
父组件:


子组件:
{{value}}
props:{ value: String }, methods: { test1(){ this.$emit('input', '小红') }, },

99. vue3响应和vue2响应式区别

  1. vue2 使用object.defineProperty, vue3 使用proxy
  2. Object.defineProperty 无法检测数组下标变化,且智能代理对象的第一层属性,如果对象属性还是对象,需要递归遍历,proxy代理也是第一层,子属性如果是对象,则通过reactive继续做代理,实现深度代理
  3. Object.defineProperty无法监控新增加的属性,需要借助$set, proxy没问题
  4. proxy再ie上有兼容问题

100. vue2 和 vue3 diff算法分别说一下

diff 算法就是比较新旧两颗树,找出差异化,利用打补丁的方式进行局部渲染,触发时机是 _update(_rende())

  1. 同层比较,只比较统一层级,不会跨级
  2. tag不相同,直接删除重建,不在深度遍历
  3. tag和key相同,认为是相同节点,继续深度遍历

101. hash 和 history 模式实现原理

  1. hash 是带 # , 地址变化,不会重新请求,通过hasChange事件可以知道hash是否发生变化
  2. history实现,主要具有html5 发布的两个标准,pushState 和 replaceState,这两个api可以再改变url,但是不会重新发送请求,
  3. 区别
    1. hash兼容低版本,但是history不行
    2. hash有#, history没有
    3. 刷新页面,hash模式可以正常加载到hash对应页面,而history没有处理的话,会返回404,一般需要后端将所有页面都配置重定向路由

102. vue-router路由钩子函数是什么,执行顺序是什么

  1. 钩子函数总类有全局守卫,路由守卫,组件守卫
  2. 全局路由守卫
    1. beforeEach,全局前置守卫,路由跳转前触发,比如拦截登录验证
    2. beforeResolve,全局解析守卫,和beforeEach类似,路由跳转前触发,再beforeEach和组件内beforeRouteEnter后,afterEach前触发
    3. afterEach, 全局后置钩子,发生在beforeEach和beforeResolve 之后,没有next
  3. 路由守护 beforeEnter
    1. 再beforeEach后执行
const router = new VueRouter({
  routes: [
    {
      path: '/foo',
      component: Foo,
      beforeEnter: (to, from, next) => {
        // ...
      }
    }
  ]
  1. 组件守卫
    1. 为配置路由的组件添加生命周期函数

<template>
  ...
</template>
<script>
export default{
  data(){
    //...
  },
  beforeRouteEnter (to, from, next) {
    // 在渲染该组件的对应路由被 confirm 前调用
    // 不!能!获取组件实例 `this`,可以通过
    next(vm => {
        // 通过 `vm` 访问组件实例
    })
    // 因为当守卫执行前,组件实例还没被创建
  },
  beforeRouteUpdate (to, from, next) {
    // 在当前路由改变,但是该组件被复用时调用
    // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
    // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
    // 可以访问组件实例 `this`
  },
  beforeRouteLeave (to, from, next) {
    // 导航离开该组件的对应路由时调用
    // 可以访问组件实例 `this`
  }
}
</script>
  1. 触发顺序
    1 触发进入其它路由
    2 调用要离开路由的组件守卫beforeRouteLeave
    3 调用全局的前置守卫beforeEach
    4 在重用的组件里调用 beforeRouteUpdate
    5 在路由配置里调用 beforeEnter
    6 解析异步路由组件
    7 在将要进入的路由组件中调用beforeRouteEnter
    8 调用全局的解析守卫beforeResolve
    9 导航被确认
    10 调用全局的后置钩子afterEach。
    11 触发 DOM 更新mounted。
    12 执行beforeRouteEnter守卫中传给 next的回调函数

103. vue项目中你做了哪些优化

  1. 对象层级不要太深,否则会影响性能
  2. 不需要响应的数据不要放在data中,可以使用Object.freeze冻结
  3. v-if, v-show, computed,watch分场景使用
  4. 大数据表格做虚拟列表
  5. 防止内存泄漏,组件销毁,把全局变量和时间清理
  6. 图片懒加载
  7. 路由懒加载
  8. 异步路由
  9. 按需加载
  10. 防抖和节流应用
  11. 服务器端渲染或则预渲染

104. nextTick 原理

  1. 作用,vue更新dom不会立马更新,是异步的,nextTick回调实在下次dom更新循环结束后回调
  2. 原理,使用了微任务和宏任务,和执行环境有关
    1. Promise
    2. MutationObserver, h5新加额功能,
    3. 如果以前都不行,则采用setTimeout

105. Vue.set原理

了解 Vue 响应式原理的同学都知道在两种情况下修改 Vue 是不会触发视图更新的。
在实例创建之后添加新的属性到实例上(给响应式对象新增属性)
直接更改数组下标来修改数组的值。
Vue.set 或者说是 $set 原理如下
因为响应式数据 我们给对象和数组本身新增了 ob 属性,代表的是 Observer 实例。
当给对象新增不存在的属性,首先会把新的属性进行响应式跟踪 然后会触发对象 ob
的 dep 收集到的 watcher 去更新,当修改数组索引时我们调用数组本身的 splice 方法去
更新数组。

106. css盒子模型

  1. ie盒子模型
  2. w3c盒子模型
  3. 盒子模型有 内容content,填充padding, margin, border
  4. 区别: IE盒子模型把content算到border和padding里面去了

107. css 优先级

!import > 行内样式 > ID选择器 > 类选择器 > 标签选择器 > 通配符 > 继承 > 浏览器默认值

108. link 和 @import区别

  1. link是XHTML标签,除了加载CSS外,还可以定义RSS等,@imprt只加载css
  2. link和htm元素同时加载,@import需要等元素全部加载才会加载
  3. link无兼容性问题,@import在css2.1引入
  4. link支持js控制dom去改变元素,@import不支持

109. rem em vh px含义

  1. rem 相对于根元素文字大小相关
  2. em 相对于父元素大小
  3. vw vh 视口的宽高
  4. px 分辨率

110. 解决chrome 小于12px像素问题

  1. -webkit-text-size-adjust: none

110 new操作符做了什么

  1. 创建空对象,this指向该对象,同时继承了该函数原型
  2. 属性和方法加载到this引用中
  3. 新创建的对象由this所引用,并返回this

111. iframe 优缺点

  1. 优点:
    1. 解决加载缓存满的第三方内存,如广告等
    2. 安全的沙盒机制
    3. 并行加载脚本
  2. 缺点
    1. iframe会阻塞主页面的onload事件
    2. 内容为空,也需要加载时间
    3. 没有语意

112. href和src区别

  1. 请求资源类型不同
    1. href:指向网络资源,建立和当前元素或当前文档链接之间的联系
    2. src:会将资源下载到文档中,比如脚本,img图片
  2. 作用不同
    1. href:当前文档和引用资源建立关系
    2. src:替换当前内容
  3. 浏览器解析不同:
    1. href 不会阻塞浏览器的解析下载
    2. src会停止其他资源下载处理,将资源加载,编译,执行完

113. rgba 和 opacity透明效果有和不同

  1. rgba 设置后后代元素不会继承不透明属性
  2. opactiy 会继承父类的opacity属性

114 position的值,relative和absolute分别是相对谁进行定位的

  1. relative: 相对定位, 相对于自己本身在正常文档流中位置进行定位
  2. absolute:决定定位,相对于近一级定位不是static的父元素进行定位
  3. fixed: 绝对定位,相对于浏览器或则iframe进行定位
  4. static: 默认值,没有丁定位,在正常文档流中定位
  5. sticky:粘性定位,容器位置根据文档流计算得出

115 calc, support, media

  1. calc 函数,动态计算长度,支持 + - / 等
  2. support 主要检查浏览器支付支持css某个属性
  3. @media 媒体查询, 针对不同媒体类型定义不同样式

116 如何画三角形

.a {
    width: 0;
    height: 0;
    border-width: 100px;
    border-style: solid;
    border-color: transparent #0099CC transparent transparent;
    transform: rotate(90deg); /*顺时针旋转90°*/
}

117 css 兼容性问题如何解决

  1. 每个浏览器都有默认的margin和padding,解决方案: 全局 *{margin:0, padding: 0}
  2. chrome默认中文不小于12px,解决方案: 通过-webkit-text-size-adjust: none 解决

118 document.write 和innerHtml区别

  1. document.write 绘制整个界面
  2. innerHtml 绘制一部分

117 闭包

  1. 闭包三个特点
    1. 函数嵌套函数
    2. 函数内部可以引用外部的参数和变量
    3. 参数和变量不会被垃圾回收

118 垃圾回收机制

  1. 标记清除法: 进入环境,打上标记, 离开环境,清除标记
  2. 引用计数法:引用了一次+1,移出了引用-1

119 vuex

store状态存储响应

  1. State 基础数据,定义了状态的数据结构
  2. Getter 从基础数据派生的数据,允许store获取数据, mapGetter辅助函数将store的getter映射到局部计算属性
  3. Mutation 唯一的更改store的状态方法, 必须是同步
  4. Action 装饰器,包裹了mutations,可以异步,不能直接改变状态
  5. Module 模块化vuex,允许将多个store拆分成多个store,且保存在单一的状态树中

120 谈谈对 keep-alive了解

一般用作组件状态保留的,避免重新渲染

  1. 一般结合路由和动态组件一起使用,用于缓存组件
  2. 提供了include和exclude,支持字符串和正则表达式 exclude优先级高于include
  3. 两个钩子函数activated和deactviated,被激活和被移除触发

121 vue路由模式

  1. hash, 使用url hash来计算,支持所有浏览器,
  2. history 依赖html5 history api
  3. abstract 只有所有js环境,比如node.js

122 vue key的作用

key是对vue的vnode的唯一标记,通过key,diff操作会更准,更快,特别是在带有for循环的时候,需要设置key

#123 vue3 新的更改

  1. 监听机制, 解决了数组下表该变化和新增属性不能被监听到的问题
  2. 模板, 修改了作用域插槽,把插槽改成函数,自会影响子组件渲染
  3. 对象是组件声明

124 vue模板编译原理

  1. 模板字符串 转成 elementAST(解释器)
    切割vue,生成AST语法树,大量正则匹配
  2. AST进行静态节点标记,主要来做虚拟dom的渲染优化(dom更新,不需要diff静态节点)
  3. 使用elementAST生成render函数代码字符串
  4. 组件渲染调用render函数就可以

125 性能6大指标

  1. 加载优化
  2. 执行优化
  3. 渲染优化
  4. 样式优化
  5. 脚本优化
    6 V8 引擎优化

126 如何防止回流

  1. 回流产生
    1. 窗口调整大小
    2. 改变字体
    3. 增加样式或则删除样式
    4. 内容变化,input
    5. 操作dom
    6. offsetWidth 和offsetHeight
    7. 多层内联样式
  2. 如何避免
    1. 避免使用table布局
    2. dom 叶子节点更改class
    3. 避免多层内联样式,设置动画,最好脱离文档流
    4. 操作元素,可以先设置不可见, display: none, 操作完成,在显示出来
    5. 避免频繁操作dom

127 移动端优化

  1. 使用css3动画,开启硬件加速
  2. touch代替click
  3. 合理使用requestAnimationFRame,少用setTimeout
  4. 避免css3阴影渐变效果

127 Array.forEach 和 Array.map

  1. forEach 遍历每个元素但不返回新的数组
  2. map 遍历数组并返回新的数组

128 vue 导入图片方式

  1. css 静态引入
  2. image中的src
  3. import 语句
  4. URL 方式

129 浅拷贝 深拷贝

  1. 浅拷贝
let aar = [2,3,[4,6]]
let arr2 = [..arr]
arr[0] != arr2[0]
arr[2] == arr2[2]

let obj = (a: 1, b: {c: 1})
let obj1 = {...obj}
let obj2 = Object.assign(obj2, obj)
  1. 深拷贝
let arr = [2,3,[4,6]]
let arr2 = JSON.parse(JSON.stringify(arr))

function deepCopy(obj, cache = new WeakMap) {
    if (type obj !== 'object' || obj === null) {
        return obj 
    }

    if (cache.has(obj)){
        return cache.get(obj)
    }

    const clone = Array.isArray(obj) ? [] : {}
    cache.set(obj, clone)
    
    for (let key in obj) {
        if (Object.prototype.hasOwnProperty.call(obj, key)) {
            clone[key] = deepCopy(obj[key], clone)
        }
    }
    return clone
}

130 useVModel 改变props数据通用方法

// useVModel.js

import {computed} from 'vue'
const cacheMap = new WeakMap();
export function useVModel(props, propName, emit) {
    return computed({
        get() {
            if (cacheMap.has(props[propName])) {
                return cacheMap.get(props[propName])
            }
            const proxy = new Proxy(props[propName], {
                get(target, key) {
                    return Reflect.get(target, key)
                },
                set(target, key, value) {
                    emit('update:' + propName, {
                        ...target, [key]: value
                    })
                    return true
                }
            })
            cacheMap.set(props[propName], proxy)
            return proxy
        },
        set(val) {
            emit('update:' + propName, val)
        }
    })
}

// 使用
// index.vue
<template>
  <div class="">
    <child v-model="objRef"></child>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import Child from './Child.vue'
const objRef = ref({name: 'jiang'})
</script>

<style scoped>
</style>
// Child.vue
<template>
    <input v-model="modelValue.name">
  <div class="">{{ modelValue.name }}</div>
</template>

<script setup lang="ts">
import {useVModel} from './useVModel.js'

const props = defineProps({
    // modelValue 是默认名字, 使用v-mode="111" 传值
    modelValue: {
        type: Object,
        default: {}
    }
})
const emits = defineEmits(['update:modelValue'])
const nameProxy = useVModel(props, 'modelValue', emits)
</script>

<style scoped>
</style>

140 主题切换

html[data-theme='dark']{
    --text-color: #fff;
    --bg1: #102128;
}

:root {
    --text-color: '#333';
    --bg1: #fbd988;
}

html

切换主题

<html data-theme="dark">
    
html>

141 防止debug


setInterval(function() {
    debuggetCheck();
}, 1000)

var debuggetCheck = function () {
    function doCheck(a) {
        if (('' + a / a)['length'] !== 1 || a % 20 === 0){
            //动态生成匿名函数,函数体是 debugger, 动态生成的,类似eval
            (function(){}['constructor']('debugger')());
        } else {
            (function(){}['constructor']('debugger')());
        }
        doCheck(++a)
    }
    try{
        doCheck(0)
    }catch(err) {}
}

debuggetCheck();

131 ES6 Promise 和 Promise A+

  1. Promise A+ 是Promise的一个规范,包含
    1. promise状态(pending初始状态,fulfilled最终状态,rejected最终环境)
    2. then方法
    3. promise解析过程(resolvePromise)
  2. ES6的Promise是PromiseA+规范的实现,并增加了all和race等
  3. promise状态流转
    1. pending->resolve->fulfilled
    2. pending->reject->rejected

你可能感兴趣的:(IT资源,前端,学习,面试,vue)