56、说一下 v-if 与 v-show 的区别
1、手段
- v-if 是动态的向 DOM 树内添加或者删除 DOM 元素
- v-show 是通过设置 DOM 元素的 display 样式属性控制显隐
2、编译过程
- v-if 切换有一个局部编译/卸载的过程,切换过程中合适地销毁和重建内部的事件监听和子组件
- v-show 只是简单的基于 css 切换
3、编译条件
- v-if 是惰性的,如果初始条件为假,则什么也不做。只有在条件第一次变为真时才开始局部编译
- v-show 是在任何条件下(首次条件是否为真)都被编译,然后被缓存,而且 DOM 元素保留
4、性能消耗
- v-if 有更高的切换消耗
- v-show 有更高的初始渲染消耗
5、使用场景
- v-if 适合运营条件不大可能改变
- v-show 适合频繁切换
57、 如何让 CSS 值在当前的组件中起作用
在 vue 文件中的 style 标签上,有一个特殊的属性:scoped。当一个 style 标签拥有 scoped 属性时,它的 CSS 样式就只能作用于当前的组件,也就是说,该样式只能适用于当前组件元素。通过该属性,可以使得组件之间的样式不互相污染。如果一个项目中的所有 style 标签全部加上了 scoped,相当于实现了样式的模块化。
scoped 的实现原理
vue 中的 scoped 属性的效果主要通过 PostCSS 转译实现的。PostCSS 给一个组件中的所有 DOM 添加了一个独一无二的动态属性,然后,给 CSS 选择器额外添加一个对应的属性选择器来选择该组件中 DOM,这种做法使得样式只作用于含有该属性的 DOM,即组件内部 DOM。
例如:
转译前
xml
<template>
<div class="example">hi</div>
</template>
<style scoped>
.example {
color: red;
}
</style>
转译后:
xml
<template>
<div class="example" data-v-5558831a>hi</div>
</template>
<style>
.example[data-v-5558831a] {
color: red;
}
</style>
58、 0.1 + 0.2 === 0.3 嘛?为什么?
运算时发生了什么?
首先,计算机无法直接对十进制的数字进行运算,这是硬件物理特性已经决定的。这样运算就分成了两个部分:先按照IEEE 754转成相应的二进制,然后对阶运算
.
1.进制转换
0.1和0.2转换成二进制后会无限循环
js
0.1 -> 0.0001100110011001...(无限循环)
0.2 -> 0.0011001100110011...(无限循环)
IEEE 754标准,通过64位来表示一个数字,会将多余的位数截取掉(进制之间的转换中精度已经损失
)
- 第0位:符号位,0表示正数,1表示负数(s)
- 第1位到第11位:储存指数部分(e)
- 第12位到第63位:储存小数部分(即有效数字)f
2.对阶运算
对两个二进制数做加法
js
0 01111111100 0.1100110011001100110011001100110011001100110011001101
+ 0 01111111100 1.1001100110011001100110011001100110011001100110011010
= 0 01111111100 10.0110011001100110011001100110011001100110011001100111
对阶后发现,最后一个 1
放不下了,需要舍弃,根据标准当要舍弃一位数时,需要进行0舍1入
。如果被舍弃的是 0
什么都不用做,如果被舍弃的是1
,则需要补回来。
js
0 01111111101 0011001100110011001100110011001100110011001100110011 1(1 多出,需要舍弃)
0 01111111101 0011001100110011001100110011001100110011001100110100 (补 1)
造成不一样的原因:浮点数运算过程中的误差问题。
小数在计算机的存储过程中本身就存在精度丢失的问题,然后尾数的位数总共只有 52
位,放不下时会被丢弃,并按照 舍0补1
来弥补导致最终运算结果不相等。
59、 new 一个函数发生了什么
通过 new
去调用一个函数时,这个函数就是一个构造函数
- 在内存中创建一个新的空对象;
- 构造函数的
prototype
的值会被赋给第 1 步创建的对象的 [[Prototype]] 属性; - 构造函数内部的
this
,也会指向第 1 步创建的对象; - 执行函数的内部代码(函数体);
- 如果构造函数没有返回非空对象,则返回第 1 步创建的对象(其实也就是
this
)。
以下是使用 new
关键字创建对象的基本原理
-
创建一个空对象:首先,JavaScript 会创建一个空对象,这个对象将成为新创建对象的实例。
-
执行构造函数:接下来,JavaScript 会调用传递给
new
关键字的函数,并将新创建的空对象作为this
参数传递给该函数。这个函数通常被称为构造函数。 -
设置原型:在构造函数内部,可以为新对象设置属性和方法。构造函数的返回值通常是被忽略的,但如果构造函数返回一个对象,那么这个对象将被用作新创建对象的原型。
-
原型链:新创建的对象具有一个指向构造函数的原型对象的内部链接,这个链接被称为原型链。通过原型链,新对象可以访问从原型对象继承的属性和方法。
js
function Person(name, age) {
this.name = name;
this.age = age;
}
// 为原型对象添加方法
Person.prototype.sayHello = function() {
console.log('Hello, my name is ' + this.name);
}
var person1 = new Person('John', 30);
person1.sayHello();
60、 你知道 301、302 状态码是什么嘛?
301 状态码
301 Moved Permanently,永久性重定向。当服务器收到请求后,会告诉浏览器,此资源被分配到了一个新的URL下,此时的浏览器会自动将请求重定向到新的URL下,以后所有的请求都会去请求新的URL。
包含了 第一次请求
与 第二次请求
的情况
- 第一次访问原始URL,浏览器向服务器发送请求。
- 服务器响应请求,将
301状态码
与最新的资源地址(位于响应头里的location字段)
返回给浏览器。 - 浏览器收到301状态码后,向最新的地址发送请求,此时浏览器地址栏里的地址也将变为最新的资源地址。
- 浏览器将最新的资源缓存到本地。
- 当以后再访问老的URL时,浏览器就不去请求老的URL,而是去请求新的URL。
例如:
js
// 老路由
router.get('/301oldLogin', function(req, res, next) {
// 301永久重定向
res.redirect(301, '/login/301newLogin');
});
// 新路由
router.get('/301newLogin', function(req, res, next) {
res.send(`
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>301访问新登录页</title>
<style>
* {
margin: 0;
padding: 0;
}
html, body {
width: 100%;
height: 100%;
}
div {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
</style>
</head>
<body>
<div>欢迎登陆新的页面-301</div>
</body>
</html>
`);
});
第一次访问老路由(浏览器里输入:http://localhost:3000/login/301oldLogin
),此时的页面状态如下:
第二次访问老路由
- 第一次访问老url,先请求老的url的资源,再去请求新的url的资源,此时地址栏里的地址将会自动变为新的url。
- 浏览器将最新的资源地址 与 资源内容缓存到本地。
- 当再次访问老的url的时候,浏览器直接去请求新的资源地址。
302 状态码
302 Found(临时重定向)。表示资源临时被移动到新的url。浏览器在遇到这个状态码后,同样会将地址栏里的老url替换为新的url,但后续请求依旧会去请求老的url。
- 浏览器访问老的url,服务端返回302状态码 以及 最新的资源地址。
- 浏览器得到302状态码,将地址栏变为最新的资源地址,然后去访问最新的地址。
- 当浏览器再次访问老的url,开始重复第一步。
包含了 第一次请求
和 第二次请求
的状况
例如:
js
router.get('/302oldLogin', function(req, res, next) {
res.redirect(302, '/login/302newLogin');
});
router.get('/302newLogin', function(req, res, next) {
res.send(`
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>302访问新登录页</title>
<style>
* {
margin: 0;
padding: 0;
}
html, body {
width: 100%;
height: 100%;
}
div {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
</style>
</head>
<body>
<div>欢迎登陆新的页面-302</div>
</body>
</html>
`);
});
第一次请求老路由,地址栏输入: http://localhost:3000/login/302oldLogin
,页面状态如下:
第二次请求老路由也是一样的结果.