面试梳理 2021-05-03

浏览器的缓存

  • 强缓存
    • exprices 绝对时间 格林尼治时间 时间点
    • cache-control 相对时间 优先级高于 exprices
  • 协商缓存
    • last-modified (文件最后修改的时间) if-modified-since (文件最后修改的时间) --- 304 状态码
    • Etag(哈希值) 和 if-none-match
面试梳理 2021-05-03_第1张图片
image

从浏览器地址输入到页面渲染

HTML -- ke.qq.com -- 缓存 -- HTTP -- TCP ------ Server
DNS -- IP地址
HTML -- DOM Tree -- Render Tree -- Paint -- 页面

[图片上传失败...(image-7851ac-1620039458971)]
[图片上传失败...(image-e11f5b-1620039458971)]

https和http的区别

  1. https协议需要到ca申请证书,一般免费证书较少,因而需要一定的费用
  2. http是超文本协议传输,信息是明文传输,https则是具有安全性的ssl加密传输协议
  3. http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443
  4. http的连接很简单,是无状态的;https协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全

vue

1.什么是vue生命周期?
答: Vue 实例从创建到销毁的过程,就是生命周期。从开始创建、初始化数据、编译模板、挂载Dom→渲染、更新→渲染、销毁等一系列过程,称之为 Vue 的生命周期。

2.vue生命周期的作用是什么?
答:它的生命周期中有多个事件钩子,让我们在控制整个Vue实例的过程时更容易形成好的逻辑。

3.vue生命周期总共有几个阶段?
答:它可以总共分为8个阶段:创建前/后, 载入前/后,更新前/后,销毁前/销毁后。

4.第一次页面加载会触发哪几个钩子?
答:会触发 下面这几个beforeCreate, created, beforeMount, mounted 。

5.DOM 渲染在 哪个周期中就已经完成?
答:DOM 渲染在 mounted 中就已经完成了。

  • router的区别
    • $route是“路由信息对象”,包括path,params, hash, query, fullPath, matched, name等信息参数,
    • $router是“路由实例”对象包括了路由的跳转方法,钩子函数等
  • vue.js的两个核心是什么 数据驱动,组件系统
  • vue常用的修饰符
    • .stop 该修饰符将阻止事件向上冒泡,同理于调用 event.stopPropagation() 方法
    • .prevent 该修饰符会阻止当前事件的默认行为。同理于调用 event.preventDefault() 方法
    • .self 该指令只当事件是从事件绑定的元素本身触发时才触发回调
  • vue中key值的作用
    • 当vue.js用v-for正在更新已渲染过的元素列表时,它默认用“就地复用”策略。如果数据项的顺序被改变,vue将不会移动DOM元素来匹配数据项的顺序,而是简单的复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。key的作用主要是为了高效的更新虚拟DOM
  • 什么是vue的计算属性
    • 在模版中放入太多的逻辑会让模版过重且难于维护,在需要对数据进行复杂处理,切可能多次使用的情况下,尽量采取计算属性的方式。好处
  1. 使得逻辑处理结构清晰
  2. 依赖于数据,数据更新,处理结果自动更新
  3. 计算属性内部this指向vm实例
  4. 在 template 调用时, 直接写计算属性名即可
  5. 常用的是 getter 方法,获取数据,也可以使用set方法改变数据
  6. 相较于methods,不管依赖的数据变不变,methods都会重新计算,但是依赖数据不变的时候 computed 从缓存中获取,不会重新计算
  • vue等单页面应用及其优缺点
    • 优点:Vue 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件,核心是一个响应的数据绑定系统。MVVM、数据驱动、组件化、轻量、简洁、高效、快速、模块友好。
    • 不支持低版本的浏览器,最低只支持到IE9;不利于SEO的优化(如果要支持SEO,建议通过服务端来进行渲染组件);第一次加载首页耗时相对长一些;不可以使用浏览器的导航按钮需要自行实现前进、后退。

vuex

[图片上传失败...(image-548611-1620039458971)]

state
Vuex 使用单一状态树,即每个应用将仅仅包含一个store 实例,但单一状态树和模块化并不冲突。存放的数据状态,不可以直接修改里面的数据。
mutations
mutations定义的方法动态修改Vuex 的 store 中的状态或数据。
getters
类似vue的计算属性,主要用来过滤一些数据。
action 
actions可以理解为通过将mutations里面处里数据的方法变成可异步的处理数据的方法,简单的说就是异步操作数据。view 层通过 store.dispath 来分发 action。

