前端笔记

1.mock 的理解 优劣 :

在系统交互双定义好接之后,我们可以提前进行开发和测试,并不依赖上游系统的开发实现
 优点:与前端代码分离,可生成随机数据
缺点:数据都是动态生成的假数据,无法真实模拟增删改查的情况

2.fiddler -----http协议调试代理工具

a,最强大最好用的Web调试工具之一,它能记录所有客户端和服务器的http和https请求,
允许你监视,设置断点,甚至修改输入输出数据. 使用Fiddler无论对开发还是测试
b.是强大的抓包工具,它的原理是以web代理服务器的形式工作的
c.同类的工具有: httpwatch, firebug, wireshark

  1. charles 是做什么的
    Charles 是在 PC 端常用的网络封包截取工具,在做移动开发时,我们为了调试与服务器端的网络通讯协议,常常需要截取网络封包来分析。除了在做移动开发中调试端口外,Charles 也可以用于分析第三方应用的通讯协议。配合 Charles 的 SSL 功能,Charles 还可以分析 Https 协议。
    Charles 通过将自己设置成系统的网络访问代理服务器,使得所有的网络访问请求都通过它来完成,从而实现了网络封包的截取和分析。

4.forEach 不能 break 退出,return 只能跳出本次循环,

    var  arr = [1,2,3,4,5,6,7]
    ;arr.forEach((item)=>{
        if(item === 3){
            return 
        }
        console.log(item)// 1,2,4,5,6,7
    })
    
    如果要真正意义跳出循环,可以使用try...catch,throw new Error()
    
    try{
         [1,2,3,4,5,6,7].forEach((item)=>{
        if(item === 3){
            throw new Error('exit') 
        }
        console.log(item)
    })
    }catch(e){
        if(e.message != 'exit'){
            throw e
        }
        console.log(e)
    }

5.break ,continue ,return 的区别及作用

break:可以用在    for、do/while、while、for/in、for/of
      不能用在 forEach、map 遍历中使用,
continue :可以用在 for、do/while、while、for/in、for/of
        不能用在 forEach、map 遍历中使用,
return:    在 for、do/while、while、for/in、for/of 中会退出循环,类似 break 的效果
        在 forEach、map 遍历中,只跳过当前循环,会继续下次迭代,类型 continue 的效果

    for(let ii of [1,2,3,4,5,6]){
        if(ii == 3){
            break
        };
        console.log(ii)
    }
在 break,continue和return 三个关键字中, break,continue是化为一类的,return 是函数返回语句,但是返回的同时也将函数停止。

相同之处:三个都会将此时进行的语句停止。

不同之处:

a、break:是立即结束语句,并跳出语句,不再执行 for循环;//1,2

b、continue:是停止当前语句,本次循环的后面语句不再执行,执行下一循环语句。// 1,2,4,5,6

c、return:停止函数。//会报错,Illegal return statement

d、使用的语句环境不一样,break和continue是用在循环或switch语句中,return是用在函数语句中。

forEach 不能使用 break,continue;

continue语句只能用在while语句、do/while语句、for语句、或者for/in语句的循环体内,在其它地方使用都会引起错误!

return语句应用范围只能出现在函数体内,出现在代码中的其他任何地方都会造成语法错误

6.JS中return 和 return false的区别

(function (){return  })() // undefined

(function (){return null })()  // null

a. return返回undefined,起到中断方法执行的效果,return 事件处理函数将会继续执行,表单将提交

b. return false,返回错误的处理结果;终止处理;比如表单将终止提交。阻止默认的事件行为

c. return true;返回正常的处理结果.

d、都可以终止执行当前方法;


return false 就相当于终止符,return true 就相当于执行符。 返回的false和true通常用在需要进行布尔类型判断时。


7.在浏览器从输入 URL 到页面加载显示完成的过程?从输入URL到页面加载发生了什么?

DNS解析( 域名解析)
TCP连接
发送HTTP请求
服务器处理请求并返回HTTP报文
浏览器解析渲染页面
连接结束

7.1 页面渲染html的过程

1.浏览器解析html源码,然后创建一个 DOM树。并行请求 css/image/js在DOM树中,每一个HTML标签都有一个对应的节点,
并且每一个文本也都会有一个对应的文本节点。DOM树的根节点就是 documentElement,对应的是html标签。

2.浏览器解析CSS代码,计算出最终的样式数据。构建CSSOM树。对CSS代码中非法的语法它会直接忽略掉。
解析CSS的时候会按照如下顺序来定义优先级:浏览器默认设置 < 用户设置 < 外链样式 < 内联样式 < html中的style。

3.DOM Tree + CSSOM --> 渲染树(rendering tree)。渲染树和DOM树有点像,但是是有区别的。

DOM树完全和html标签一一对应,但是渲染树会忽略掉不需要渲染的元素,比如head、display:none的元素等。
而且一大段文本中的每一个行在渲染树中都是独立的一个节点。渲染树中的每一个节点都存储有对应的css属性。

4.一旦渲染树创建好了,浏览器就可以根据渲染树直接把页面绘制到屏幕上。

以上四个步骤并不是一次性顺序完成的。如果DOM或者CSSOM被修改,以上过程会被重复执行。
实际上,CSS和JavaScript往往会多次修改DOM或者CSSOM。

renderTree里包括js执行吗?
 浏览器应用HTML解析器对HTML文档进行解析生成 DOM 树
应用CSS解析器对CSS代码进行解析生成 CSSOM 树
两者合并生成  render tree
生成render tree之后,会去执行js代码,如果js代码有操作dom,就会立即挂起js,
然后去更新DOM,更新完毕之后再执行js,再挂起...直至js不再涉及DOM操作,
只要js操作了DOM,就会触发render tree的修改, render tree修改会导致layout tree 的修改,
这一过程是非常耗时的,其中就涉及到了重排、重绘。layout tree不再变化之后就会通知UI线程,
进行paint。这就是整个渲染机制的流程。

重排:当render tree中一部分,因为元素的规模尺寸,布局,隐藏等改变而需要重新构建,这一过程就叫做重排,重排之后必定会导致浏览器重新绘制页面,导致重绘。
重绘:例如当元素内文字或者颜色变化,就会进行重新渲染,这个过程称为重绘。

    (1)解析生成DOM 树、CSSOM树

    (2)结合生成 渲染树 render tree

      (3)  结合js生成布局树 layout tree 

      (4)  最后进行绘制 paint

8.HTTP 与 HTTPS 的区别,

HTTP 默认工作在 TCP 协议 80 端口,HTTP 协议以明文方式发送内容,不提供任何方式的数据加密
HTTPS 默认工作在 TCP 协议443端口 
HTTPS工作流程:1、TCP 三次同步握手
    2、客户端验证服务器数字证书
    3、DH 算法协商对称加密算法的密钥、hash 算法的密钥
    4、SSL 安全加密隧道协商完成
    5、网页以加密的方式传输,用协商的对称加密算法和密钥加密,保证数据机密性;
    用协商的hash算法进行数据完整性保护,保证数据不被篡改。
    
HTTP 页面响应速度比 HTTPS 快,主要是因为 HTTP 使用 TCP 三次握手建立连接,
客户端和服务器需要交换 3 个包,而 HTTPS除了 TCP 的三个包,还要加上 ssl 握手需要的 9 个包,所以一共是 12 个包。
三次握手:1,x==> 
        <==1,y ,x+1
        ==>x+1,y+1
HTTP 的连接很简单,是无状态的。HTTPS 协议是由 SSL+HTTP 协议构建的可进行加密传输、身份认证的网络协议,比 HTTP 协议安全。
HTTPS协议要申请CA认证;HTTPS的安全基础是TLS/SSL
标准的http协议是无状态的,无连接的

9.webpack的打包过程及原理

a.初始化参数:从配置文件和Shell语句中读取与合并参数,得出最终的参数
b.确定入口:根据配置中的entry 找出所有的入口文件。
c.编译模块:从入口文件出发,调用所有配置的Loader对模块进行翻译.
    再找出该模块依赖的模块.再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理
d.完成模块编译:得到了每个模块被翻译后的最终内容以及它们之间的依赖关系,即AST树,得到关系依赖图
e.输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的Chunk,
    再把每个Chunk转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会。
    
打包原理:webpack从入口文件开始分析模块依赖关系,针对不同的模块使用不同的loader,
         编译模块生成抽象语法树,循环遍历语法树拼接输出。
         webpack将每个boundle生成为一个自执行函数,参数是依赖的模块。
         每个模块有唯一的id。
         webpack按照模块引入顺序执行这些模块。

10.loader和plugins区别

Loader直译为"加载器"。Webpack将一切文件视为模块,但是webpack原生是只能解析js文件,
如果想将其他文件也打包的话,就会用到loader。 
所以Loader的作用是让webpack拥有了加载和解析非JavaScript文件的能力。
loader它只专注于转化文件(transform)这一个领域,完成压缩,打包,语言翻译;
而plugin不仅只局限在打包,资源的加载上,还可以打包优化和压缩,重新定义环境变量等

Plugin直译为"插件"。Plugin可以扩展webpack的功能,让webpack具有更多的灵活性。
在 Webpack 运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,
在合适的时机通过 Webpack 提供的 API 改变输出结果

loader运行在打包文件之前(loader为在模块加载时的预处理文件);plugins在整个编译周期都起作用

一个loader的职责是单一的,只需要完成一种转换。一个loader其实就是一个Node.js模块。
当需要调用多个loader去转换一个文件时,每个loader会链式的顺序执行

不同的用法:

Loader在module.rules中配置,也就是说他作为模块的解析规则而存在。
类型为数组,每一项都是一个Object,里面描述了对于什么类型的文件(test),
使用什么加载(loader)和使用的参数(options)

Plugin在plugins中单独配置。 类型为数组,每一项是一个plugin的实例,参数都通过构造函数传入

11.什么是微任务和宏任务

微任务和宏任务皆为异步任务,它们都属于一个队列
ES6 规范中,microtask 称为 jobs,macrotask 称为 task
宏任务是由宿主发起的,而微任务由JavaScript自身发起。
宏任务一般是:script、setTimeout、setInterval、I/O、UI Rendring、postMessage、MessageChannel、异步Ajax请求、文件操作、setImmediate(Node.js 环境)
微任务:Object.observe、MutationObserver、Process.nextTick(Node独有)、promise.then()、.catch()、 .finally 
每一个宏任务执行完之后,都会检查是否存在待执行的微任务, 如果有,则执行完所有微任务之后,再继续执行下一个宏任务。
先执行同步再执行异步,异步遇到微任务,先执行微任务,执行完后如果没有微任务,
就执行下一个宏任务,如果有微任务,就按顺序一个一个执行微任务
执行顺序:先执行同步代码,遇到异步宏任务则将异步宏任务放入宏任务队列中,遇到异步微任务则将异步微任务放入微任务队列中,当所有同步代码执行完毕后,再将异步微任务从队列中调入主线程执行,微任务执行完毕后再将异步宏任务从队列中调入主线程执行,一直循环直至所有任务执行完毕。

这里容易产生一个错误的认识:就是微任务先于宏任务执行。实际上是先执行同步任务然后在执行异步任务,异步任务是分宏任务和微任务两种的。


微任务是更小的任务,微任务更新应用程序的状态,但是必须在浏览器任务继续执行其他任务之前执行,
浏览器任务包括重新渲染页面的UI。

微任务包括Promise的回调函数,DOM发生变化等,微任务需要尽可能快地,通过异步方式执行,同时不能产生全新的微任务。
微任务能使得我们能够在重新渲染UI之前执行指定的行为,避免不必要的UI重绘,UI重绘会使得应用状态不连续
另一些异步回调会进入 microtask queue(微任务队列) ,等待后续被调用,这些异步函数包括:
微任务:
process.nextTick (Node)
Promise.then()
catch
finally
Object.observe
MutationObserver

