3.17

94 阅读6分钟

1. HTTP 缓存相关的响应头信息

  1. Cache-Control // 控制缓存
  2. Expire // 控制缓存
  3. ETag // 校验缓存用
  4. Last-Modified // 校验缓存用

2. 浏览器缓存相关标识符

与浏览器缓存的字段有如下几种:

  1. Cache-Control (指定缓存机制,覆盖其它设置)
  2. Expires (http1.0字段,指定缓存的过期时间, 到了HTTP/1.1,Expire已经被Cache-Control替代)
  3. Last-Modified (资源最后一次的修改时间)
  4. ETag (唯一标识请求资源的字符串)
  5. If-Modified-Since (缓存校验字段, 值为资源最后一次的修改时间, 即上次收到的Last-Modified值)
  6. If-None-Match (同上, 处理方式与之相反)

3. 箭头函数和普通函数的区别

🌼 箭头函数的特点:

  • 没有自己的 this,所以 this 从外部获取,继承外部的执行上下文中的 this

  • 没有 prototype 属性,没有原型和 super,所以箭头函数也不能作为构造函数,也不能使用 new

  • 通过 call()apply() 方法调用箭头函数时,只能传递参数,不能绑定 this,第一个参数会被忽略。

  • 不能使用 yield 关键字,因此箭头函数不能用作 Generator 函数。

image.png

4. v-for 遍历,能否用 key 做数组下标?

可以,但不推荐。

key 的作用主要是为了高效的更新 虚拟DOM,使用 v-for 更新已渲染的元素列表时,默认 就地复用 策略,列表数据修改的时候,会根据 key 值去判断某个值是否修改,如果修改,则重新渲染这一项,否则复用之前的元素。

如果我们使用了数组的下标来作为 key,而数据又恰好只在数组末尾新增元素的话,不会有影响;但是如果在数组中间插入新数据,就会使后面没有被修改的数据反复更新,就会很没效率。

所以我们要尽可能在使用 v-for 时使用 key 来给每个节点做一个唯一标识,Diff算法 就可以正确的识别此节点,在新增节点的同时复用原来的节点。

5. 为什么 vue2 不用 proxy?

vue2之前之所以不用 Proxy,是因为 Proxy 是 es6 提供的新特性,兼容性不好,最主要的是这个属性无法用 polyfill 来兼容。Polyfill 指的是用于实现浏览器并不支持的原生 API 的代码。

比如说 querySelectorAll 是很多现代浏览器都支持的原生 Web API, 但是有些古老的浏览器并不支持,那么假设有人写了一段代码来实现这个功能. 使这些浏览器也支持了这个功能,那么这就可以成为一个 Polyfill。

  • vue2 的数据双向绑定原理使用的是 es5 的数据劫持 object.defineProperty,如果读取数据就会触发 get,修改数据就会触发 set,达到数据和视图的响应和更新,但是因为 js 固有的特性,不能动态添加和删除属性,需要调用 $set$delete 这些方法来实现动态添加双向绑定属性。

  • vue3 的数据双向绑定使用的是 es6Proxy 配合 Reflect 实现的,他比起数据劫持可以监听到对象添加属性和删除属性。

proxy的优势 Proxy 与 Object.defineProperty 优劣对比

  • 响应式是惰性的。按需实现响应式,减少性能消耗。
  • 在 Vue2 中,对于一个深层属性嵌套的对象,要劫持它内部深层次的变化,就需要递归遍历这个对象,执行 Object.defineProperty 把每一层对象数据都变成响应式的,这无疑会有很大的性能消耗。

  • 在 Vue3 中,使用 Proxy API 并不能监听到对象内部深层次的属性变化,因此它的处理方式是在 getter 中去递归响应式,这样的好处是真正访问到的内部属性才会变成响应式,简单的可以说是按需实现响应式,减少性能消耗。

  • Proxy 有多达 13 种拦截方法,不限于 apply、ownKeys、deleteProperty、has 等等是 Object.defineProperty 不具备的

为什么要用 Proxy 替代 defineProperty ?

  1. defineProperty API 的局限性最大原因是它只能针对单例属性做监听。 Vue2.x中的响应式实现正是基于defineProperty中的descriptor,对 data 中的属性做了遍历 + 递归,为每个属性设置了 getter、setter。这也就是为什么 Vue 只能对 data 中预定义过的属性做出响应的原因。

  2. Proxy API的监听是针对一个对象的,那么对这个对象的所有操作会进入监听操作, 这就完全可以代理所有属性,将会带来很大的性能提升和更优的代码。 Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。

🌼 1. 什么是跨域访问,浏览器对哪些跨域访问是允许的,哪些是禁止的

(1)什么是跨域访问

跨域指的是浏览器不能执行其他网站的脚本,从一个域名的网页去请求另一个域名的资源时,协议、域名、端口任一不同,都是跨域。跨域是由浏览器的同源策略造成的,是浏览器对 JavaScript 施加的安全限制。

(2)浏览器对哪些跨域访问是允许的

src 的标签一般都是允许的,如 imgscript 标签,还有 iframelink 标签。

(3)哪些是禁止的

  1. Cookie、LocalStorage、IndexedDB 等存储性内容
  2. 操作DOM 节点
  3. Ajax请求发送后,结果被浏览器拦截了

(4)解决浏览器跨域限制的方法

  1. jsonp
  2. 代理服务器
  3. CORS 跨域资源共享
  4. 服务器 niginx 反向代理
  5. 后台语言处理
  6. websocket

🌼 2. localStorage 和 cookie 的区别

localstorage 和 cookie 都可以用来做本地存储,实现数据持久化。但它们的区别还是很多的,主要体现在以下几个方面:

1. 存储量不同。 cookie 的存储量在 4k 左右,而 localStorage 的存储量有 5M。

2. 有效时间不同。 cookie 的有效期可以自行设置,而 localstorage 可以一直生效。

3. 在向服务器请求时,cookie 会被携带,而 localstorage 不会。 同源的 cookie 信息会自动作为请求头的一部分发给服务器。而 localstorage 一般仅用作客户端的数据存储。

4. 存储类型。 cookie 存储的是字符串,而 localStorage 存储的是对象。

🌼 1. 编写形状类,编写一个子类正方形类,使可以计算周长和面积

        class Shape {
            constructor(length, width) {
                this.length = length
                this.width = width
            }
        }
        class Square extends Shape {
            constructor(length, width) {
                super(length, width)
            }
            area() {
                return this.length * this.length
            }
            circumference() {
                return this.length * 4
            }
        }

        var square1 = new Square(7)

        console.log('正方形的面积是' + square1.area());  // 正方形的面积是49
        console.log('正方形的周长是' + square1.circumference());  // 正方形的周长是28

🌼 2. 使用 Promise、async、await 实现红绿灯切换,并在控制台打印输出,红灯:30s,黄灯5s,绿灯20s

    <style>
        #light {
            /* background:red; */
            width: 50px;
            height: 50px;
            border-radius: 50%;
            border: 1px solid #000;
        }
    </style>
    
    <div id="light"></div>
    
    <script>
        function sleep(duration) {
            return new Promise(function (resolve, reject) {
                setTimeout(resolve, duration);
            })
        }

        async function changeLightColor(duration, color) {
            document.getElementById('light').style.background = color
            console.log('color', color)
            await sleep(duration)
        }
        
        async function act() {
            while (true) {
                await changeLightColor(3000, 'green');
                await changeLightColor(1000, 'yellow');
                await changeLightColor(2000, 'red');
            }
        }
        act()
    </script>