==闭包(对闭包的看法,为什么要用闭包)==

闭包是指有权访问另一个函数作用域中的变量的函数

  1. 匿名自执行函数
  2. 结果缓存
  3. 封装

优点
1.可以读取函数内部的变量
2.可以让这些局部变量保存在内存中,实现变量数据共享。
缺点
1.由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
2.闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。

两种策略:
1.标记清除; (最常用的垃圾回收方式。当变量进入环境时,将变量标记为"进入环境";当变量离开环境时,将其标记为"离开环境"。)

2.引用计数
引用计数是跟踪每个值被引用的次数;当有一个变量被引用时,则这个值的引用次数加1,当取消一个引用时,次数减1。当引用值变为0 时,将由垃圾收集器回收

引用计数方式有严重的问题,就是,当变量相互引用时,如:

var obj1 = {}
var obj2 = {}
obj1.a = obj2;
obj2.b = obj1;
对于上面的代码,存在相互引用,其引用计数永远为2,就会导致对象永远不会被回收。

obj = null;

css3 动画性能优化

实现丝般顺滑主要决定因素有二:

  • 时机(Frame Timing): RAF
window.requestAnimFrame = (function(){
 return  window.requestAnimationFrame   || 
   window.webkitRequestAnimationFrame || 
   window.mozRequestAnimationFrame    || 
   window.oRequestAnimationFrame      || 
   window.msRequestAnimationFrame     || 
   function( callback ){
        window.setTimeout(callback, 1000 / 60);
   };
})();

  • 成本(Frame Budget):
    • 避免layout: 先读后写
    • 尽量少paint: 注意样式的使用
    • 适当的硬件加速

js中查找字符串

  • charAt()
  • indexOf()

==箭头函数和普通函数的重要区别==

  • 没有自己的this、super、arguments 和 new.target, 它们是离该箭头函数最近的非箭头函数的绑定
  • 不能使用new 来调用
  • 没有原形对象
  • 内部的this无法改变
  • 行参名称不能重复

箭头函数和箭头函数的指向

  • 箭头函数的写法
    • 箭头函数只能用赋值式写法,不能用声明式写法
    • 如果参数只有一个,可以不加括号,如果没有参数或者参数多于一个就需要加括号
    • 如果函数体只有一句话,可以不加花括号
    • 如果函数体没有括号,可以不写return,箭头函数会帮你return
  • 理解常规函数中的this
    • 纯粹的函数调用
    • 对象中函数的调用
    • 构造函数中的this (每个构造函数在new之后都会返回一个对象,这个对象就是this,也就是context上下文。)
    • window.setTimeout()和window.setInterval()中函数的调用
  • 理解箭头函数中的this
    • 默认绑定外层this
    • 不能使用call方法修改里面的this
    • 多层对象嵌套里函数的this (多层对象嵌套里箭头函数里this是和最最外层保持一致的。)

Set—Map与数组和对象的比较

通过对比:
在这个数据开发中涉及数据结构,能使用Map不使用数组,尤其是复杂的数据结构;
如果对数据结构要求存储的唯一性,考虑使用Set,(优先使用Map,如果对数据要求比较高,保证每个数据的唯一性,用Set)放弃使用object;
--Map删除的成本最低;
--Set和Map的语义上最优

JavaScript专题之数组去重

  • 双层循环
  • indexOf
  • 排序后去重
  • es6
    https://juejin.im/post/5949d85f61ff4b006c0de98b#heading-8
// Set

function unique(array) {
    return [...new Set(array)];
}

// Map

function unique (arr) {
    const seen = new Map()
    return arr.filter((a) => !seen.has(a) && seen.set(a, 1))
}

事件循环进阶

Promise里有了一个一个新的概念:microtask

或者,进一步,JS中分为两种任务类型:macrotask和microtask,在ECMAScript中,microtask称为jobs,macrotask可称为task

  • macrotask(又称之为宏任务),可以理解是每次执行栈执行的代码就是一个宏任务(包括每次从事件队列中获取一个事件回调并放到执行栈中执行)
  • microtask(又称为微任务),可以理解是在当前 task 执行结束后立即执行的任务