微任务会在下一轮任务开始前执行。
1.每执行完一个宏任务后 都会将微任务清空 然后再从宏任务队列中取出第一个宏任务执行

2.宏任务是到时间了才会放在宏任务队列

3.微任务是立刻放入到微任务队列中的
下一个宏任务执行前会去查看微任务队列中是否有任务 有就执行所有的微任务 微任务全部执行完 再去执行下一个宏任务

【浏览器执行任务的顺序:】

1.从task任务队列中取第一个task(比如setTimeout、setIntervel的回调,也可以将同一轮循环中的所有同步代码看作是一个宏任务),执行它。
2.执行微任务队列里的所有微任务。
3.浏览器判断是否更新渲染屏幕,如果需要重新绘制,则执行步骤4-13,如果不需要重新绘制,则流程回到步骤1,这样不断循环。
4.触发resize、scroll事件,建立媒体查询(执行一个任务中如果生成了微任务,则执行完任务该后就会执行所有的微任务,然后再执行下一个任务)。
5.建立css动画(执行一个任务中如果生成了微任务,则执行完该任务后就会执行所有的微任务,然后再执行下一个任务)。
6.执行 requestAnimationFrame 回调(执行一个任务中如果生成了微任务,则执行完该任务后就会执行所有的微任务,然后再执行下一个任务)。
7.执行 IntersectionObserver 回调(执行一个任务中如果生成了微任务,则执行完该任务后就会执行所有的微任务,然后再执行下一个任务)。
8.更新渲染屏幕。
9.浏览器判断当前帧是否还有空闲时间,如果有空闲时间,则执行步骤10-12。
10.从 requestIdleCallback回调函数队列中取第一个,执行它。
11.执行微任务队列里的所有微任务。
12.流程回到步骤9,直到requestIdleCallback回调函数队列清空或当前帧没有空闲时间。
13.流程回到步骤1,这样不断循环。


在此次 tick 中选择最先进入队列的任务( oldest task ),如果有则执行(一次)
检查是否存在 微任务 ,如果存在则不停地执行,直至清空微任务 Queue
更新 render
主线程重复执行上述步骤
根据HTML Standard,一轮事件循环执行结束之后,下轮事件循环执行之前开始进行 UI render。
即:宏任务执行完毕,接着执行完所有的微任务后,此时本轮循环结束,
开始执行UI render。UI render完毕之后接着下一轮循环。

requestAnimationFrame回调的执行与task和microtask无关,而是与浏览器是否渲染相关联的。

                它是在浏览器渲染前,在微任务执行后执行,requestAnimationFrame使用一个回调函数作为参数,
                这个回调函数会在浏览器重绘之前调用。
                它返回一个整数,表示定时器的编号,这个值可以传递给cancelAnimationFrame用于取消这个函数的执行

requestIdleCallback是在浏览器渲染后有空闲时间时执行,

                如果requestIdleCallback设置了第二个参数timeout,则会在超时后的下一帧强制执行。

12.canvas.width和canvas.style.width区别以及应用

canvas.width / canvas.height 表示画布真实大小,其实我们并不可见
canvas.style.width / canvas.style.height 表示画布输出到浏览器我们可见的/最终的大小                    


13.DDOS是(Distributed Denial of Service)的缩写,即分布式阻断服务,
广域文件服务(WAFS)
TTFB 是 Time To First Byte的缩写,是指从访客打开网站页面到网页内容开始呈现之间的等待时间。
TTFB只是一个指标,只代表网站服务器的响应速度
Time to Interactive可交互时间 (TTI)

First Contentful Paint 首次内容绘制 (FCP)

浏览器并发数 6
立即执行函数表达式(IIFE)

BFC

14.浏览器F12 waterfall性能检测详解详解

    Queueing 是排队的意思

    Stalled 是阻塞  请求访问该URL的主机是有并发和连接数限制的,必须要等之前的执行才能执行之后的,这段时间的耗时

    DNS Lookup 是指域名解析所耗时间

    Initial connection 初始化连接时间,这里一般是TCP 3次连接握手时间
    
    SSL https特有,是一种协议 

    Request sent 发送请求所消耗的时间     

    Waiting 等待响应时间,这里一般是最耗时的

    Content Download 下载内容所需要消耗的时间

15.首屏优化

    
    DNS prefetching  
    Preconnect  。
    prefetch    
    prerender    
    preload        
                
                
    JavaScript外联文件引用放在html文档底部;
    CSS外联文件引用在html文档头部,位于head内;对首屏页面用到的 css内容,可以style 的形式写在首页
    精灵图
    压缩图片,大图用base64,
    CDN优化
    按需加载
    Webpack,nginx开启gzip压缩
    避免404错误:尽量减少外联js
    减少DOM Elements的数量
    
    
    
    

16.attribute 和 property区别

attribute是html文档上标签属性,

而property则是对应dom元素的自身属性。从操作方法上来看,attribute可以通过 getAttribute和setAttribute进行获取修改,

而property可以通过对象访问属性的方式 . 或者 [" "]来修改获取。

  1. debounce
    函数防抖(debounce),就是指触发事件后,在 n 秒内函数只能执行一次,
    如果触发事件后在 n 秒内又触发了事件,则会重新计算函数延执行时间
    onresize,scroll,mousemove ,mousehover 等,会被频繁触发(短时间内多次触发)

    function debounce(fn, wait = 50) {

    let timer = null
    return function(...args) {
        var context =  this;
        if (timer) clearTimeout(timer)
        timer = setTimeout(() => {
            
            fn.apply(context, args)
        }, wait)
    }

    }

    function throttle(action, delay) {
    let timeout = null;
    let movement = null;
    let lastRun = 0;
    let needRun = false;
    return function () {

    needRun = true;
    if (timeout) {
      return;
    }
    let elapsed = Date.now() - lastRun;
    let context = this;
    let args = arguments;
    let runCallback = function () {
      lastRun = Date.now();
      timeout = false;
      action.apply(context, args);
    };
    if (elapsed >= delay) {
      runCallback();
    } else {
      timeout = setTimeout(runCallback, delay);
    }
    if (needRun) {
      clearTimeout(movement);
      movement = setTimeout(runCallback, 2 * delay);
    }

    };
    }

    防抖和节流本质是不一样的。防抖是将多次执行变为最后一次执行,节流是将
    多次执行变成每隔一段时间执行
    函数防抖一定连续触发的事件,只在最后执行一次,而函数节流一段时间内只执行

    一次。

  2. .native 的用法
    你可能有很多次想要在一个组件的根元素上直接监听一个原生事件。这时,你可以使用 v-on 的 .native 修饰符:
    在组件上自定义事件,采用native与否,差别很大。
    采取native,自定义事件注册到组件的顶级元素上。随便点击都能触发回调函数。

    不采取native,自定义事件注册到组件实例上,点击无法触发回调函数,只能通过emit的方式触发事件。

  3. target和currentTarget的区别

    currentTarget始终是监听事件者,而target是事件的真正发出者。
    比如说现在有parent和child,parent包含child,parent监听鼠标点击事件
    那么当点击child时,target是child,currentTarget是parent


20。event.stopPropagation()和 event.preventDefault()
event.preventDefault() 方法阻止元素发生默认的行为
event.stopPropagation 是用来阻止事件传递的,阻止的是整个事件传递过程中,该节点之后的事件传递。
也就是说,stopPropagation阻止的并不单单是捕获阶段或者冒泡阶段,
它针对的是整个事件传递过程,即包括了事件捕获以及事件冒泡。

捕获阶段:先由文档的根节点document往事件触发对象,从外向内捕获事件对象;
目标阶段:到达目标事件位置(事发地),触发事件;
冒泡阶段:再从目标事件位置往文档的根节点方向回溯,从内向外冒泡事件对象。
capture phase(捕获阶段)=》 target phase(目标阶段) =》 bubble phase(冒泡阶段)


21.$nextTickd 的作用

何为$nextTick,是Vue的异步更新队列,$nextTick是用来知道什么时候DOM更新完成的。
Vue实现响应并不是指DOM在数据改变后立即改变,而是按照一定的策略更新DOM。
$nextTick是在下一次DOM更新的循环结束后的延迟回调。如果在修改数据后使用$nextTick
,可以在回调中获得更新后的DOM。
Vue 在更新 DOM 时是异步执行的。当数据发生变化,Vue将开启一个异步更新队列,
视图需要等队列中所有数据变化完成之后,再统一进行更新
数据在发现变化的时候,vue并不会立刻去更新Dom,而是将修改数据的操作放在了一个异步操作队列中

如果我们一直修改相同数据,异步操作队列还会进行去重

等待同一事件循环中的所有数据变化完成之后,会将队列中的事件拿来进行处理,进行DOM的更新

  1. 聊聊 == 和===

    Undefined 只和 Null 相等  null == undefined
    和 Number 比较时,另一个值会自动转换为 Number
    和 Boolean 比较时,另一个值会转换为 Number
    如果两个操作数都是对象,则仅当两个操作数都引用同一个对象时才返回true。
    当数字与字符串进行比较时,会尝试将字符串转换为数字值。
    如果操作数之一是Boolean,则将布尔操作数转换为1或0。
    如果是 true,则转换为1。
    如果是 false,则转换为0。
    如果操作数之一是对象,另一个是数字或字符串,会尝试使用对象的valueOf()和toString()方法将对象转换为原始值。

    null == undefined // true
    null == null // true
    null === null // true
    undefined == undefined // true
    undefined === undefined // true
    null !== undefined
    1 == '1' // true
    0 == '0' // true
    0 == '' // true
    [0] != ''
    [[]] == '' // true
    [[]] == 0 // true
    [[]] == false // true
    [] == false // true
    [0] == false // true
    ['0'] == false // true
    [''] == false // true
    [1] == true // true
    ['1'] == true // true
    /b/i == /b/i // false
    /b/i === /b/i // false
    new RegExp(/b/i) == new RegExp(/b/i) // false
    new RegExp(/b/i) === new RegExp(/b/i) // false

Object.prototype.toString.call(/b/i) // '[object RegExp]'
Object.prototype.toString.call(new RegExp(/b/i)) // '[object RegExp]'
var string1 = "hello";
var string2 = String("hello");
var string3 = new String("hello");

string2 == string1 // true
string3 == string2 // true
string3 == string1 // true
string2 === string1 // true
string3 === string1 // false
string3 === string2 // false

Object.is() 与 == 不同 , Object.is 不会强制转换两边的值。
Object.is() 与 === 也不相同。差别是它们对待有符号的零和 NaN 不同,
例如,=== 运算符(也包括 == 运算符)将数字 -0 和 +0 视为相等,而将 Number.NaN 与 NaN 视为不相等。
Object.is(NaN,NaN) // true
Object.is(+0,-0) // false

在JavaScript中,如果想要将对象转换成基本类型时,也就是所谓的拆箱时,会调用toPrimitive()。
如果转换的类型是number,会执行以下步骤:

  1. 如果input是原始值,直接返回这个值;
  2. 否则,如果input是对象,调用input.valueOf(),如果结果是原始值,返回结果;
  3. 否则,调用input.toString()。如果结果是原始值,返回结果;
  4. 否则,抛出错误。

如果转换的类型是String,2和3会交换执行,即先执行toString()方法。

你也可以省略preferedType,此时,日期会被认为是字符串,而其他的值会被当做Number。

number 布尔值 除了0、-0、NaN都为true
string 布尔值 除了空串都为true
undefined、null 布尔值 false
引用类型 布尔值 true
number 字符串 5 => ‘5’
Boolean、函数、Symbol 字符串 true => ‘true’
数组 字符串 [1,2] => ‘1,2’
对象 字符串 ‘[object Object]’
string 数字 ‘1’ => 1, ‘a’ => NaN
数组 数字 空数组为0、存在一个元素且为数字转为数字、其他情况NaN
null 数字 0
除了数组的引用类型 数字 NaN
Symbol 数字 抛错
———

