大厂经典面试题
邵预鸿 Lv5

css性能问题,以下代码性能最好的是?

1
2
3
4
5
6
a{
color:red;
}
li a{
color:blue;
}

答案: 第一个,原因浏览器渲染机制选择器从右向左匹配,以下选择器会首先匹配a,然后li,li进行的是二次匹配

symbol问题

1
2
3
4
5
var a = {},b=Symbol('1'),c=Symbol(1);
a[b] = '培训';
a[c]= '计划';
console.log(a[b]);

以下代码将输出

1
2
3
4
5
6
var test =(function(i){
return function(){
console.log(i*=2);
}
})(5);
test(10);

valueOf与toString的区别

参考链接:链接

HTTPS和HTTP有什么区别?

http协议传输的数据都bai是未加密的,du也就是明文的,因此使用zhihttp协议传输隐私dao信息非常不安全。为了保证这些隐私数据能加密传输,于是网景公司设计了ssl(Secure Sockets Layer)协议用于对http协议传输的数据进行加密,从而就诞生了https。

简单zhuan说,https协议是由ssl+http协议构建的可进行加密传输、身份认证的网络协议,要比http协议安全。

https和http的主要区别:

一、https协议需要到ca机构申请ssl证书(如沃通CA),另外沃通CA还提供3年期的免费ssl证书,高级别的ssl证书需要一定费用。

二、http是超文本传输协议,信息是明文传输,https 则是具有安全性的ssl加密传输协议。

三、http和https使用的是完全不同的连接方式,用的端口也不一样,http是80端口,https是443端口。

四、http的连接很简单,是无状态的;https协议是由ssl+http协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。

写出执行结果,并解释原因

1
2
3
4
5
6
(function () {
var a = (b = 5);
})();
console.log(b);
console.log(a);
// 写出执行结果,并解释原因

答案5 Error, a is not defined

解析

在这个立即执行函数表达式(IIFE)中包括两个赋值操作,其中a使用var关键字进行声明,因此其属于函数内部的局部变量(仅存在于函数中),相反,b被分配到全局命名空间。window.b另一个需要注意的是,这里没有在函数内部使用严格模式(use strict;)。如果启用了严格模式,代码会在输出 b 时报错Uncaught ReferenceError: b is not defined,需要记住的是,严格模式要求你显式的引用全局作用域。

写出执行结果,并解释原

1
2
3
4
var min = Math.min();
max = Math.max();
console.log(min < max);
// 写出执行结果,并解释原因

答案 false

解析

  • 按常规的思路,这段代码应该输出 true,毕竟最小值小于最大值。但是却输出 false
  • MDN 相关文档是这样解释的
  • Math.min 的参数是 0 个或者多个,如果多个参数很容易理解,返回参数中最小的。如果没有参数,则返回 Infinity,无穷大。
  • 而 Math.max 没有传递参数时返回的是-Infinity.所以输出 false

写出执行结果

1
2
3
4
5
6
7
8
9
10
function side(arr) {
arr[0] = arr[2];
}
function a(a, b, c = 3) {
c = 10;
side(arguments);
return a + b + c;
}
a(1, 1, 1);
// 写出执行结果,并解释原因

答案:12

解析

arguments 中 c 的值还是 1 不会变成 10,arguments依然是[1,1,1]

因为 a 函数加了默认值,就按 ES 的方式解析,ES6 是有块级作用域的,所以 c 的值是不会改变的

{} 的 valueOf 结果为 {} ,toString 的结果为 “[object Object]”

[] 的 valueOf 结果为 [] ,toString 的结果为 “”

数据类型的加减

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
({}+{})
//结果:"[object Object][object Object]"

({}+{}).length
//结果:30

[]+[]
//结果:""
//原因:数组相加时,作为表达式会调用toString()方法,空数组.toString(),结果为空; [1,2].toString() 结果为1,2

[]+[1,2]
//结果:1,2

([]+[1,2]).length
//结果:3

(function(){}).length
//结果:0

(function(a,b){}).length
//结果:2
//原因:这里的length长度取决于形参的个数
// ** 来源于早上地铁上看的一篇文章,又学会了一段没用的骚写法。 **