分别很么样的场景会形成macrotask和microtask呢?

macrotask:主代码块,setTimeout,setInterval等(可以看到,事件队列中的每一个事件都是一个macrotask)
microtask:Promise,process.nextTick等

再根据线程来理解下:

macrotask中的事件都是放在一个事件队列中的,而这个队列由事件触发线程维护
microtask中的所有微任务都是添加到微任务队列(Job Queues)中,等待当前macrotask执行完毕后执行,而这个队列由JS引擎线程维护

盒子模型

什么是“盒子”
初学 CSS 的朋友,一开始学 CSS 基础知识的时候一定学过padding border和margin,即内边距、边框和外边距。它们三者就构成了一个“盒子”。就像我们收到的快递,本来买了一部小小的手机,收到的却是那么大一个盒子。因为手机白色的包装盒和手机机器之间有间隔层(内边距),手机白色盒子有厚度,虽然很薄(边框),盒子和快递箱子之间还有一层泡沫板(外边距)。这就是一个典型的盒子。

简单的说每个html标签都是一个方块,然后这个方块又包着几个小方块。分别是:margin、border、paddding、content。它们的关系是margin包着border包着padding包着content。就像盒子一层一层地包着一样。这就是我们所说的盒模型。

Vue 兄弟组件通讯

  1. 新建中央事件线
  2. $emit 发送数据
  3. $on 监听并接受数据

原生click时间绑定

element.addEventListener(event, function, useCapture)

event 指定事件名
function 指定要事件触发时执行的函数
useCapture 指定事件是否在捕获或冒泡阶段执行

事件委托就是利用冒泡的原理,把事件加到父元素或祖先元素上,触发执行效果。

  1. 提高JavaScript性能。事件委托可以显著的提高事件的处理速度,减少内存的占用
  2. 动态的添加DOM元素,不需要因为元素的改动而修改事件绑定。

canvas性能优化

  • 将渲染阶段的开销转嫁到计算阶段之上。
  • 使用多个分层的 Canvas 绘制复杂场景。
  • 不要频繁设置绘图上下文的 font 属性。
  • 不在动画中使用 putImageData 方法。
  • 通过计算和判断,避免无谓的绘制操作。
  • 将固定的内容预先绘制在离屏 Canvas 上以提高性能。
  • 使用 Worker 和拆分任务的方法避免复杂算法阻塞动画运行。

canvas 绘制一个三角形

/*
* 题目:
* 在画布上绘制一个三角形轮廓,三角形三个点分别是 (20, 50)、(150, 200)、(20, 200)
* 在画布上绘制一个三角形填充图形,三角形三个点分别是 (180, 140)、(230, 200)、 (180, 200)
*/

var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');

// 绘制三角形轮廓
context.beginPath();
context.moveTo(20, 50);
context.lineTo(150, 200);
context.lineTo(20, 200);
// 调用stroke()时不会自动闭合,所以需要调用 closePath() 函数
context.closePath(); 
context.stroke();// 绘制轮廓使用 stroke

// 绘制三角形填充图形
context.beginPath();
context.moveTo(180, 140);
context.lineTo(230, 200);
context.lineTo(180, 200);
// 当你调用fill()函数时,所有没有闭合的形状都会自动闭合,所以你不需要调用 closePath() 函数。
context.fill(); // 绘制填充区域使用 fill

vue 和 react 的比较

  1. 都支持组件化
  2. 都是数据驱动试图

性能优化

[图片上传失败...(image-31f2d1-1620039458971)]

flex 子元素属性

  • flex-grow 属性表示当父元素空间有剩余时,将剩余空间分配给各子元素的比例,默认为0,表示不分配;当为数值时,表示父元素剩余空间分配给各子元素的比例,不是扩张后子元素的尺寸比例 (是否扩张)
  • flex-shrink flex-shrink 属性与flex-grow属性的作用相反,表示当子元素宽度总和大于父元素宽度,且未换行显示时,各子元素压缩大小,默认未1,表示各子元素等比压缩;当数值不一时,表示各子元素因为压缩空间而减少的尺寸的比例,不是压缩后子元素尺寸的比例。
  • flex-basis 属性可以用来设置子元素的空间,默认值为auto,表示为原本大小。当父元素有剩余空间时,可通过此属性扩充子元素的空间;各子元素通过扩充之后的空间总和超过了父元素的空间大小时,按flex-basis值比例来设置子元素的大小,没有flex-basis属性时,默认flex-basis值为子元素原本大小,使子元素大小总和不超过父元素空间大小。