JavaScript 中很多系统函数都使用严格相等,比如数组的 indexOf,lastIndexOf 和 switch-case 等
同值零是另一种相等算法,名字来源于规范的直译,规范中叫做 SameValueZero,
同值零和严格相等功能一样,除了处理 NaN 的方式,同值零认为 NaN 和 NaN 相等,
这在判断 NaN 是否在集合中的语义下是非常合理的。
ECMAScript 2016 引入的 includes 使用此算法,此外 Map 的键去重和 Set 的值去重,使用此算法
[NaN].incdudes(NaN)// true
new Set([NaN, NaN]); // [NaN]
new Map([
[NaN, 1],
[NaN, 2],
]); // {NaN => 2}


  1. _c 与 $createElement

    vm._c = function (a, b, c, d) { return createElement$1(vm, a, b, c, d, false); };
    vm.$createElement = function (a, b, c, d) { return createElement$1(vm, a, b, c, d, true); };

    _c 与 $createElement 都是基于 createElement 函数的包装,
    _c 用于编译后产生vnode的 render 函数,$createElement用于用户手写的 render 函数。
    _c是由vue自带的complier编译解析的,而$createElement是我们自己写的render中的h函数
    if (normalizationType === ALWAYS_NORMALIZE) {
    // true

    children = normalizeChildren(children) // $createElement

    } else if (normalizationType === SIMPLE_NORMALIZE) {
    //false

    children = simpleNormalizeChildren(children) // _c 

    }
    simpleNormalizeChildren(参数是false,调用_c)和normalizeChildren(参数是true,调用$createElement)的实现

    simpleNormalizeChildren [_c] 调用方法场景就是render函数调用编译生成的,理论上编译生成的 children都已经是 VNode 类型的,
    但这里有一个例外,就是 functional component函数式组件返回的是一个数组而不是一个根节点,
    所以会通过 Array.prototype.concat方法把整个 children数组打平,让它的深度只有一层。

    normalizeChildren [$createElement]中主要是调用normalizeArrayChildren函数去处理children类数组,
    判断children中的元素是不是数组,如果是的话,就递归调用数组,并将每个元素保存在数组中返回。
    造成这种类型不同主要是由于render函数是用户自己手写的还是template生成的。
    render: function (createElement) {
    return createElement('h1', this.blogTitle)

    }

    render函数中的 createElement 方法就是vm.$createElement 方法。
    _createElement 函数已经完成创建VNode的功能,将其返回给render函数。
    vnode = render.call(vm._renderProxy,vm.$createElement)
    normalizeChildren 方法的调用场景有 2 种,一个场景是 render 函数是用户手写的,
    当 children 只有一个节点的时候,Vue.js 从接口层面允许用户把 children写成基础类型用来创建单个简单的文本节点,
    这种情况会调用 createTextVNode 创建一个文本节点的 VNode;
    另一个场景是当编译 slot、v-for 的时候会产生嵌套数组的情况,会调用 normalizeArrayChildren方法

总结:vue在渲染阶段会把模板编译为AST,然后根据AST生成render函数,底层通过调用render函数会生成VNode创建虚拟DOM。
template (parse)=> AST (compile)=> vm.option.render function (render) => virtual dom

// 需要编译器
new Vue({
template: '

{{ hi }}
'
})

// 不需要编译器
new Vue({
render (h) {

return h('div', this.hi)

}

})

  1. Vue2中组件间通信的6种方式

     props / $emit
     ref / $refs
     eventBus事件总线($emit / $on)
     依赖注入(provide / inject)
     $parent / $children
     $attrs / $listeners
     
     
     inheritAttrs:true 时继承除props之外的所有属性
     inheritAttrs:false 只继承class 和 style属性
     

25.函数 柯里化
柯里化(Currying)又称部分求值,一个柯里化的函数首先会接收一些参数,接收了这些参数后,该函数并不会立即求值,而是继续返回另外一个函数,刚才传入的参数在函数形成的闭包中被保存起来。待到函数被真正需要求值的时候,之前传入的所有参数都会被一次性用于求值。

柯里化是一种函数的转换,它是指将一个函数从可调用的 f(a, b, c) 转换为可调用的 f(a)(b)(c)或者f(a, b)(c)或者f(a)(b, c)

通俗的来说:固定部分参数,返回一个接受剩余参数的函数,也称为部分计算函数,目的是为了缩小适用范围,创建一个针对性更强的函数。核心思想是把多参数传入的函数拆成一个个的单参数(或部分)函数,内部再返回调用下一个单参数(或部分)函数,依次处理剩余的参数。有点类似俄罗斯套娃,一层包一层

备注:柯里化不会调用函数。它只是对函数进行转换。

bind方法是函数柯里化应用的经典场景

Function.prototype.bind = function (context) {

var fun = this;
var args = Array.prototype.slice.call(arguments, 1)

return function() {
    return fun.apply(context, args)
}

}
//f.bind({},'3')()

实现一个函数,将普通函数柯里化

var curry = function (fn){

let len =  fn.length;
return function t (){
    const argslength = arguments.length;
    const args = Array.prototype.slice.call(arguments);// [...arguments ];
    if(len <= argslength){
    //////////////////////////// //>
        return fn.apply(null,args)
    }else{
        //继续柯里化
        return function (){
            const innerargs = Array.prototype.slice.call(arguments);
            return t.apply(null, args.concat(innerargs))
        }
    }

}

}


26.bind,apply,call的区别和实现

fn.bind(null,1,2,3)

fn.call(null,1,2,3)

fn.apply(null,[1,2,3])
apply,call会立即执行,bind不会立即执行,而是返回一个改变了this指向的函数
call,apply在第一个参数为undefined或null时,this会指向window
  
  
Function.prototype.call = function(context,...args){
    
    context.func = this ;
    const result = context.func(...args);
    delete context.func;
    return result
}


27.new的过程中发生了什么

1.创建一个新的对象obj
2.将这个对象与构建函数通过原型链连接起来
3.将构建函数中的this绑定到新建的对象obj上
4.返回对象
function mynew(Func, ...args) {
    // 1.创建一个新对象
    const obj = {}
    // 2.新对象原型指向构造函数原型对象
    obj.__proto__ = Func.prototype
    // 3.将构建函数的this指向新对象
    let result = Func.apply(obj, args)
    // 4.根据返回值判断
    return result instanceof Object ? result : obj
}
还有一种更简单的实现方式,通过Object.create,直接指定原型链
function _new(Func, ...args){
    const obj = Object.create(Func.prototype);
    Func.call(obj,...args);
    return obj
}

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

Person.prototype.sayHello = function() {
  console.log(`Hello, my name is ${this.name}`);
};

const alice = new Person('Alice');
alice.sayHello(); // 输出: Hello, my name is Alice

// 修改Person构造函数的prototype属性
Person.prototype.aaaaaaaa = function() {
  console.log(`Goodbye, ${this.name}`);
};

alice.aaaaaaaa(); // 输出: Goodbye, Alice
原型是function对象下的属性,它定义了构造函数的共同祖先,也就是一个父子级的关系,
子对象会继承父对象的方法和属性,每个实例对象下都有__proto__属性,
通过属性__proto__指向构造函数的原型对象,当到达末端时,
返回null,这样一层一层向顶端查找,就形成了原型链

  1. [].concat([1,2,3],[4,5]) // [1, 2, 3, 4, 5]
    [].concat(1,2,3,[4,5]) // [1, 2, 3, 4, 5]
    [].concat(1,2,3,4,5) // [1, 2, 3, 4, 5]

    var a = [[1, 2], [3, 4]]
    [].concat( a[0],a[1]) // [1, 2, 3, 4]
    [].concat.apply([], a) // [1, 2, 3, 4]

    Array.prototype.concat.apply([],a);// [1, 2, 3, 4]

  2. 1.toString() 为什么会报错
    //报错,JS引擎无法确定这里的.是什么意思,是点运算符(对象方法)还是浮点数?
    var num = 1;
    num.toString(); // "1"
    Number(1).toString(); // "1"
    1.0.toString(); // "1"
    1..toString(); // "1"
  3. .toString(); // "1"
    (1).toString(); // "1"
    当点跟在一个数字后面就意味着这个数字是一个浮点数,在点后面JS等待着一个数字。
    所以在调用toString()之前,我们需要告诉JS这是就是我们要的数字。

    通过变量(num.)的形式调用toString(),实际上是发生了隐式转换,,隐式转换变为包装类型,所以不会报错。

    30.对象无法被for of 枚举

var os = {a:1,b:2,c:3}

for(let ii of os){console.log(ii)}
//Uncaught TypeError: os is not iterable

如果需要遍历的对象是类数组对象 ,先将类数组转为数组
const obj = {1:1,2:2,3:3,length:3}
const arr = Array.from(obj)
for(let ii of arr){
console.log(ii) // 1,2,3
}

需要遍历的对象不是类数组而是对象,给对象添加一个Symbol.iterator属性,并指向迭代器

const person = {

name:'ib',
age:16,
sex:'男',
address:'iohjihuier',
width:300,
height:200,

}
//Symbol.iterator 为每一个对象定义了默认的迭代器。该迭代器可以被 for...of 循环使用。
person[Symbol.iterator] = function (){

let index = 0;
const key = Object.keys(this);
return {
    next(){
        if(index < key.length){
        ////////////////////////>
            return {value:key[index],done:false}
        }else{
            return {value:undefined,done:true}
        }
    }
}


}
//数组迭代器是一次性的,或者说临时对象,迭代完成后再次迭代,将会一直是undefined
当 next().done=true 或 currentIndex > length 时, for..of 循环结束

for(let oo of person){

console.log(oo)

}
Array.prototype.values 是 Array.prototype[Symbol.iterator] 的默认实现。
Array.prototype.values === Array.prototype[Symbol.iterator] // true


31 TCP 和 UDP 区别

TCP 靠谱稳定,能够保证数据准确无误的送到对方,先建链接再发数据,双工通道,
数据无差异,不丢数据,不重复数据,按顺序到达,只能一对一


32.import 实现原理

jsonp(动态创建script)+ promise.resolve
import()是个语法糖,返回值是一个Promise对象,意味着这需要异步处理,你可以在.then()中拿到真正的模块。
基于这点,其实是这样的:{component: () => {return import('xxx');},}
把import包裹在函数中,当真正用到模块的时候,才执行 component().then()。这就是懒加载了


  1. require 和 import 区别

34.创建vue2.0项目

npm install -g @vue/cli
 vue -V查看版本
 vue create my-project(项目名)可创建项目
 cd my-project(进入该项目文件夹下),再输入 npm run serve 即可打开项目

35 defer async

defer,“延迟” 之意。这里的延迟,指的是延迟执行脚本,下载则不会被阻塞。

给 script 标签添加了 defer 属性后,脚本不会阻塞 DOM 树的构建,会先下载资源,然后等待到在 DOMContentLoaded 事件前执行

设置 async 后,脚本一旦被下载好了就会执行,不管什么时机。
有 async,加载和渲染后续文档元素的过程将和 script.js 的加载与执行并行进行(异步)。

defer,async的差别在于脚本下载完之后何时执行,显然 defer 是最接近我们对于应用脚本加载和执行的要求的
defer与async的区别是:前者要等到整个页面正常渲染结束,才会执行;
后者一旦下载完,渲染引擎就会中断渲染,执行这个脚本以后,再继续渲染。
一句话,defer是“渲染完再执行”,async是“下载完就执行”。
另外,如果有多个defer脚本,会按照它们在页面出现的顺序加载,而多个async脚本是不能保证加载顺序的。
—————————


36.Object.preventExtensions 禁止扩展, 如果你想禁止一个对象添加新属性并且保留已有属性,
就可以使用Object.preventExtensions(...)

Object.seal()会创建一个密封的对象,这个方法实际上会在一个现有对象上调用object.preventExtensions(...)
并把所有现有属性标记为configurable:false。