假定有一随机数据 [2, 10, 3, 4, 5, 11, 10, 11, 20],将其按区间排列成一个新数组,要求新数组形式如下,例如 [[2, 3, 4, 5], [10, 11], [20]]。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<script>
function setRandomArray(){
return [...Array.from({length:30},item=>parseInt(Math.random() * 100)),1000];
}
function sortArray(arr){
return arr.sort((a,b)=>a-b);
}
function formatter(arr){
let min=parseInt(arr[0] / 10) * 10; //10,20,30
let max=parseInt(arr[0] / 10) * 10 + 9;//19,29,39
let saveTmpArray= [],resultArray=[];
for(let i=0,length=arr.length;i<length;i++){
if(arr[i]>=min && arr[i]<=max){
saveTmpArray.push(arr[i]);
}else{
resultArray.push(saveTmpArray.concat());
min=parseInt(arr[i] / 10) * 10; //10,20,30
max=parseInt(arr[i] / 10) * 10 + 9;//19,29,39
saveTmpArray.length=0;
saveTmpArray.push(arr[i]);
}
if(i===length-1){
resultArray.push(saveTmpArray);
}
}
return resultArray;
}
let arr1 = sortArray(setRandomArray());
console.log(arr1);
let result = formatter(arr1);
console.log(result);
</script>

(百度)实现 (5).add(3).minus(2) 功能。

1
2
3
4
5
6
7
8
9
<script>
Number.prototype.add=function(val){
return this+ val;
}
Number.prototype.minus = function(val){
return this - val;
}
console.log((5).add(3).minus(2) );
</script>

下面代码中 a 在什么情况下会打印 1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var a = ?;
if(a == 1 && a == 2 && a == 3){
conso.log(1);
}

//答案
var a = {
i: 1,
toString() {
return a.i++;
}
}

if( a == 1 && a == 2 && a == 3 ) {
console.log(1);
}

经典面试题

1
2
3
4
5
var b = 10;
(function b() {
b = 20;
console.log(b)
})()

针对这题,在知乎上看到别人的回答说:

  1. 函数表达式与函数声明不同,函数名只在该函数内部有效,并且此绑定是常量绑定。
  2. 对于一个常量进行赋值,在 strict 模式下会报错,非 strict 模式下静默失败。
  3. IIFE中的函数是函数表达式,而不是函数声明。

实际上,有点类似于以下代码,但不完全相同,因为使用const不管在什么模式下,都会TypeError类型的错误

1
2
3
4
5
const foo = function () {
foo = 10;
console.log(foo)
}
(foo)() // Uncaught TypeError: Assignment to constant variable.

我的理解是,b函数是一个相当于用const定义的常量,内部无法进行重新赋值,如果在严格模式下,会报错”Uncaught TypeError: Assignment to constant variable.”

例如下面的:

1
2
3
4
5
6
var b = 10;
(function b() {
'use strict'
b = 20;
console.log(b)
})() // "Uncaught TypeError: Assignment to constant variable."

关于 const 和 let 声明的变量不在 window 上

在ES5中,顶层对象的属性和全局变量是等价的,var 命令和 function 命令声明的全局变量,自然也是顶层对象。

1
2
3
4
5
var a = 12;
function f(){};

console.log(window.a); // 12
console.log(window.f); // f(){}

但ES6规定,var 命令和 function 命令声明的全局变量,依旧是顶层对象的属性,但 let命令、const命令、class命令声明的全局变量,不属于顶层对象的属性。

1
2
3
4
5
let aa = 1;
const bb = 2;

console.log(window.aa); // undefined
console.log(window.bb); // undefined

在哪里?怎么获取?通过在设置断点,看看浏览器是怎么处理的:

letandconst

通过上图也可以看到,在全局作用域中,用 let 和 const 声明的全局变量并没有在全局对象中,只是一个块级作用域(Script)中

怎么获取?在定义变量的块级作用域中就能获取啊,既然不属于顶层对象,那就不加 window(global)呗。

1
2
3
4
5
let aa = 1;
const bb = 2;

console.log(aa); // 1
console.log(bb); // 2