JavaScript设计模式之面向对象编程

//为类的原型对象属性赋值
Person.prototype.showInfo = function () {
    //展示信息
    console.log('My name is ' + this.name , ', I\'m ' + this.age + ' years old!');
}

//将对象赋值给类的原型对象
Person.prototype = {
    showInfo : function () {
        //展示信息
        console.log('My name is ' + this.name , ', I\'m ' + this.age + ' years old!');
    }
}

通过 this 添加的属性和方法是在当前对象添加的,而 javascript 语言的特点是基于prototype 的,是通过 原型prototype 指向其继承的属性和方法的;通过 prototype 继承的方法并不是对象自身的,使用的时候是通过 prototype 一级一级查找的,这样我们通过 this 定义的属性或者方法都是该对象自身拥有的,我们每次通过 new 运算符创建一个新对象时, this 指向的属性和方法也会得到相应的创建,但是通过 prototype 继承的属性和方法是每个对象通过 prototype 访问得到,每次创建新对象时这些属性和方法是不会被再次创建的

原因在于第二种方式是将一整个对象赋值给了原型对象(prototype),这样会导致原来的原型对象(prototype)上的属性和方法会被全部覆盖掉(pass: 实际开发中两种方式不要混用),那么 constructor 的指向当然也发生了变化,这就导致了原型链的错乱,因此,我们需要手动修正这个问题,在原型对象(prototype)上手动添加上 constructor 属性,重新指向 Person ,保证原型链的正确,即:

    Person.prototype = {
        constructor : Person ,
        showInfo : function () {
            //展示信息
            console.log('My name is ' + this.name , ', I\'m ' + this.age + ' years old!');
        }
    }
    
    console.log(Person.prototype.constructor === Person ) // true


//创建一个类
    var Person = function (name, age ) {
            //私有属性
            var IDNumber = '01010101010101010101' ;
            //私有方法
            function checkIDNumber () {}
            //特权方法
            this.getIDNumber = function () {}
            //实例属性
            this.name = name;
            this.age = age;
            //实例方法
            this.getName = function () {}
    }

    //类静态属性
        Person.isChinese = true;
    //类静态方法
        Person.staticMethod = function () {
            console.log('this is a staticMethod')
        }

        //公有属性
    Person.prototype.isRich = false;
    //公有方法
        Person.prototype.showInfo = function () {}
        
        
           var person = new Person('Tom',24);

        console.log(person.IDNumber) // undefined
        console.log(person.isRich)  // false
        console.log(person.name) // Tom
        console.log(person.isChinese) // undefined
        
        console.log(Person.isChinese) // true
        console.log(Person.staticMethod()) // this is a staticMethod

https://juejin.im/post/5b87b393e51d4557631bf5f0#heading-0

https://zhuanlan.zhihu.com/p/24964910?refer=muyichuanqi
js原型链继承,借用构造函数继承,组合继承,寄生式继承,寄生组合继承

数组扁平化

https://juejin.im/post/59716f15f265da6c4c500fc7

介绍下Promise的用途和性质 Promise和Callback有什么区别

http://es6.ruanyifeng.com/#docs/promise

https://segmentfault.com/a/1190000013141641

手写算法

https://juejin.im/post/5b72f0caf265da282809f3b5

https://juejin.im/post/59ac1c4ef265da248e75892b#heading-12

https://www.jianshu.com/p/8376170fb228

https://juejin.im/post/5b31a4b7f265da595725f322#heading-8

https://segmentfault.com/a/1190000012692321#articleHeader18

用 Throttle 来优化 Debounce

debounce 的问题在于它“太有耐心了”。试想,如果用户的操作十分频繁——他每次都不等 debounce 设置的 delay 时间结束就进行下一次操作,于是每次 debounce 都为该用户重新生成定时器,回调函数被延迟了不计其数次。频繁的延迟会导致用户迟迟得不到响应,用户同样会产生“这个页面卡死了”的观感。