Object.freeze()会创建一个冻结对象,这个方法实际上会在一个现有对象上调用Object.seal(),
并把所有现有属性标记为writable: false,这样就无法修改它们的值。


  1. 如何让 if(a==1 && a==2 && a==3) 同时 通过

    let b = 0
    Object.defineProperty(window, "a", {
      get : function() { b += 1; return b },
      set : function(newValue) { b = newValue; },
      enumerable : true,
      configurable : true
    });
    if(a==1 && a==2 && a==3){
      console.log('通过')
    }
    

var person = {}
Object.defineProperty(person, "a", {

value:1,
writable:true, // true时 可 person.a = '' 
enumerable : true,
configurable : true // false时不可delete person.a,不能重新定义属性,但是在writable: true的情况下,可以改变value的值

});

person.b = 'g'
等价于
Object.defineProperty(window, "b", {

value:'g',
writable:true,

enumerable : true,
configurable : true

});

configurable: false 时,不能删除当前属性,且不能重新配置当前属性的描述符(有一个小小的意外:
可以把writable的状态由true改为false,但是无法由false改为true),但是在writable: true的情况下,可以改变value的值
configurable: true时,可以删除当前属性,可以配置当前属性所有描述符。

通过Object.defineProperty()为对象定义属性,有两种形式,且不能混合使用,
分别为数据描述符,存取描述符,下面分别描述下两者的区别:
数据描述符 --特有的两个属性(value,writable)
存取描述符 --是由一对 getter、setter 函数功能来描述的属性

数据描述符和存取描述均具有以下描述符
configrable 描述属性是否配置,以及可否删除
enumerable 描述属性是否会出现在for in 或者 Object.keys()的遍历中

var obj = {};
Object.defineProperties(obj, {
'a': {

value: true,
writable: true

},
'b': {

value: 'Hello',
writable: false

}

});


38.Symbol.toStringTag

Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });

Object.prototype.toString.call('foo'); // "[object String]"
Object.prototype.toString.call([1, 2]); // "[object Array]"
Object.prototype.toString.call(3); // "[object Number]"
Object.prototype.toString.call({}); // "[object Object]"
Object.prototype.toString.call(true); // "[object Boolean]"
Object.prototype.toString.call(undefined); // "[object Undefined]"
Object.prototype.toString.call(null); // "[object Null]"
Object.prototype.toString.call(new Map()); // "[object Map]"
Object.prototype.toString.call(function* () {}); // "[object GeneratorFunction]"
Object.prototype.toString.call(Promise.resolve()); // "[object Promise]"
class ValidatorClass {}; Object.prototype.toString.call(new ValidatorClass()); // "[object Object]"

现在,在toStringTag 帮助下,我们可以设置自己的自定义标签:
class ValidatorClass {
get [Symbol.toStringTag]() {

return 'Validator';

}
}

Object.prototype.toString.call(new ValidatorClass()); // "[object Validator]"

Object.defineProperty(t, Symbol.toStringTag, { value: 'a-Module-0' });
Object.prototype.toString.call(t); // '[object a-Module-0]'

Symbol.hasInstance 当其他对象使用 instanceof 运算符,判断是否为该对象的实例时,会调用这个方法
Symbol.isConcatSpreadable 对象的 Symbol.isConcatSpreadable 属性等于的是一个布尔值,表示该对象用于 Array.prototype.concat()时,是否可以展开。
Symbol.species 创建衍生对象时,会使用该属性
Symbol.match 当执行 str.match(myObject) 时,如果该属性存在,会调用它,返回该方法的返回值。
Symbol.replace 当该对象被 str.replace(myObject)方法调用时,会返回该方法的返回值。
Symbol.search 当该对象被 str. search (myObject)方法调用时,会返回该方法的返回值。
Symbol.split 当该对象被 str. split (myObject)方法调用时,会返回该方法的返回值。
Symbol.iterator 对象进行 for…of 循环时,会调用 Symbol.iterator 方法,返回该对象的默认遍历器
Symbol.toPrimitive 该对象被转为原始类型的值时,会调用这个方法,返回该对象对应的原始类型值。
Symbol.toStringTag 在该对象上面调用 toString 方法时,返回该方法的返回值
Symbol.unscopables 该对象指定了使用 with 关键字时,哪些属性会被 with环境排除

Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
Object.defineProperty(t, Symbol.toStringTag, { value: 'a-Module-0' });
Object.prototype.toString.call(t); // '[object a-Module-0]'

const person = {}
//Symbol.iterator 为每一个对象定义了默认的迭代器。该迭代器可以被 for...of 循环使用。
person[Symbol.iterator] = function (){

let index = 0;
const key = Object.keys(this);
return {
    next(){
        if(index < key.length){
        ////////////////////////>
            return {value:key[index],done:false}
        }else{
            return {value:undefined,done:true}
        }
    }
}


}


39.通过css实现隐藏元素方法有如下:

    1.display: none: 渲染树不会渲染对象

    2.visibility: hidden: 元素在页面中仍占据空间,但是不会响应绑定的监听事件。

    3.opacity: 0: 元素在页面中仍然占据空间,并且能够响应元素绑定的监听事件。

    4.position: absolute: 通过使用绝对定位将元素移除可视区域内,以此来实现元素的隐藏。

    5.z-index: 负值:来使其他元素遮盖住该元素,以此来实现隐藏。

    6.clip/clip-path: 元素仍在页面中占据位置,但是不会响应绑定的监听事件。

    7.transform: scale(0,0): 将元素缩放为 0,元素仍在页面中占据位置,但是不会响应绑定的监听事件。

    8、color alpha 透明度

    9、可以通过使用width、height、padding、border-width 或 font-size 来缩小元素的尺寸

    10、覆盖另一个元素

    11、transform 属性可以用于元素的平移、缩放、旋转或倾斜等。

40.箭头函数中的this的指向

箭头函数没有自己的this, 它的this是继承而来; 
默认指向在定义它时所处的对象(宿主对象),此处指父级作用域,而不是执行时的对象,
 定义它的时候,可能环境是window; 

  1. 前端性能优化

    1.减少 HTTP 请求数量,雪碧图,defer  , prefetch /preload/preconnect/prerender ,CDN优化,按需加载,减少dom 数量
    2.gzip(GUNzip)压缩,目前使用最多的一种压缩格式,可以减少文件的大小
    3.利用浏览器的强缓存,服务器协商缓存时间,可以减少服务器的压力。
    4.Ajax缓存」 Last-Modified ,  Expires , Cache-Control

    no-cache—在与源服务器确认之前,不得使用缓存来满足后续的请求。
    max-age—如果当前数值大于在请求时给定的值(秒),那么响应过时
    no-store—缓存不应存储有关客户端请求或服务器响应的任何内容,即不使用任何缓存。

    一般的大的站点的图片服务器都有实现HTTP 304 缓存功能。 webp图片或  avif 图片
    
    这个 304 状态一般主要在用户刷新页面(F5键)的时候触发,当用户在刷新页面的时候,因为原来的页面里的很多图片已经缓存过,
    客户端的浏览器已经记录了图片的最后更新时间(Last Mod),所以在用户刷新页面的时候,
    会向服务器提交一个字段:If-Modified-Since: Wed, 08 Sep 2010 21:35:06 GMT
    这个时候,服务器端的程序先取得这个字段的值,然后与服务器上的图片最后修改时间对比,如果相同,
    就直接返回 304 Not Modified ,然后停止。这样就不用把图片重新传输到客户端,达到节省带宽的目的。    
       
        
【V8 性能优化】
 保证以相同的顺序实例化对象属性,这样可以保证它们共享相同的隐藏类。
在对象实例化后向对象添加属性将会迫使隐藏类改变,这将会使也已经进行行内缓存的方法的访问速度变慢。
所以,请尽量保证,在构造器内进行所有的属性声明。
不停执行相同方法的代码会比总在执行不同方法的代码速度快。