重绘和回流(Repaint & Reflow),以及如何进行优化

浏览器渲染机制

  • 浏览器采用流式布局模型(Flow Based Layout
  • 浏览器会把HTML解析成DOM,把CSS解析成CSSOMDOMCSSOM合并就产生了渲染树(Render Tree)。
  • 有了RenderTree,我们就知道了所有节点的样式,然后计算他们在页面上的大小和位置,最后把节点绘制到页面上。
  • 由于浏览器使用流式布局,对Render Tree的计算通常只需要遍历一次就可以完成,但table及其内部元素除外,他们可能需要多次计算,通常要花3倍于同等元素的时间,这也是为什么要避免使用table布局的原因之一。

重绘

由于节点的几何属性发生改变或者由于样式发生改变而不会影响布局的,称为重绘,例如outline, visibility, colorbackground-color等,重绘的代价是高昂的,因为浏览器必须验证DOM树上其他节点元素的可见性。

回流

回流是布局或者几何属性需要改变就称为回流。回流是影响浏览器性能的关键因素,因为其变化涉及到部分页面(或是整个页面)的布局更新。一个元素的回流可能会导致了其所有子元素以及DOM中紧随其后的节点、祖先节点元素的随后的回流。

1
2
3
4
5
6
7
8
9
10
11
<body>
<div class="error">
<h4>我的组件</h4>
<p><strong>错误:</strong>错误的描述…</p>
<h5>错误纠正</h5>
<ol>
<li>第一步</li>
<li>第二步</li>
</ol>
</div>
</body>

在上面的HTML片段中,对该段落(<p>标签)回流将会引发强烈的回流,因为它是一个子节点。这也导致了祖先的回流(div.errorbody – 视浏览器而定)。此外,<h5><ol>也会有简单的回流,因为其在DOM中在回流元素之后。大部分的回流将导致页面的重新渲染。

回流必定会发生重绘,重绘不一定会引发回流。

浏览器优化

现代浏览器大多都是通过队列机制来批量更新布局,浏览器会把修改操作放在队列中,至少一个浏览器刷新(即16.6ms)才会清空队列,但当你获取布局信息的时候,队列中可能有会影响这些属性或方法返回值的操作,即使没有,浏览器也会强制清空队列,触发回流与重绘来确保返回正确的值。

主要包括以下属性或方法:

  • offsetTopoffsetLeftoffsetWidthoffsetHeight
  • scrollTopscrollLeftscrollWidthscrollHeight
  • clientTopclientLeftclientWidthclientHeight
  • widthheight
  • getComputedStyle()
  • getBoundingClientRect()

所以,我们应该避免频繁的使用上述的属性,他们都会强制渲染刷新队列。

减少重绘与回流

CSS

  • 使用 transform 替代 top
  • 使用 visibility 替换 display: none ,因为前者只会引起重绘,后者会引发回流(改变了布局
  • 避免使用table布局,可能很小的一个小改动会造成整个 table 的重新布局。
  • 尽可能在DOM树的最末端改变class,回流是不可避免的,但可以减少其影响。尽可能在DOM树的最末端改变class,可以限制了回流的范围,使其影响尽可能少的节点。
  • 避免设置多层内联样式,CSS 选择符从右往左匹配查找,避免节点层级过多。
1
2
3
4
5
6
7
8
9
10
11
<div>
<a> <span></span> </a>
</div>
<style>
span {
color: red;
}
div > a > span {
color: red;
}
</style>
  • 对于第一种设置样式的方式来说,浏览器只需要找到页面中所有的 span 标签然后设置颜色,但是对于第二种设置样式的方式来说,浏览器首先需要找到所有的 span 标签,然后找到 span 标签上的 a 标签,最后再去找到 div 标签,然后给符合这种条件的 span 标签设置颜色,这样的递归过程就很复杂。所以我们应该尽可能的避免写过于具体的 CSS 选择器,然后对于 HTML 来说也尽量少的添加无意义标签,保证层级扁平。
  • 将动画效果应用到position属性为absolutefixed的元素上,避免影响其他元素的布局,这样只是一个重绘,而不是回流,同时,控制动画速度可以选择 requestAnimationFrame,详见探讨 requestAnimationFrame
  • 避免使用CSS表达式,可能会引发回流。
  • 将频繁重绘或者回流的节点设置为图层,图层能够阻止该节点的渲染行为影响别的节点,例如will-changevideoiframe等标签,浏览器会自动将该节点变为图层。
  • CSS3 硬件加速(GPU加速),使用css3硬件加速,可以让transformopacityfilters这些动画不会引起回流重绘 。但是对于动画的其它属性,比如background-color这些,还是会引起回流重绘的,不过它还是可以提升这些动画的性能。

JavaScript

  • 避免频繁操作样式,最好一次性重写style属性,或者将样式列表定义为class并一次性更改class属性。
  • 避免频繁操作DOM,创建一个documentFragment,在它上面应用所有DOM操作,最后再把它添加到文档中。
  • 避免频繁读取会引发回流/重绘的属性,如果确实需要多次使用,就用一个变量缓存起来。
  • 对具有复杂动画的元素使用绝对定位,使它脱离文档流,否则会引起父元素及后续元素频繁回流。

不用找UI, CSS也能搞定图片效果

一. 实现图片的等比缩放

在实际开发过程中, 总是会遇到各种需要处理图片的情况,举个简单的例子, 用户上传头像,我们都知道头像宽高是有一定比例的, 但用户的图片千奇百怪,如果简单的按照我们设定的宽高显示,图片变形不可避免,那么该怎么处理?

方法1: 「object-fit」

这个时候我们需要用到css的一个属性,「 object-fit.」

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<div class='header-container'>
<img src="./333.jpg" alt="">
</div>
<img src="./333.jpg" alt="" style='height: 100px;'>
复制代码
.header-container{
width: 100px;
height: 100px;
border: 1px solid #333;
border-radius: 50%;
overflow: hidden;
}
.header-container img{
width: 100%;
height: 100%;
}
复制代码

img

不难看出, 上面的头像对比下面的原图,高度被拉伸了, 那么此时只需要给img添加一个属性「object-fit: cover;」

效果如下:

img

object-fit属性你了解多少呢?下面听我详细介绍下。

「object-fit属性详解」

根据MDN(object-fill)的介绍, **object-fit** CSS 属性指定可替换元素的内容应该如何适应到其使用的高度和宽度确定的框。

也就是说盒子固定宽高, 图片在这个盒子里面会如何适应。

它有四个属性值:

1
fill | contain | cover | none | scale-down

contain: 被替换的元素会被缩放,以此来适应框的宽高比, 如果里面元素的宽高比和框的宽高比不匹配,那么就会产生黑边。

img

可以看到上面图片中左右两边的就是所谓的黑边, 因为它的宽高比与框的不一致。

cover: 被替换的内容在保持其宽高比的同时填充元素的整个内容框。如果对象的宽高比与内容框不相匹配,该对象将被剪裁以适应内容框。

也就是说, 在宽高比不一致时,cover属性值会进行裁剪,以此来适应容器。

就像这样:

img

fill:被替换的内容正好填充元素的内容框。整个对象将完全填充此框。如果对象的宽高比与内容框不相匹配,那么该对象将被拉伸以适应内容框。

fill属性与cover属性值类似,都会完全填充内容框, 不同的是「fill属性值会拉伸元素来适应容器」

如下图, 高度被拉伸

img

scale-down: 内容的尺寸与 nonecontain 中的一个相同,取决于它们两个之间谁得到的对象尺寸会更小一些。

大概就是取决于none和contain的最小值, 这个属性不怎么用到。

方法2: max-width和 max-height

我们可以设置max-width和max-height来限制图片的最大值,一般是设置为外层容器的100%; 这样图片就会等比缩放,且不会变形。

img

二.css处理图片效果

比如背景图片变模糊, 头像变亮,增加投影效果,反转颜色,对比度,饱和度等等

只需要使用到css3的一个属性, filter

原图:

img

1.图片变模糊
1
filter: blur(5px);复制代码

img

2.图片对比度调整
1
filter: contrast(200%);复制代码

img

#####3. 将图片转为灰度图像

1
filter: grayscale(1);复制代码

img

像清明节等这样的特殊节日,一行代码使全网变灰, 就是利用的这个属性。

4.色相旋转,
1
filter: hue-rotate(45deg);复制代码

img

5.给图像设置一个阴影效果
1
filter: drop-shadow(16px 16px 20px yellow) invert(3%);复制代码

img

下面具体说说filter的各个属性值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/* URL to SVG filter */
filter: url("filters.svg#filter-id");
/* values */
filter: blur(5px);
filter: brightness(0.4);
filter: contrast(200%);
filter: drop-shadow(16px 16px 20px blue);
filter: grayscale(50%);
filter: hue-rotate(90deg);
filter: invert(75%);
filter: opacity(25%);
filter: saturate(30%);
filter: sepia(60%);
/* Multiple filters */
filter: contrast(175%) brightness(3%);
/* Global values */
filter: inherit;
filter: initial;
filter: unset;

复制代码
  • 「url()」:URL函数接受一个XML文件,该文件设置了 一个SVG滤镜,且可以包含一个锚点来指定一个具体的滤镜元素.
  • 「blur()」:给图像设置高斯模糊,值越大越模糊, 但不支持百分比
  • 「brightness()」: 给图像应用一种线性乘法,使其变暗/变亮,为0则全黑,为100%以上才会有变亮的效果
  • 「contrast()」:调整图像的对比度。值是0%的话,图像会全黑。值是100%,图像不变。值可以超过100%,意味着会运用更低的对比。若没有设置值,默认是1。
  • 「drop-shadow()」: 给图像设置一个阴影效果。阴影是合成在图像下面,可以有模糊度的,可以以特定颜色画出的遮罩图的偏移版本.
  • 「grayscale()」: 将图像转换为灰度图像。值定义转换的比例。值为100%则完全转为灰度图像,值为0%图像无变化。值在0%到100%之间,则是效果的线性乘子。若未设置,值默认是0。
  • 「hue-rotate()」: 给图像应用色相旋转。“angle”一值设定图像会被调整的色环角度值。值为0deg,则图像无变化。若值未设置,默认值是0deg。该值虽然没有最大值,超过360deg的值相当于又绕一圈。
  • 「invert()」: 反转输入图像。值定义转换的比例。100%的价值是完全反转。值为0%则图像无变化。值在0%和100%之间,则是效果的线性乘子。 若值未设置,值默认是0。

【哪里不会补哪里】TCP3次握手

TCP层级

1
应用层、表示层、会话层、传输层、网络层、数据链路层、物理层

TCP与UDP的区别

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1、连接方面区别
TCP需要经过3次握手建立连接
UDP是无连接的,即发送数据之前专不需属要建立连接。

2、安全方面的区别
TCP提供可靠的服务,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达。
UDP尽最大努力交付,即不保证可靠交付

3、传输效率的区别
TCP传输效率相对较低,原因是每次连接都需要3次握手,例如移动支付必须确保数据的准确和可靠
UDP传输效率高,例如视频播放,提高效率

4、连接对象数量的区别
TCP连接只能是点到点、一对一的
UDP支持一对一,一对多,多对一和多对多的交互通信。

TCP3次握手图

img

1
2
3
4
第一次握手:建立连接时,客户端发送syn包(seq=j)到服务器,并进入SYN_SENT状态,等待服务器确认;SYN:同步序列编号
第二次第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(seq=k),即SYN+ACK包,此时服务器进入SYN_RECV状态。
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。
完成三次握手,客户端与服务器开始传送数据

函数提升高于变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var a = 10;
function a(){
console.log('function a');
}
console.log(a,typeof a)??????
//以上输出10
//原因是函数的优先级提升高于变量提升,所以上述代码等同于
function a(){
console.log('function a');
}
var a = 10;
console.log(a,typeof a);

//奇怪的知识又增加了

js表达式

1
2
3
str1 = 1&&2&&3 ; //str1 =3
str2 = 1&&0&&3 ; //str2 = 0
总结:所有条件为真,返回最后一个表达式。 条件为假,返回为假

关于img 与背景图的区别

  1. 只要是img src引用的都会请求;

  2. background: url()所属样式如果挂靠在某个元素上,就一定会请求;单独写了这么一个样式并不请求。

1
2
3
4
5
6
7
8
9
+[] ===0

function test(a){
a=a+10;
}
var a=10;
test(a);
console.log(a);
//a是形参,属于局部变量,不影响全局变量a的值,因此输出的a是全局变量的值10

下列关于比较Ajax与Flash的优缺点,相关描述正确的是?

Ajax的优势在意在于开放性,易用性及易于开发

Flash的优势在于多媒体处理,可以更容易的调用浏览器以外的外部资源

Ajax最主要的批评就是它可能破坏浏览器的后退功能

flash 文件经常会很大,用户第一次使用的时候需要忍耐较长的等待时间

正确答案: A B C D

面试被问很多次的题,HTTP1和HTTP2的区别

Http1.0(短连接)

缺陷:浏览器与服务器只保持短暂的连接,浏览器的每次请求都需要与服务器建立一个TCP连接(TCP连接的新建成本很高,因为需要客户端和服务器三次握手),服务器完成请求处理后立即断开TCP连接,服务器不跟踪每个客户也不记录过去的请求;

解决方案:添加头信息——非标准的Connection字段Connection: keep-alive

Http1.1

持久连接(与Http1其它版本的最大区别)

引入了持久连接,即TCP连接默认不关闭,可以被多个请求复用,不用声明Connection: keep-alive(对于同一个域名,大多数 浏览器允许同时建立6个持久连接)

管道机制

即在同一个TCP连接里面,客户端可以同时发送多个请求。

分块传输编码

即服务端每产生一块数据,就发送一块,采用”流模式”而取代”缓存模式”。

新增请求方式

PUT:请求服务器存储一个资源;

DELETE:请求服务器删除标识的资源;

OPTIONS:请求查询服务器的性能,或者查询与资源相关的选项和需求;

TRACE:请求服务器回送收到的请求信息,主要用于测试或诊断;

CONNECT:保留将来使用

缺点:

虽然允许复用TCP连接,但是同一个TCP连接里面,所有的数据通信是按次序进行的。服务器只有处理完一个请求,才会接着处理下一个请求。如果前面的处理特别慢,后面就会有许多请求排队等着。这将导致“队头堵塞”

避免方式:一是减少请求数,二是同时多开持久连接

Http/2.0

  1. 采用二进制格式而非文本格式;
  2. 完全多路复用,而非有序并阻塞的、只需一个连接即可实现并行;(解决了线头阻塞的问题,与Http1最重要的区别)
  3. 使用报头压缩,降低开销
  4. 服务器推送

深度解析使用CSS单位px、em、rem、vh、vw、vmin、vmax实现页面布局

vw、vh、vmin、vmax 主要用于页面视口大小布局,相对于rem;v*在页面布局上更加方便简单

vw:viewpoint width,视窗宽度,1vw等于视窗宽度的1%。 该单位适用于大屏数据展示时,使用px=》vh vw的转化

vh:viewpoint height,视窗高度,1vh等于视窗高度的1%。 该单位适用于大屏数据展示时,使用px=》vh vw的转化

vmin:vw和vh中较小的那个。

vmax:vw和vh中较大的那个。

vw逻辑非常清晰,”1vw = 1/100th viewport width”,用viewport width的百分比来设置element width。

vw被支持的太晚是其并不流行的根本原因,而当时移动端web app/page的开发需求已经十分旺盛,弹性布局是一种不错的移动端界面兼容展现方式,对于rem机遇就此而来,便成为一个实现弹性布局效果的极佳方案。

百度面试题记-写一个函数实现返回数据类型,包含基本数据类型,引用数据类型,日期型,正则

1
2
3
4
5
6
7
<script>
function checkDataType(data){
let dataType = Object.prototype.toString.call(data);
let substrType = dataType.substring(8,dataType.length-1);
return subStrType;
}
</script>

时间复杂度

图片

我以为a == 1 && a == 2 && a == 3这种判断的面试题已经够变态,没想道

本以为

if(a == 1 && a == 2 && a == 3){console.log(‘a’)}

这种判断通过JS隐式转换的题已经足够变态,没想道遇上了他,先上代码。

1
2
3
4
if(a===1 && a===2 && a===3){
console.log('success')
}
//不改变if判断的情况下补充代码,实现功能

解决,利用数据劫持,监听window对象

1
2
3
4
5
6
7
8
9
var current = 0;
Object.definePrototype(this,'a',{
get:function(){
return ++current;
}
})
if(a===1 && a===2 && a===3){
console.log('success')
}

以上代码,a ===1获取a时必然触发数据劫持中的get方法,this指向的window,a也是全局变量,挂载到了window中,实际中window.a ===a,所以每一个判断都会调get方法返回数据,只需要在get方法中累加并返回

感谢吴黎明大佬分享该题,2021/2/23 22:10修改

JavaScript 有几种类型

  • 基本数据类型:undefined、null、boolean、number、string、symbol(es6的新数据类型)
  • 引用数据类型:object、array、function(统称为object)

数据类型检测

typeof 对于基本数据类型来说,除了 null 都可以显示正确的类型,typeof 对于对象来说,除了函数都会显示 object

1
2
3
4
5
6
7
8
9
10
11
typeof 5 // 'number'
typeof '5' // 'string'
typeof undefined // 'undefined'
typeof false// 'boolean'
typeof Symbol() // 'symbol'
console.log(typeof null) //object
console.log(typeof NaN) //number

typeof [] // 'object'
typeof {} // 'object'
typeof console.log // 'function'

new 操作符具体干了什么?

  • 首先是创建实例对象{}
  • this 变量引用该对象,同时还继承了构造函数的原型
  • 其次属性和方法被加入到 this 引用的对象中
  • 并且新创建的对象由 this 所引用,最后隐式的返回 this

this 对象的理解

  • this 总是指向函数的直接调用者
  • 如果有 new 关键字,this 指向 new 出来的实例对象
  • 在事件中,this 指向触发这个事件的对象
  • IE 下 attachEvent 中的 this 总是指向全局对象 Window
  • 箭头函数中,函数体内的this对象,就是定义时所在作用域的对象,而不是使用时所在的作用域的对象。

关于cookie与session

cookie与session如果没有配置有效时间,则当前页面未关闭有效,页面关闭后便失效

输出以下结果

1
2
3
4
5
(function(){
var a= b = 100;
console.log(a,b);
})();
console.log(a,b);

结果为: 100,100 报错 100

原因是var a 定义的变量只在自执行函数中有效,自执行函数本身具体独立的作用域。b没有使用var定义,所以实现访问的是window.b = 100

实现$attr功能

Q:

1
2
假定html结构 如下:<body class="2"><h1 name='h1'>3</h1><p class="2"></p><div class="2">2</p><h3 name="h1">3</h3></body>
使用$attr('class',2),能得到所有class=2的元素。$attr('name',"h1")我能得到所有name=h1的元素

实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<body>
<h2 class="h">p class="h"</h2>
<p name="h">p name=h</p>
<h3 class="box1 box3 h p">p class="h"</h3>
<p age="22">p age=22</p>
</body>
</html>
<script>
(function(){
window.$attr = function(property,value){
var eleAll = document.querySelectorAll("*");
var elements = Array.from(eleAll);//第一种写法
/* [].forEach.call(eleAll,item=>{ console.log(item);})
遍历nodeList数组的第二种写法
*/
var result = elements.filter(item=>{
if(property ==='class'){
//class特殊处理 如class='box box2 box3'
var reg = new RegExp(`\\b${value}\\b`);
if(reg.test(item.getAttribute(property))){
return item;
}
}
if(item.getAttribute(property) === value){
return item;
}
});
return result;
}
})();

console.log($attr('class','h'))
console.log($attr('age','22'))
</script>

注意[].forEach.call(eleList,item=>{ item是每一个元素 }) 用法

  • 本文标题:大厂经典面试题
  • 本文作者:邵预鸿
  • 创建时间:2021-02-20 22:23:44
  • 本文链接:/images/logo.jpg2021/02/20/大厂经典面试题/
  • 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!