为了避免弄巧成拙,我们需要借力 throttle 的思想,打造一个“有底线”的 debounce——等你可以,但我有我的原则:delay 时间内,我可以为你重新生成定时器;但只要delay的时间到了,我必须要给用户一个响应。这个 throttle 与 debounce “合体”思路,已经被很多成熟的前端库应用到了它们的加强版

【微信小程序】性能优化

小程序启动加载性能

控制代码包的大小

分包加载

首屏体验(预请求,利用缓存,避免白屏,及时反馈

小程序渲染性能

避免不当的使用setData

合理利用事件通信

避免不当的使用onPageScroll

优化视图节点

使用自定义组件

作者:小平果118
链接:https://juejin.im/post/5b496d5d5188251a90187635
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

JavaScript 中有几种原始类型数据?请再列举几个引用对象。

7 种,分别为:Boolean,Null,Undefined,Number,BigInt,String,Symbol

列举几种引用对象:

普通对象 Object
数组对象 Array
正则对象 RegExp
函数 Function

服务端渲染的优化

Vue组件的设计

CDN 的缓存与回源机制解析

事件冒泡喝事件捕获

JS中事件冒泡与捕获

原型与原型链(继承)

当试图得到一个对象的某个属性时,如果这个对象本身没有这个属性,那么会去它的proto(即它的构造函数的prototype)中寻找。

作用域和闭包

px、em、rem区别介绍

https://segmentfault.com/a/1190000012225828?utm_source=tag-newest
https://juejin.cn/post/6844903988488306701

数组扁平化
重绘和回流 占用的线程
优化的时间
webpack打包的时间和速度
v8

https://juejin.im/book/5a36661851882538e2259c0f/section/5a37bbb35188257d167a4d64

https://juejin.im/book/5b936540f265da0a9624b04b/section/5bb1826af265da0a972e3038

http://www.imooc.com/read/68/article/1558

http://www.imooc.com/read/68/article/1546

https://juejin.im/book/5bdc715fe51d454e755f75ef/section/5bdc715f6fb9a049c15ea4e0

new的实现

  • 创建一个空对象
  • 获取构造函数
  • 设置空对象的原型
  • 绑定 this 并执行构造函数
  • 确保返回值为对象

实现一个简易的DOM选择器

var $ = jQuery = function (selector,context) {    //定义类
    return new jQuery.fn.init(selector,context);    //返回选择器的实例
};
jQuery.fn = jQuery.prototype = {    //jQuery的原型对象
    init: function(selector,context) {    //定义选择器的构造器
        selector = selector || document;    //默认值为document
        context = context || document;    //默认值为document
        if (selector.nodeType) {    //如果传入的参数是DOM节点
            this[0] = selector;        //把参数节点传递给实例对象的index
            this.length = 1;        //设置长度为1
            this.context = selector;
            return this;    //返回jQuery对象
        }
        if (typeof selector === 'string') {//如果传进来的是标签字符串
            let ele = document.getElementsByTagName(selector);    //获取指定名称的元素
            for (let i = 0; i < ele.length; i++) {    //将获取到的元素放入实例对象中
                this[i] = ele[i];
            }
            this.length = ele.length;
            return this;
        } else {
            this.length = 0;
            this.context = context;
            return this;
        }
    },
    name : "jQuery",
    size : function () {
        return this.length;
    }
};
jQuery.prototype.init.prototype = jQuery.prototype;let div = $('div').size();

实现$('div').html("hello")功能

var $ = jQuery = function (selector,context) { //定义类
return new jQuery.fn.init(selector,context); //返回选择器的实例
};
jQuery.fn = jQuery.prototype = { //jQuery的原型对象
init: function(selector,context) {
//定义选择器的构造器    //省略初始化构造器的主体代码
},

constructor: jQuery,

//定义jQuery中的html()方法
html: function(val) {
    if (val) {
        for(let i = 0; i < this['length']; i++){
               this[i].innerHTML = val; 
        }
    }else {
        return this[0].innerHTML;
    }      
},    
name : "jQuery",
size : function () {
    return this.length;
}

};

jQuery.prototype.init.prototype = jQuery.prototype;
let div = $('div').html('hello');

https://juejin.cn/post/6844903827036962824

HTTP面试问题之(三):HTTP状态码(HTTP Status Code)一般有哪些?
https://blog.csdn.net/peipeiluo/article/details/80157232

bind的实现
tigger remove 的实现
数组perent_id 分类
promise
排序

你可能感兴趣的