还有我们要循环插入很多DOM元素时,可以使用documentFragment

 //创建DocumentFragment
    var fragment = document.createDocumentFragment();
 
 //把DOM元素添加到fragment
    var oDiv = document.createElement('div');
    for(let i = 0; i < 10; i++){
        oDiv.innerHTML += "number:" + i + '
'; fragment.appendChild(oDiv) } //最后把fragment插入到页面 document.body.appendChild(fragment)

42.聊聊cookie

Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT; Secure; HttpOnly
这个cookie保存在浏览器的运行内存,在浏览器不关闭的情况下,用户再次发送请求的时候会自动将内存的cookie发送给服务器,
服务器通过cookie中的的jsessionid的值找到对应的session对象
 cookie最终是保存在浏览器客户端上的 可以保存在运行内存中(浏览器只要关闭cookie就消失了) 

主要作用:保持客户端状态
在进行页面cookie操作的时候,应该尽量保证每个域cookie个数小于50个,单条cookie总长度4KB
HttpOnly 不支持读写,浏览器不允许脚本操作document.cookie去更改cookie, 所以为避免跨域脚本 (XSS) 攻击,
通过JavaScript的 Document.cookie API无法访问带有 HttpOnly 标记的Cookie,
它们只应该发送给服务端。如果包含服务端 Session 信息的 Cookie 不想被客户端 JavaScript 脚本调用,
那么就应该为其设置 HttpOnly 标记。
由于在HTTP请求中的Cookie是明文传递的,所以安全性成问题,除非用HTTPS,
标记为 Secure 的Cookie只应通过被HTTPS协议加密过的请求发送给服务端。
但即便设置了 Secure 标记,敏感信息也不应该通过Cookie传输,因为Cookie有其固有的不安全性,
Secure 标记也无法提供确实的安全保障。
SameSite是Cookie中的一个属性用来限制第三方Cookie,从而减少安全风险。
浏览器的Cookie新增加了一个SameSite属性,用来防止CSRF攻击和用户追踪。
SameSite 属性有三个枚举值,分别是 strict/lax/none
CSRF 漏洞目前的措施一般是验证 referer 或者是用安全 token,和这个SameSite

sessionStorage保存的数据用于浏览器的一次会话,当会话结束(通常是该窗口关闭),数据被清空;
sessionStorage 特别的一点在于,即便是相同域名下的两个页面,
只要它们不在同一个浏览器窗口中打开,那么它们的 sessionStorage 内容便无法共享;
localStorage 在所有同源窗口中都是共享的;
cookie也是在所有同源窗口中都是共享的。除了保存期限的长短不同

withCredentials是XMLHttpRequest的一个属性,表示跨域请求是否提供凭据信息(cookie、HTTP认证及客户端SSL证明等)

实际中用途就是跨域请求是要不要携带cookie

43.如何判断一个元素是否在可视区域中?

offsetTop、scrollTop el.offsetTop - document.documentElement.scrollTop <= viewPortHeight

function isInViewPortOfOne (el) {
    // viewPortHeight 兼容所有浏览器写法
    const viewPortHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight 
    const offsetTop = el.offsetTop
    const scrollTop = document.documentElement.scrollTop
    const top = offsetTop - scrollTop
    return top <= viewPortHeight
}

getBoundingClientRect
    如果一个元素在视窗之内的话,那么它一定满足下面四个条件:

    top 大于等于 0
    left 大于等于 0
    bottom 小于等于视窗高度
    right 小于等于视窗宽度
    
    function isInViewPort(element) {
      const viewWidth = window.innerWidth || document.documentElement.clientWidth;
      const viewHeight = window.innerHeight || document.documentElement.clientHeight;
      const {
        top,
        right,
        bottom,
        left,
      } = element.getBoundingClientRect();

      return (
        top >= 0 &&
        left >= 0 &&
        right <= viewWidth &&
        bottom <= viewHeight
      );
    }
        

Intersection Observer

Intersection Observer API提供了一种异步观察目标元素与祖先元素或顶级文档viewport的交集中的变化的方法。
这使得以往较难实现的功能,更加简单,例如,监听图片元素,在适当的时候懒加载图片。
Intersection Observer 即重叠观察者,从这个命名就可以看出它用于判断两个元素是否重叠,
因为不用进行事件的监听,性能方面相比getBoundingClientRect会好很多

const options = {
  // 表示重叠面积占被观察者的比例,从 0 - 1 取值,
  // 1 表示完全被包含
  threshold: 1.0, 
  root:document.querySelector('#scrollArea') // 必须是目标元素的父级元素
};
const observer = new IntersectionObserver((entries, observer) => { 
     entries.forEach(entry => {
        entry.time;               // 触发的时间
        entry.rootBounds;         // 根元素的位置矩形,这种情况下为视窗位置
        entry.boundingClientRect; // 被观察者的位置举行
        entry.intersectionRect;   // 重叠区域的位置矩形
        entry.intersectionRatio;  // 重叠区域占被观察者面积的比例(被观察者不是矩形时也按照矩形计算)
        entry.target;             // 被观察者
    });
}, options);
const target = document.querySelector('.target');
observer.observe(target);

44.BFC (Block Formatting Context),即块级格式化上下文,它是页面中的一块渲染区域,并且有一套属于自己的渲染规则:

内部的盒子会在垂直方向上一个接一个的放置
对于同一个 BFC 的俩个相邻的盒子的 margin 会发生重叠,与方向无关。
每个元素的左外边距与包含块的左边界相接触(从左到右),即使浮动元素也是如此
BFC 的区域不会与 float 的元素区域重叠
计算 BFC 的高度时,浮动子元素也参与计算
BFC 就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素,反之亦然
BFC目的是形成一个相对于外界完全独立的空间,让内部的子元素不会影响到外部的元素

#触发条件
可以通过如下的设置来触发(产生)一个BFC:

根元素,即 HTML 元素
浮动元素:float 值为 left、right
overflow 值不为 visible,为 auto、scroll、hidden
display 的值为 inline-block、inltable-cell、table-caption、table、inline-table、flex、inline-flex、grid、inline-grid
position 的值为 absolute 或 fixed

防止 margin 重叠(塌陷)
清除内部浮动
自适应多栏布局\

  1. CSS3 新特性
    border-radius:圆角边框

    box-shadow:盒子阴影

    background-size:背景图片大小

    transition:过渡

    transform:转换(位移 旋转 缩放)

    animation:动画

    linear-gradient:线性渐变

    box-sizing:css3 盒子模型

    @container (min-width: 380px) {} // 容器查询

    scroll-snap-type: x mandatory; //滚动捕捉

    object-view-box: inset(10% 50% 35% 5%); // 属性为图像带来了 SVG 的 viewBox 属性的功能。它允许您使用单行 CSS 平移、缩放和裁剪图像。
    @scroll-timeline at-rule,直译过来就是滚动时间线。

    @scroll-timeline 能够设定一个动画的开始和结束由滚动容器内的滚动进度决定,而不是由时间决定。

    46.
    服务器接收到请求,是否需要检查缓存?
    检查什么字段?
    什么样的缓存需要服务器端检查?
    强制缓存和协商缓存的顺序?
    设置max-age:0跟浏览器缓不缓存有关系吗?
    s-max-age的作用?
    浏览器如何检查比较缓存是否过期?这些字段的优先级是怎么样的?
    Last-Modified和Etag有什么区别?
    Etag这个字符串是怎么生成的?
    什么是from disk cache和from memory cache?什么时候触发?

    什么是启发式缓存?在什么条件下触发?

  2. 堆 栈
    基本数据类型由于占据的空间大小固定且较小,会被存储在栈当中,也就是变量访问的位置

    引用数据类型存储在堆当中,变量访问的其实是一个指针,它指向存储对象的内存地址

    48.
    基本数据类型:String、Number、Boolean、Null、Undefined、Symbol、BigInt

    引用数据类型:Object【Object是个大类,function函数、array数组、date日期...等都归属于Object】

    49.双飞翼布局和圣杯布局


50.margin-left 和left 区别

left的使用要求该元素必须有除static之外的定位。margin-left的使用不要求元素的定位。
left指令要生效,必须其有position:relative或者position:absolute的定位才能执行;margin-left则不需要。
left属性是配合定位使用的,如果没有设置定位,left属性就没有作用。left属性设置的是当前元素参照相对元素的左侧距离。
margin-left值是元素自身左侧有外间距,导致元素占据空间变大。 

51.前端数据埋点怎么实现


52.http 状态码

    1xx : 服务器收到请求, 请求尚未完成
    2xx : 成功完成
    3xx : 重定向状态码,请求需要附加处理才能完成
    4xx : 客服端错误状态码,服务器无法处理该请求
    5xx : 服务端错误状态码,服务器处理该请求出错
    
    
    301 -  永久重定向,表示请求的资源分配了新的url,以后应使用新url
    302 -  临时重定向,请求的资源临时分配了新的url(response中location所指的地址),本次请求暂时使用新url
    304 -  自从上次请求过后,网页未被修改过。客户端发送请求,有缓存则返回304,客户端使用缓存资源
    403 - Forbidden(禁止访问),服务器拒绝请求
    404 - 请求的资源(网页等)不存在
    500 - 服务器内部错误
    502 - Bad Gateway(坏的网关),一般是网关服务器请求后端服务时,后端服务没有按照http协议正确返回结果
    503 - Service Unavailable(服务当前不可用),可能因为超载或停机维护。
    504 - Gateway Timeout(网关超时),一般是网关服务器请求后端服务时,后端服务没有在特定的时间内完成服务。

53.浏览器在处理下面的 css 的时候,会使用 gpu 渲染:

        transform
        opacity
        filter
        will-change

54.浏览器五大进程

    
    1.浏览器的主进程
    2.GPU 进程:最多一个,用于3D绘制等
    3.浏览器渲染进程(即通常所说的浏览器内核)(Renderer进程,内部是多线程的):主要作用为页面渲染,脚本执行,事件处理等
        1> GUI 渲染线程:下载HTML,深度遍历dom,解析后生成dom树,下载css代码,解析生成cssom树,合并生成render 树,
                        计算每个元素的大小和位置等布局信息,进行layout(回流),
                        赋予颜色等影响元素的外观,风格的进行repaint或redraw(重绘)
                        在谷歌浏览器中叫 Layout,火狐中叫reflow
        2> JS 引擎线程: 也称为JS内核,负责解析执行Javascript脚本程序的主线程(例如V8引擎)。
        3> 事件处理线程: 归属于浏览器内核进程,不受JS引擎线程控制。主要用于控制事件(例如鼠标,键盘等事件),当该事件被触发时候,事件触发线程就会把该事件的处理函数推进事件队列,等待JS引擎线程执行。
        4> 定时器触发线程:主要控制计时器setInterval和延时器setTimeout,用于定时器的计时,计时完毕,满足定时器的触发条件,则将定时器的处理函数推进事件队列中,等待JS引擎线程执行。
        5> HTTP请求线程:通过XMLHttpRequest连接后,通过浏览器新开的一个线程,监控readyState状态变更时,如果设置了该状态的回调函数,则将该状态的处理函数推进事件队列中,等待JS引擎线程执行。
        GUI渲染线程和JS 引擎线程互斥
        默认情况下,Chrome 会为每个 Tab 标签创建一个渲染进程。
        但是我们也能看到有几个标签页共用一个进程,这其实是浏览器的优化机制,将某些同域名下的进程合并为一了
    4.网络进程。
    5.插件进程:每种类型的插件对应一个进程,仅当使用该插件时才创建
    6.1个音频(Audio)进程
    7.storage进程

55.CSS不会阻塞JS文件的下载,但会阻塞JS执行

浏览器在渲染页面的时候,如果JS在此期间同步操作样式或者获取样式,会导致页面渲染混乱,所以需要等待CSS执行完才能执行JS
JS文件与CSS文件下载是并行的,CSS文件会在后面的JS文件执行前先加载执行完毕,所以CSS会阻塞后面JS的执行
CSS不会阻塞DOM的解析,但会阻塞DOM的渲染
浏览器在生成DOM树和CSSOM树通常是并行构建的,所以CSS不会阻塞DOM的解析
浏览器在渲染等待DOM树和CSSOM树构建完成生成render树才开始渲染,所以CSS加载会阻塞DOM的渲染
 JS执行的时候渲染引擎就会挂起,所以会阻塞页面的渲染,根本原因:GUI 渲染线程与 Javascript 引擎为互斥
 

56.DOMContentLoaded与load的区别

 DOMContentLoaded:当DOM解析完成后触发,不包括JS,CSS,图片等静态资源

load:当HTML,CSS,JS,图片等所有资源加载完成后触发

由此可见,DOMContentLoaded 事件提前于 load 事件触发

57.标签不受同源策略的限制,所有可能会有安全问题




58.如何解决跨域

    JSONP 本质上是利用了 script 标签不受跨域限制的特性
    nodejs 服务代理  webpack.config.js  proxyTable
    nginx 代理转发  proxy_pass 
    服务器配置响应头 cors

59.移动端的自适应布局如何实现

px是跟逻辑像素挂钩的,而逻辑像素反映的是同样观看距离设备的屏幕尺寸。
既然手机和平板是同样观看距离的设备,那么,可以简单理解为,逻辑像素就等同于物理尺寸


1.使用 HTML5中Viewport,利用Viewport功能,可以把页面按照屏幕尺寸缩放,可以使页面自适应。
2.media 查询
3.flex
4.vh vw

5.rem
6.dpr 设备像素比
7.JavaScript的matchmedia()方法
8.栅格系统(Grid System):可以将页面分成等宽的列,每一列的宽度可以根据屏幕尺寸和设备方向自动调整。
使用栅格系统可以快速搭建响应式网站,同时保持页面的结构和布局。
9.文字流式,控件弹性,图片等比缩放 rem+vw+媒体查询
DPR 设备物理像素和设备独立像素比,即,是指在理想布局宽度,使用多少个物理像素来渲染一个设备独立像素。
js中通过window.devicePixelRatio获取,css中通过-webkit-device-pixel-ratio,-webkit-min-device-pixel-ratio,
-webkit-max-device-pixel-ratio进行媒体查询
Redmi Note 12 Turbo的屏幕参数显示,其屏幕尺寸为6.67英寸,分辨率为2400x1080px,这表明其设备像素比(devicePixelRatio)为2.0。
设备像素比是指物理像素与独立像素的比例,对于Retina显示屏等高分辨率屏幕,这个比例通常大于1,意味着屏幕上的物理像素点比显示的一个独立像素要多,
从而提供了更清晰的显示效果。Redmi Note 12 Turbo的devicePixelRatio为2.0,意味着它的显示效果相对较为清晰,能够提供较好的视觉体验‌
屏幕物理像素640像素,独立像素还是320像素,因此,window.devicePixelRatio等于2.
‌canvas.width‌和‌canvas.style.width‌在HTML5的元素中有不同的作用和意义。

‌canvas.width‌:这个属性决定了canvas内部的像素数量。换句话说,它定义了画布的尺寸,即画布上有多少个像素点。
如果你想要一个特定分辨率的画布,比如2048x2048像素,那么你需要将canvas的html width和height属性设置为2048,
以确保画布内部有足够的像素来支持这个分辨率。这个属性对于需要高清晰度的绘图非常重要,因为它直接影响到画布的像素密度和图像质量‌。

‌canvas.style.width‌:这个属性控制的是canvas在浏览器中的视觉表现大小,即它的样式宽度。它并不直接影响画布内部的像素数量,
而是用来调整画布在浏览器窗口中的显示尺寸。例如,如果你将canvas的style.width和style.height设置为较小的值,
比如800x800,而内部的像素数量保持不变(例如2048x2048),那么在浏览器中显示的画布将会缩小,但画布上的每个像素仍然保持其原始的大小和清晰度。
这种差异在处理画布的缩放、布局以及保持图像清晰度时尤为重要‌。

总结来说,‌canvas.width‌定义了画布内部的像素数量,是保证图像清晰度的关键;而‌canvas.style.width‌则决定了画布在浏览器中的显示大小,用于调整画布的视觉表现。两者在HTML5 canvas中使用时需要仔细考虑,以确保画布既能满足内部像素需求,又能适应不同的浏览器窗口尺寸‌
在移动端,devicePixelRatio指的是window.devicePixelRatio。
移动端设备分为非视网膜屏幕和视网膜屏幕。
为说明二者区别,举个例子:
非视网膜屏幕是指,屏幕可视区域宽度是320像素,就只能显示320像素的内容。
视网膜屏幕是指,屏幕可视区域宽度是320像素,却能够显示640像素、960像素的内容。
其中,屏幕可视区宽度叫设备独立像素,device independent pixels,简称dip或dp。屏幕能够显示的显示的实际像素数叫做物理像素。
像素比window.devicePixelRatio=物理像素/设备独立像素(dips)
 
vmin:表示选择视窗最小的那一个
vmax:选择视窗最大的那一个;

60.JS内存泄漏有哪几种

1.dom remove时,还存在引用
2.不规范的使用闭包
3.全局变量,意外的挂在到了window上
4.DOM中的addEventLisner 函数及派生的事件监听, 比如Jquery 中的on 函数, vue 组件实例的 $on 函数,
要及时removeEventLisner,off,$off ,clearTimeout

  1. css 新特性,冷门属性

    text-rendering: optimizelegibility

    optimizeSpeed 优先考虑渲染速度,禁用字距和连写
    optimizeLegibility 优先考虑易读性,清晰度,启用字距和连写.

    font-feature-settings 属性允许控制 OpenType 字体中的高级印刷特性

  2. 聊聊前端安全
    XSS(Cross Site Scripting)跨站脚本攻击
    XSS 如何防御防御 1。转义 HTML,对于输入的 HTML 代码,防御的方式是把输入的 HTML 代码转义,

                    比如把< script > 转义成 <script>
                  2。 使用内容安全策略(CSP)

    63.

    .header .title span { color: red; }
    浏览器会从右往左(从下向上-树形)解析CSS选择器,减少遍历失败回溯的次数

    先匹配 span 元素,然后向上寻找 .title 和 .header 的节点,直到根元素 html 结束

    64.如何理解JS 的函数,prototype, porto
    函数(Function也是函数)是new Function的结果,所以函数可以作为实例对象,
    其构造函数是Function(),原型对象是Function.prototype
    对象(函数也是对象)是new Object的结果,所以对象可以作为实例对象,
    其构造函数是Object(),原型对象是Object.prototype
    function Foo () {}
    foo = new Foo ()

Foo.prototype === foo.__porto__ // foo = new Foo()
Foo.constructor --> ƒ Function() { [native code]
Foo.constructor === Function
Foo.constructor.prototype === Foo.__proto__
Function.prototype === Function.__proto__
Function.prototype === Foo.__proto__ // Foo = new Function()
Function.prototype === Object.__proto__// Object = new Function()
Function.prototype.__proto__ === Object.prototype
Foo.prototype.__proto__ === Object.prototype
Object.__proto__.__proto__ === Object.prototype
Function.__proto__ === Function.prototype
Object.prototype.__proto__ === null

Object.__proto__ === Function.prototype

Function.__proto__ === Function.prototype

Foo.__proto__ === Function.prototype

65.CSS 选择器及其优先级

    !important > 行内 > id > class/属性选择 > 伪元素/标签
    

66.虚拟dom和ast的区别:

 template --> 抽象语法树 --> render(h) --> 虚拟DOM-->UI
虚拟dom和ast即抽象语法树,都涉及到了页面渲染,两者都是使用对象来进行抽象表示,
但是虚拟dom是将真实dom以对象的方式进行抽象表示,而ast则是对语法结构的抽象表示。
抽象语法树的终点是渲染函数(h函数)。

渲染函数(h函数),它既是AST的产物,也是vnode(虚拟节点)的起源
VNode的本质是一个JavaScript的对象;

67.

1、模板编译的流程,主要分为解析器 优化器 代码生成器

2、解析器主要原理:一段一段的截取html字符串,根据截取的字符串类型触发不同的钩子函数,直至模板字符串截取完毕,最终创建出AST。

3、优化器:主要是标记ast的静态节点和静态子节点。

4、代码生成器:根据优化后的ast生成代码字符串,然后交给render函数,执行生成vnode。
vdom就是基于vnode进行diff的。

68.
document.documentElement.scrollTop 页面滚动上去的高度

document.body.clientHeight=document.body.scrollHeight(整个页面的高度)-document.documentElement.scrollTop
document.body.offsetHeight
document.documentElement.clientHeight

document.body指的是html节点中的body节点
document.documentElement指的是根节点,即html节点
offsetHeight = clientHeight+边框(border)
clientHeight:包含内容和内边距(padding),不包含边框(border)

offsetHeight = 内容高度 + padding + border
clientHeight = 内容高度 + padding
scrollHeight = 内容实际尺寸 + padding

window.screenLeft 返回浏览器窗口相对于屏幕的X坐标,浏览器向右移动,screenLeft增加
window.screenTop 返回浏览器窗口相对于屏幕的Y坐标,浏览器向下移动,screenTop增加

window.screen.height 屏幕分辨率的高 768
window.screen.width 屏幕分辨率的宽 1366
window.screen.availHeight 屏幕可用工作区高度(728)= window.screen.height - 任务栏的高度(40)
window.screen.availWidth 屏幕可用工作区宽度 1366
document.body.clientWidth 网页可见区域宽,不包括边框
document.body.clientHeight 网页可见区域高,不包括边框
document.body.offsetWidth 网页可见区域宽,包括边框和滚动条的宽
document.body.offsetHeight 网页可见区域高,包括边框宽
document.body.scrollWidth 网页正文全文宽
document.body.scrollHeigh 网页正文全文高

box-sizing:
content-box:对象的实际宽度等于设置的width值和border、padding之和,设置的width值仅是content值(标准盒模型)
border-box:对象的实际宽度就等于设置的width值,已经包含了border和padding的值(ie盒模型)


  1. WebKitCSSMatrix SVGMatrix DOMMatrix
    WebKitCSSMatrix === DOMMatrix
    WebKitCSSMatrix and SVGMatrix are aliases to DOMMatrix.

70.allSettled()与all()的区别

​如果其中一个 promise 失败了​​​,则 ​​Promise.all​​​ 整体将会失败,其他执行成功的Promise的消息都丢失了
拿到的是resolve的数据
​​Promise.allSettled​​将永远不会失败,一旦数组中的所有 Promises 被完成或失败,它就会完成。
如:{ status: 'fulfilled', value: value }或 {status: 'rejected', reason: reason}
Promise.allSettled(promises)可以并行地运行 promise,

并将状态(fulfilled 或reject)收集到一个聚合数组中

71.函数的创建

把函数的代码以字符串的形式存储在堆内存中(函数再不执行的情况下,只是存储在堆内存中的字符串)

将函数堆的地址,放在栈中供变量调用(函数名)

72.Qwik
Qwik的工作原理就是在服务端序列化 HTML 模版,从而在客户端延迟创建事件处理程序,
这也是它为什么非常快速的原因。
常规水合过程:获取html => 下载JS文件,=> 执行JS代码 => 绑定事件=>结束
Qwik过程:获取html =>结束
qwik 的核心思路还是通过更加细粒的代码控制配合惰性加载事件处理程序以及事件委托来缩短首屏 TTI。

省略了传统 SSR 下首屏需要加载庞大的 JS 进行 hydration 的过程

73.var和let声明变量时的一些区别

var是函数作用域,而let是块作用域
1、如果在全局作用域中用var声明变量,此变量会默认成为window的一个属性,
let声明的变量则不会添加到window对象中。

2、在es6之前,是没有块级作用域,所谓块级作用域,就是用{}包含的区域,
我们常用的有for,while,if等。但是在块级作用域中用let声明变量,
那么此变量就有了块级作用域,就必须只有在此块级作用域才能访问此变量。

3、var声明的变量有变量提升特性,let声明则没有这个特性。 

4、var可以允许重复声明相同的变量,后者会覆盖前者,let则不能重复声明相同的变量。

74.影响回流、重绘的 CSS 属性有哪些

1. 添加、删除元素(回流+重绘)

2. 隐藏元素,display:none(回流+重绘),visibility:hidden(只重绘,不回流)

3. 移动元素,比如改变top,left(jquery的animate方法就是,改变top,left不一定会影响回流),或者移动元素到另外1个父元素中。(重绘+回流)

4. 对style的操作(对不同的属性操作,影响不一样)

5. 还有一种是用户的操作,比如改变浏览器大小,改变浏览器的字体大小等(回流+重绘)

75 pnpm
hard link 机制
那么 pnpm 是怎么做到如此大的提升的呢?是因为计算机里面一个叫做 Hard link 的机制,
hard link 使得用户可以通过不同的路径引用方式去找到某个文件。
pnpm 会在全局的 store 目录里存储项目 node_modules 文件的 hard links 。
如果是 npm 或 yarn,那么这个依赖在多个项目中使用,在每次安装的时候都会被重新下载一次。


76.详解package-lock.json的作用
package.json用于告诉npm项目运行需要哪些包,
但包的最终安装的版本不能够只依靠这个文件进行识别, 还需以package-lock.json为准
package.json中修改版本号会影响package-lock.json,
并且package.json比package.lock.json的优先级高,
如果package.json中less版本为​​^1.0.0​​ , package-lock.json中less版本为​​2.1.2​​,

则最终安装的less版本为1.7.5​​, package-lock.json中less即其依赖的包将被从​​2.1.2​​退回到​​1.7.5`的状态

77.npm install 之后发生了什么
检查有没有lock.json文件,如果有就比较package-lock.json文件和package.json是否兼容,
如果兼容则根据package-lock.json文件安装,如果不兼容则根据根据package.json安装,并更新package-lock.json
如果没有lock.json文件,则读取package.json,获取包信息,构建依赖树,并扁平化,
然后检查缓存,没有缓存则下载依赖包,添加到缓存,并解压到node_modules,生成lock.json文件
如果有缓存,则直接解压到 node_modules,同时生成lock.json文件

78.vue diff算法

VUE3 diff 算法增加了静态标记,如果是静态节点则不参与diff计算

  1. Range(用于断点续传)
    Range:bytes=0-5 指定第一个字节的位置和最后一个字节的位置。用于告诉服务器自己想取对象的哪部分。
    79.
    overflow: scroll 在移动端滚动不流畅
    只需要配置 -webkit-overflow-scrolling 为 touch 即可

-webkit-overflow-scrolling: touch;
禁止 iOS 识别电话

h5 输入框被键盘遮挡问题
if (/Android [4-6]/.test(navigator.appVersion)) {
window.addEventListener("resize", function () {

if (document.activeElement.tagName == "INPUT" || document.activeElement.tagName == "TEXTAREA") {
  window.setTimeout(function () {
    document.activeElement.scrollIntoViewIfNeeded();
  }, 0);
}

});
}

80.如何解决重复的请求
我们常见的业务场景有,用户频繁点击数据提交,用户频繁的切换数据量大的表格,
在网络较差的环境下,会出现一些异常的情况,当然,各类UI库提供的loading状态可以帮我们解决以上烦恼,
以及可以通过防抖解决部分问题,但是我们今天从另一个方面,使用axios的cancelToken取消上次重复的请求

81.为什么有了last-modified 还要有 etag
HTTP协议中引入ETag的目的是为了解决Last-Modified无法解决的一些问题。‌
Last-Modified的局限性:‌
某些服务器可能无法精确获取文件的最后修改时间,‌导致无法准确判断文件是否更新。‌
对于频繁修改的文件(‌如每秒内多次修改)‌,‌Last-Modified只能精确到秒,‌无法捕捉到秒以下的修改。‌
即使文件的最后修改时间改变了,‌文件的内容可能并未发生变化,‌但Last-Modified无法区分这种情况,‌可能导致客户端错误地认为文件已更新。‌
ETag的作用:‌
ETag是一个服务器自动生成的资源的唯一标识符,‌每次资源变动都会生成新的ETag值,‌因此能够更准确地控制缓存。‌
与Last-Modified相比,‌ETag能够更细致地处理文件的变化,‌包括那些内容未变但修改时间改变的情况。‌
ETag和If-None-Match的使用,‌允许服务器和客户端之间进行更精细的缓存协商,‌进一步提高网页加载性能和用户体验。‌
综上所述,‌ETag的引入是为了弥补Last-Modified在处理某些特定情况下的不足,‌提供了一种更精确、‌更灵活的缓存控制机制

82.BFF架构
BFF是一种Web架构,全名为Backends For Frontends,即为服务于前端的后端。
这个词来源于Sam Newman的一篇文章:Pattern: Backends For Frontends[1]。
BFF一般指的是在前端与后端之间加增加一个中间层。为什么要在前端和后端之间增加一个BFF层呢?

83.text-transform:uppercase;

84.媒体查询

@media (max-width: 480px) {

/* css here */

}





if (matchMedia('(max-width: 480px)').matches) {

// js here

}

@media (any-hover: hover) {
/ 支持悬停 /
}
@media (any-hover: none) {
/ 不支持悬停 /
}
@media (hover: hover) {
/ 主要输入装置支持悬停 /
}
@media (hover: none) {
/ 主要输入装置不支持悬停 /
}
@media (pointer: none) {
/* none:主要输入机制不包括输入设备
coarse:主要输入机制包括精度有限的输入设备,例如触摸屏上的手指
fine:主要输入机制包括精确的输入设备,例如鼠标
*/
}

@media not all and (hover: hover) {
abbr::after {

content: ' (' attr(title) ')';

}
}

/ 在你的代码的顶层 /
@media screen and (min-width: 900px) {
article {

padding: 1rem 3rem;

}
}

/ 嵌套至其他的 at 条件规则中 /
@supports (display: flex) {
@media screen and (min-width: 900px) {

article {
  display: flex;
}

}
}

@media print {
body {

font-size: 10pt;

}
}

@media screen {
body {

font-size: 13px;

}
}

@media screen, print {
body {

line-height: 1.2;

}
}

@media only screen and (min-width: 320px) and (max-width: 480px) and (resolution: 150dpi) {
body {

line-height: 1.4;

}
}

@media (height > 600px) {
body {

line-height: 1.4;

}
}

@media (400px <= width <= 700px) {
body {

line-height: 1.4;

}
}

85.max_old_space_size
max_old_space_size参数用于指定V8引擎的 老生代内存的最大大小。通过增加max_old_space_size参数的值,我们可以提供更多的内存给V8引擎,从而提高应用程序的性能和稳定性。

node的内存上限都有一定限制;用户可以通过node环境的变量NODE_OPTIONS指定内存,提高运行性能
set NODE_OPTIONS=%NODE_OPTIONS%;--max-old-space-size=15000

"serve": "vue-cli-service serve --max-old-space-size=12096",

node --max_old_space_size=15000 --inline --config webpack.dev.js

86.vue-cli-service webpack-dev-server区别
vue-cli-service 是 Vue CLI 创建的项目使用的命令行工具,它封装了一系列工具函数,包括启动开发服务器的webpack-dev-server。

webpack-dev-server是一个轻量级的服务器,它使用webpack的开发中间件堆栈来提供web包内容。这个服务器也提供了实时重新加载(HMR)的能力,可以在开发过程中自动更新页面。

在 Vue CLI 创建的项目中,你可以通过以下命令启动开发服务器:
vue-cli-service serve
这个命令会启动 webpack-dev-server 并且默认在 localhost:8080 上监听。

如果你想要直接使用 webpack-dev-server,你可以全局安装它:
npm install --global webpack-dev-server
然后在你的项目目录中运行:webpack-dev-server --open
这将会启动 webpack-dev-server 并且打开你的默认浏览器到本地服务器地址。

在 Vue CLI 项目中,vue-cli-service 是用来启动和控制 webpack-dev-server 的工具,它提供了一个简洁的接口,用户不需要直接和 webpack-dev-server 的各种参数和复杂配置打交道。

vue-cli-service是把webpack-dev-server包装了一层,所以,webpack-dev-server的配置方法都可以拿过来用

87.Vue.config.js需要多入口

Vue.config.js需要多入口的主要原因包括分离业务模块、‌提高代码复用性、‌提升页面加载速度、‌方便扩展和维护、‌简化开发流程,‌以及减小文件体积和实现动态加载模块。‌

分离业务模块:‌多入口架构允许根据不同的业务模块将代码分开,‌每个入口可以单独管理和维护,‌减少代码的耦合性,‌提高代码的可维护性。‌
提高代码复用性:‌通过多入口,‌可以将通用的代码抽离出来作为共享模块,‌不同的入口可以共享这些模块,‌避免了代码冗余,‌提高了代码的复用性。‌
提升页面加载速度:‌多入口可以将入口文件进行拆分,‌只加载当前入口所需的文件,‌减少了不必要的加载和解析,‌提升了页面加载速度,‌提高了用户体验。‌
方便扩展和维护:‌多入口可以根据不同的需求方便地新增或删除入口,‌只需要修改配置文件即可,‌不影响其他模块的功能,‌方便后续的扩展和维护工作。‌
简化开发流程:‌多入口可以根据不同的需求定制不同的构建流程,‌例如不同的入口可以使用不同的Webpack配置,‌方便开发人员根据需求进行定制化开发,‌减少了开发流程的复杂性。‌
减小文件体积:‌通过多入口可以按需加载不同的模块,‌减小最终打包出来的文件体积,‌提升应用的性能。‌
实现动态加载模块:‌多入口可以动态加载不同的模块,‌根据用户需求实现按需加载,‌提高页面加载速度和用户体验。‌
这些优势使得多入口架构成为处理复杂Vue项目时的有效策略,‌特别是在大型项目中,‌通过将应用分为多个独立的模块和入口点,‌可以提高开发效率、‌代码可维护性以及用户体验

88.window.customElements.define

89.Events
UIEvents UI 事件
MouseEvents 鼠标事件
MutationEvents DOM 变动事件
HTMLEvents HTML 事件

const evt1 = document.createEvent("MouseEvents");
evt1.initEvent("click", false, false);
window.addEventListener("click", (e) => {
console.log("click");
});
window.dispatchEvent(evt1);

90,MessageEvent
EventSource.onmessage
WebSocket 接口的 onmessage
Window.postMessage() 和 Window.onmessage
MessageChannel MessagePort.postMessage() 和MessagePort.onmessage
Worker Worker.postMessage(), Worker.onmessage, ServiceWorkerGlobalScope.onmessage
Broadcastchannel Broadcastchannel.postMessage()) 和 BroadcastChannel.onmessage

91.冷门CSS

box-decoration-break: clone; CSS布局中总会存在元素box盒子断开的情况(page/column/region/line),box-decoration-break可以决定断开时候的渲染表现。

vector-effect: non-scaling-stroke; SVG stroke描边的默认特性,描边会跟随尺寸缩放,我们希望图片无论尺寸多大,描边的大小都是设定的宽度值

video::backdrop dialog::backdrop img::backdrop; 给全屏时候视频背景加个透明

-webkit-print-color-adjust和color-adjust属性值和作用是一样的。 灰色条纹就能正常打印。

scroll-snap-type: x mandatory; 图片左边缘会和滚动容器的左边缘进行吸附

92.package.json
"vue-template-compiler":"vue 组件template 的模板编译器",
"Autoprefixer":"解析CSS文件并且添加浏览器前缀到CSS规则里",
"babel-preset-env":"babel转码神器,根据你支持的环境自动决定适合你的Babel插件,babel-preset-env可以基于特定环境引入需要的polyfill",
"babel-preset-stage-2":"stage-x(实验阶段presets)",
"babel-loader":"用来处理ES6语法,将其编译为浏览器可以执行的js语法",
"file-loader":"指示webpack将所需对象作为文件发出并返回其公共URL",
"url-loader":"Loads files as base64 encoded URL;功能类似于file-loader,但是在文件大小(单位 byte)低于指定的限制时,可以返回一个 DataURL。",
"compression-webpack-plugin":"提供带 Content-Encoding 编码的压缩版的资源"

93.outline border区别
‌outline和border的主要区别在于它们对网页布局的影响、应用范围、以及它们的默认行为。‌
‌对网页布局的影响‌:
‌outline‌不占用网页布局空间,它位于边框旁边但在边框之外,与box-shadow和margin重叠,但不影响元素的尺寸。outline是一种动态样式,只有在元素获得焦点或者被激活时呈现效果,突出元素的作用。
‌border‌是盒模型的一部分,它位于padding和margin之间,它的宽度将影响计算出的元素尺寸。border可以应用于几乎所有有形的html元素。
‌应用范围‌:
‌outline‌主要是针对链接、表单控件和ImageMap等元素设计,它的效果随元素的focus自动出现,由blur自动消失,这是浏览器的默认行为,无需JavaScript配合CSS来控制。
‌border‌可应用于几乎所有有形的html元素。
‌默认行为‌:
‌outline‌的轮廓线四边都必须是一样的,且外轮廓线必须闭合,不可以只设置一边。outline创建的轮廓线可以向内扩展(将outline-offset设置为负值),而border只能向内。
‌border‌的宽度、样式和颜色可以直接控制元素的尺寸和外观,而outline则更多地用于视觉上的强调,不直接影响布局。
综上所述,选择使用outline还是border取决于设计需求和布局考虑。如果需要不影响元素尺寸的动态视觉效果,outline是更好的选择;如果需要定义元素的固定边界并影响布局,则应使用border‌

94.undefined null '[object Object]'
(!(~+[])+{})--[~+""][~+[]] + ~~!+[]]+({}+[])[[~!+[]]~+[]]

var str = '(!(~+[])+{})--[~+""][~+[]] + ~~!+[]]+({}+[])[[~!+[]]~+[]]'
var bar =new Function ('', 'return ' + str )

bar()

[~!+[]]*~+[] => 2
({}+[]) => '[object Object]'
({}+[])[[~!+[]]*~+[]] => b
(!(~+[])+{}) => 'false[object Object]'
--~+""]*[~+[]] + ~~!+[] => 3

95.
og:title 标题
og:type 类型 常用值:article book movie
og:image 略缩图地址
og:url 页面地址
og:description 页面的简单描述
og:site_name 页面所在网站名
og:videosrc 视频或者Flash地址
og:audiosrc 音频地址

96.CanvasKit
CanvasKit 是基于 Skia 图形库的 js 版本,它使用 WebAssembly (WASM) 技术将 Skia 的图形 API 导出到 Web 平台.
canvaskit 是 Skia 的 js 版本

97.tools

通用去重(适用于简单类型和可哈希对象)
function removeDuplicates(arr) {
return Array.from(new Map(arr.map(item => [item, item])).values());
}

//针对对象数组的去重(根据对象的某个或多个属性去重)
function removeDuplicatesByProperty(arr, property) {
const map = new Map();
return arr.filter(item => {

const key = item[property];
if (!map.has(key)) {
  map.set(key, true);
  return true;
}
return false;

});
}

let objectArrayWithDuplicates = [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' },
{ id: 2, name: 'Charlie' },
{ id: 3, name: 'Dave' },
];

98.Map、Set、WeakMap和WeakSet的区别,他们是四个不同的数据结构,它们都有不同的特点和用途
Map:Map是一种键值对的集合,其中的键和值可以是任意类型的。与对象类似,它们可以通过键来访问值。不同之处在于,Map可以使用任意类型作为键,而对象只能使用字符串或Symbol类型作为键。Map还提供了许多有用的方法,例如size属性来获取键值对的数量,以及forEach()方法来遍历集合。
Set:Set是一种值的集合,其中每个值都是唯一的。与数组不同,它们没有重复的元素,并且没有特定的顺序。Set提供了许多有用的方法,例如add()方法来添加新的值,delete()方法来删除值,has()方法来检查是否存在某个值,以及size属性来获取集合的大小。
WeakMap:WeakMap与Map类似,也是一种键值对的集合。然而,它们的键必须是对象,而值可以是任何类型。与Map不同的是,WeakMap的键是弱引用,也就是说,如果键对象没有被其他地方引用,则它们可以被垃圾回收。这使得WeakMap非常适合缓存数据,因为当对象不再需要时,它们可以自动从WeakMap中删除,从而释放内存。
WeakSet:WeakSet是一种值的集合,其中每个值都是唯一的,并且没有特定的顺序。与Set不同的是,它们的值也是弱引用的,因此可以被垃圾回收。WeakSet通常用于存储对象的引用,以避免内存泄漏。
99.prefers-color-scheme css 媒体特性: 用于检测用户是否有将系统的主题色设置为亮色或者暗色。
:root {

--background-color: yellow;

}
body {
background-color: var(--background-color);
}
@media (prefers-color-scheme: light) {
:root {

--background-color: green;

}
}
@media (prefers-color-scheme: dark) {
:root {

--background-color: blue;

}
}
// 检查用户是否偏好深色主题 const darkModeMediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
// 监听变化 darkModeMediaQuery.addEventListener('change', () => {
if (darkModeMediaQuery.matches) { console.log('主题已切换:用户偏好深色主题');
// 在这里应用深色主题的样式或逻辑
} else { console.log('主题已切换:用户偏好浅色主题');
// 在这里应用浅色主题的样式或逻辑
} });
// 初始检查
if (darkModeMediaQuery.matches) {
console.log('初始状态:用户偏好深色主题');
} else { console.log('初始状态:用户偏好浅色主题'); }

  1. 如果闭包内 e 存储过之前生成的结果,那直接返回这个结果,否则执行入参t函数,且将结果存储到e
    function $(t) {

    var e = Object.create(null);
    return function (n) {

    var r = e[n];
    return r || (e[n] = t(n))

    }

}
var O = /-(\w)/g,

//S('-swfddd') => 'Swfddd'
S = $((function (t) {
    return t.replace(O, (function (t, e) {
        return e ? e.toUpperCase() : ""
    }))
})),  
//k('fdfspo3o') => 'Fdfspo3o'
k = $((function (t) {
    return t.charAt(0)
        .toUpperCase() + t.slice(1)
})),
 j = /\B([A-Z])/g,
 // E('FGGA') =>  'f-g-g-a'
E = $((function (t) {
    return t.replace(j, "-$1")
        .toLowerCase()
}))

  1. git 撤回已经push到远程仓库的代码

    git reset --hard HEAD^    
    
    git push origin zk0927 --force
    
    # 修改本地提交历史
    git rebase -i HEAD~3 # 这里的3是要修改的提交数,可以根据需要修改
    # 修改完毕后,强制推送到远程仓库
    git push origin zk0927 --force
    

# 或者使用 git reset 来重置本地分支
git reset --hard HEAD~1 # 这里的1是要回退的提交数,可以根据需要修改
# 重置完毕后,强制推送到远程仓库
git push origin zk0927 --force


工作区->暂存区->版本库->远程仓库
git status  # 查看缓冲区状态
git config --global user.name "Your Name"
git config user.name c_zhangke-035
git config --list
git checkout -     # 切换到上一个分支
git fsck 检查 Git 文件系统的完整性,并修复损坏的对象。
git add .  # 添加修改到缓存区
git checkout . # 切换分支是主要功能  ,也可撤销工作区中当前目录中的所有更改
git checkout . #  等价于 git restore .  可以还原工作目录中的文件,覆盖本地还没添加到缓存区的修改

git restore . # 将缓存区的内容,覆盖本地还没添加到缓存区的修改,缓存区的内容不变,即撤销所有未缓存的修改,代码恢复到缓存区的版本
git restore --staged . #不再跟踪缓存区的文件,不会覆盖最近的修改 只是撤销添加到缓冲区的记录,与工作区的内容没关系
git restore --staged file-to-restore   还原暂存区的文件,撤销添加到缓冲区的文件
git mv README  README.md  重命名文件或者目录
git config --global user.name "runoob"
git config --global user.email [email protected]
git branch --set-upstream-to=origin/master master

git branch -d mybranch    删除分支
git branch     列出所有分支    列出所有本地分支
git branch -r    # 列出所有远程分支
git branch -vv   如果你不确定当前分支的状态,可以使用以下命令 ,  这会显示所有分支及其关联的远程跟踪分支信息。
git branch -v    查看各个分支最后一次提交
git branch –-merged   查看哪些分支合并入当前分支
git branch –no-merged   查看哪些分支未合并入当前分支
git branch -d new-feature   如果不再需要新功能分支,可以将其删除
git branch -D dev            #强行删除分支  分支未合并
git stash list   查看堆栈中的 stash 列表
git stash show     查看,stash中存了哪些内容
git push origin --delete [branch-name] # 删除远程分支
git add filename    将修改过的文件添加到暂存区,以便进行下一步的提交操作:
git commit -m "Add new feature"   将暂存区的更改提交到本地仓库,并添加提交信息:
git pull origin main    在推送本地更改之前,最好从远程仓库拉取最新的更改,以避免冲突:
git push origin new-feature    将本地的提交推送到远程仓库:
git fetch origin     更新远程库到本地
git merge origin/mybranch    取远程分支合并到本地
git checkout -b master0823 origin/master0823
git checkout -b mybranch origin/mybranch   取远程分支并分化一个新分支

git push origin --delete new-feature    从远程仓库删除分支:

 git checkout master  ;  git merge mybranch    mybranch合并到master
合并分支:  1 git push origin new-feature
            2 git checkout main
            3 git pull origin main
            4 git merge new-feature

git checkout -b fix/5.17.3-anchor-replace
git add .
git commit -m "fix: anchor-replace"
git push --set-upstream origin fix/5.17.3-anchor-replace    --set-upstream选项会指定一个默认主机

工作区->暂存区->版本库->远程仓库

【未add,放弃本地工作区修改】 git restore .
【add后,未commit】git add example.txt 撤销用: git reset example.txt
【add后,未commit】git add example.txt 撤销用: git restore --staged . 撤销添加到缓冲区的文件
【commit后,未push】git commit -m 修改字段 撤销用:

     git reset --soft HEAD^   会撤销最后一次的commit,但是保留工作区和暂存区的内容,撤销commit
     git reset HEAD^          会撤销最近一次的commit,并保留工作区代码 ,并清空暂存区, 撤销commit add
     git reset --hard HEAD^   会撤销最后一次的commit,并且撤销工作区和暂存区的更改, 撤销commit add
     git commit 之后撤回  git reset commitid (提交的commitid 可用git log 查看)

【push后】

     git log   获取需要回退至的版本号,比如 85dee0d8b108c7450e0c820b2d72928f98d94f93
     git revert  85dee0d8b108c7450e0c820b2d72928f98d94f93
     git push origin master –force强制提交当前版本号,以达到撤销仓库远程版本号的目的。
     git push origin master --force-with-lease

【执行git revert后想放弃】如果你还没有推送到远程仓库,你可以通过git reset来重置到git revert之前的状态:

    git reset --hard HEAD~1   这将会把你的HEAD指针移到revert操作之前的提交。


    
    

【问题1】fatal: bad object refs/remotes/origin/master

解决办法:
    mv .git/refs/remotes/origin/master/tmp
    
    $ git gc
    然后重新选择远程分支

    $ git branch --set-upstream-to=origin/master master


102 autofocus 在移动版 Safari 上不工作

103 (function() {})"constructor"()

    (new Function('debugger'))()

下面三个结果相同
(function() {})"constructor"
(new Function('debugger'))
Function('debugger')
//调用 Function 时可以使用或不使用 new,两者都会创建一个新的 Function 实例
=》
ƒ anonymous() {
debugger
}

new Function('a', 'b', 'return a + b')
=》

ƒ anonymous(a,b) {
return a + b
}

(function() {})["constructor"] =》 ƒ Function() { [native code] }

[]["constructor"] =》 ƒ Array() { [native code] }

''["constructor"] =》ƒ String() { [native code] }

true["constructor"] =》ƒ Boolean() { [native code] }

通过以下方法,可以有效解决iOS平台上键盘弹起导致的布局问题,提升用户体验。
//解决ios键盘弹起问题

inputBlur() {
  setTimeout(() => {
    const scrollHeight =
      document.documentElement.scrollTop || document.body.scrollTop || 0;
    window.scrollTo(0, Math.max(scrollHeight - 1, 0));
  }, 100);
},

‌监听键盘弹出事件‌:在iOS中,可以通过监听 keyboardWillShow 事件来获取键盘弹出的信息。
在页面加载完成后注册这个事件,并在事件回调函数中处理键盘弹出的逻辑。例如:

window.addEventListener('keyboardWillShow', function(e) {

var keyboardHeight = e.keyboardHeight;
// 调整页面布局
input.style.bottom = keyboardHeight + 'px';

});
这样可以获取键盘的高度,并据此调整页面布局,避免输入框被键盘遮挡‌1。

‌使用Vue.js处理布局上移‌:在Vue应用中,可以通过监听resize事件来调整页面布局。例如:

mounted() {

window.addEventListener('resize', this.handleResize);

},
methods: {

handleResize() {
    this.isKeyboardVisible = window.innerHeight < 500;
    this.adjustLayout();
},
adjustLayout() {
    if (this.isKeyboardVisible) {
        document.body.style.transform = 'translateY(-200px)';
    } else {
        document.body.style.transform = 'translateY(0)';
    }
}

}
这种方法可以根据键盘的出现和消失来动态调整页面布局,确保用户体验‌。

‌处理输入框失焦事件‌:在输入框失焦时,可以通过监听 focusout 事件来调整页面滚动位置,确保页面恢复到初始状态。例如:

mounted() {

document.body.addEventListener('focusout', () => {
    window.scrollTo({ top: 0, left: 0, behavior: "smooth" });
});

},
methods: {

fixScroll() {
    if (navigator.userAgent.match(/iPhone/i)) {
        window.scrollTo(0, 0);
    }
}

}
这种方法可以确保在输入框失焦时,页面能够平滑地滚动到顶部‌。

该代码段用于处理微信中修改默认字体大小引起页面布局混乱的问题。
通过在页面加载后调用WeixinJSBridge接口,重置字体大小为初始值,并监听用户设置字体事件,保持页面样式稳定。
同时使用CSS属性-webkit-text-size-adjust确保文本缩放不影响页面比例。
适用场景,修改微信默认字体,导致页面变形,思路=> 页面加载完毕之后,重置字体大小

此模式通常在网络上使用。但这也有一些缺陷,使其在某些情况下不可靠。
幸运的是,Chrome开发者工具(Chrome DevTools)的Mathias Bynens 提出了一种不受这些缺点影响的创造性模式:

(function() {
if (typeof globalThis === 'object') return;
Object.defineProperty(Object.prototype, '__magic__', {

get: function() {
  return this;
},
configurable: true // This makes it possible to `delete` the getter later.

});
__magic__.globalThis = __magic__; // lolwat
delete Object.prototype.__magic__;
}());

// Your code can use globalThis now.

console.log(globalThis)

style="width: 0px; height: 0px; border-style: solid; border-width: 0px 50px 100px; border-color: transparent transparent rgb(233, 105, 0);">

loading:

udvr:y9vngqt3

4、启动cmd执行sqlite3 .svn/wc.db "select * from work_queue"

5、启动cmd执行sqlite3 .svn/wc.db "delete from work_queue"

https://fly63.com/php/ico/ 在线生成ICO图标

https://tool.lu/
https://convertio.co/zh/
https://www.open-open.com/lib/view/open1430832317648.html

https://wx.cpic.com.cn/sxwxclub/wx/menuByState?state=21070&lo...

canvas-raycaster

你可能感兴趣的:(前端笔记)