前端面试笔试(四)
目录
一、数据结构算法等综合篇
1.线性探查法解决哈希冲突
2.请求分页系统中文件区和对换区
3.RADIUS认证协议,运行在哪个网络协议上
二、代码输出篇
1.res=['1','2','100'].map(parseInt)
如果我们想要输出为[1,2,100],可以:
还可以换map里的这个函数:换成Number
2.delete 操作符用于删除对象的属性
3.call,bind改变this指向
三、html、css、JavaScript篇
1.Math.ceil()、Math.round() 和 Math.floor()
一、数据结构算法等综合篇
1.线性探查法解决哈希冲突
哈希表有10个元素,采用的hash函数为H(key)=key%10,用线性探查法解决哈希冲突,则(1,3,5,13,4,6)中4应该放在第几号格中?
答案:6
我理解的线性探查法就是,通过哈希函数取余后,得到的这个数字如果没有被占用就放在应该的位置,如果占用了就向后探查,直到探查到没有被占用的位置。
对于给定的键值序列 (1,3,5,13,4,6),我们依次插入这些键并处理冲突。
- 插入1:
- H(1)=1%10=1
- 位置1是空的,直接插入1。
- 插入3:
- H(3)=3%10=3
- 位置3是空的,直接插入3。
- 插入5:
- H(5)=5%10=5
- 位置5是空的,直接插入5。
- 插入13:
- H(13)=13%10=3
- 位置3已被3占据,使用线性探查法:
- 检查位置4(3+1),位置4是空的。
- 插入13到位置4。
哈希表当前状态:
索引: 0 1 2 3 4 5 6 7 8 9
值: _ 1 _ 3 13 5 _ _ _ _
这时候插入4:
- H(4)=4%10=4
- 位置4已被13占据,使用线性探查法:
- 检查位置5(4+1),位置5已被5占据。
- 检查位置6(5+1),位置6是空的。
- 插入4到位置6。
所以4放在6号格中。
然后链地址法就是,通过哈希函数取余后,在哈希表的这个位置放个链表,然后把哈希地址相同的记录都链接在同一链表中。
2.请求分页系统中文件区和对换区
请求分页系统中的外存分为用于存放文件的文件区和用于存放对换页面的对换区,关于文件区和对换区的分配方式,哪个用离散分配,哪个用连续分配?
文件区是离散分配,对换区是连续分配
文件区
-
分配方式:离散分配。
-
原因:文件区用于存放各类文件,这些文件的访问频率通常较低。为了提高文件存储空间的利用率,文件区采取离散分配方式。离散分配允许文件被分散地存储在外存的多个不相邻的位置,从而更有效地利用存储空间。
对换区
-
分配方式:连续分配。
-
原因:对换区用于存放从内存换出的进程(或页面)。这些进程(或页面)在需要时会被换入内存,因此它们的访问频率相对较高。为了提高进程换入和换出的速度,对换区采取连续分配方式。连续分配可以确保进程(或页面)在换入和换出时能够快速地找到连续的内存块或外存区域,从而减少地址转换和内存管理的时间开销。
综上所述,文件区采用离散分配方式以提高存储空间的利用率,而对换区则采用连续分配方式以提高进程换入和换出的速度。这两种分配方式共同构成了请求分页系统中外存的有效管理策略。
3.RADIUS认证协议,运行在哪个网络协议上
RADIUS(Remote Authentication Dial In User Service,远程用户拨号认证)认证协议是运行在网络协议UDP(User Datagram Protocol,用户数据报协议)之上的。RADIUS是一种分布式的、客户端/服务器结构的信息交互协议,能保护网络不受未授权访问的干扰,常应用在既要求较高安全性、又允许远程用户访问的各种网络环境中。该协议定义了基于UDP的RADIUS报文格式及其传输机制,并规定UDP端口1812、1813分别作为默认的认证、计费端口。
RADIUS协议最初仅是针对拨号用户的AAA(认证、授权和计费)协议,后来随着用户接入方式的多样化发展,RADIUS也适应多种用户接入方式,如以太网接入等。它通过认证授权来提供接入服务,通过计费来收集、记录用户对网络资源的使用。
二、代码输出篇
1.res=['1','2','100'].map(parseInt)
let res=['1','2','100'].map(parseInt)
console.log(res);
输出结果为:[1,NaN,4]
解释:
map函数:
将数组的每个元素传递给指定的函数处理,并返回处理后的数组
所以 [‘1’,‘2’,‘100’].map(parseInt) 就是将字符串1,2,100作为元素;0,1,2作为下标分别调用 parseInt 函数。
即求出 parseInt(‘1’,0), parseInt(‘2’,1), parseInt(‘100’,2)的结果。
parseInt
函数会接收到两个参数:当前遍历的元素(这里是字符串)和当前元素的索引(一个整数)。由于parseInt
的第二个参数(基数)通常用于指定解析时使用的进制,但在这里,它错误地接收了元素的索引作为基数。
这里是具体发生了什么:
-
对于第一个元素
'1'
,索引是0。parseInt('1', 0)
在现代浏览器中通常会被解析为1,因为当基数为0时,如果字符串不以"0x"或"0X"开头,则默认使用10作为基数(尽管这个行为在某些旧版浏览器中可能有所不同)。但在这个例子中,我们可以认为它解析为了1,因为结果符合我们的预期。 -
对于第二个元素
'2'
,索引是1。parseInt('2', 1)
会解析为NaN,因为基数1不是有效的基数。 -
对于第三个元素
'100'
,索引是2。parseInt('100', 2)
会尝试将字符串"100"解析为二进制数。在二进制中,"100"是一个有效的数字,它等于十进制的4。因此,这里的结果是4,而不是我们可能期望的100(如果我们希望将其解析为十进制数的话)。
这个结果是由于parseInt
函数在map
回调中被错误地使用了数组的索引作为基数所导致的。
如果我们想要输出为[1,2,100],可以:
指定一个明确的基数(通常是10,如果你希望将字符串解析为十进制数)给parseInt
函数
let res = ['1', '2', '100'].map(numStr => parseInt(numStr, 10));
console.log(res); // 输出: [1, 2, 100]
还可以换map里的这个函数:换成Number
let res=['1','2','100'].map(Number)
console.log(res);//[1,2,100]
2.delete
操作符用于删除对象的属性
const name="name";
url="www.baidu.com";// 注意:这里应该用var、let或const声明url,否则它是全局对象的属性(在浏览器中通常是window)
console.log(delete name);
console.log(delete url);
console.log(delete name);
console.log(delete url);
输出结果为:
false
true
在JavaScript中,delete
操作符用于删除对象的属性。然而,它不能用于删除通过 var
、const
或 let
声明的变量,因为这些变量并不是对象的属性,而是属于词法环境的一部分。
有几个关键点需要注意:
const name = "name";
声明了一个常量name
,它不能被delete
操作符删除。url = "www.baidu.com";
实际上是在全局作用域中创建或覆盖了一个属性url
(在浏览器中,这通常是window.url
的一个简写,但window
对象本身并未在代码中显式提及)。由于url
是作为全局对象的属性被创建的,所以理论上它可以通过delete
操作符被删除(尽管在实际开发中修改全局对象通常是不推荐的做法)。
在严格模式('use strict';
)下,尝试删除通过 const
或 let
声明的变量会抛出一个 TypeError
。同时,即使不在严格模式下,delete
操作符对于通过 const
声明的变量也会返回 false
,表示删除操作失败。
3.call,bind改变this指向
var num=2;
function getNum(){
let num=3;
console.log(this.num);
}
function func(){
let num=3;
getNum.call(this);
}
var obj={
num: 1,
func:func.bind(this)
}
obj.func();
输出结果为:2
在解析这段代码之前,我们需要理解几个关键点:变量作用域、this
关键字的行为,以及 bind
方法的用途。
-
变量作用域:
var
声明的变量具有函数作用域或全局作用域(如果声明在函数外部)。let
声明的变量具有块级作用域,即它们只在其声明的块(由{}
包围的代码块)内有效。 -
this
关键字:this
的值取决于函数是如何被调用的。在全局作用域中,this
通常指向全局对象(在浏览器中是window
)。但是,当函数作为对象的方法被调用时,this
指向该对象。使用call
、apply
或bind
方法可以显式地设置this
的值。 -
bind
方法:bind
方法创建一个新的函数,当这个新函数被调用时,this
被设置为bind
方法的第一个参数,其余参数将作为新函数的前置参数传递给原函数。
那么上面的代码可以添加一些注释如下:
var num = 2; // 全局变量 num
function getNum() {
let num = 3; // 块级作用域变量 num,仅在 getNum 函数内部有效
console.log(this.num); // 输出 this 指向对象的 num 属性
}
function func() {
let num = 3; // 块级作用域变量 num,仅在 func 函数内部有效
getNum.call(this); // 使用 call 方法显式设置 this 的值
}
var obj = {
num: 1, // 对象属性 num
func: func.bind(this) // 将 func 函数绑定到全局 this(在这里是全局对象)
};
obj.func(); // 调用 obj 的 func 方法
关键点在于 func.bind(this)
。在这里,this
在 bind
调用时指的是全局对象(在浏览器中是 window
)。因此,func
函数被绑定到全局对象,无论它如何被调用,其内部的 this
都指向全局对象。
但是,由于 getNum.call(this)
在 func
内部被调用,并且 func
是通过 obj.func()
被调用的,我们可能会误以为 this
在 getNum.call(this)
中会指向 obj
。然而,由于 func
已经被 bind
到全局对象,this
在 func
内部实际上指向全局对象。因此,getNum.call(this)
中的 this
也指向全局对象。
然而,这里有一个陷阱:在严格模式('use strict';
)下,全局作用域中的 this
不会是 window
对象(在浏览器中),而是 undefined
。但是,由于代码中没有启用严格模式,我们可以假设 this
指向全局对象。
最终,getNum
函数中的 console.log(this.num)
会输出全局对象上的 num
属性,即 2
(因为全局变量 num
被设置为 2
)。
三、html、css、JavaScript篇
1.Math.ceil()
、Math.round()
和 Math.floor()
console.log(Math.ceil(-0.6) + Math.round(-0.6) - Math.floor(-0.6));
输出结果为: 0
在这个表达式中,我们使用了三个数学函数:Math.ceil()
、Math.round()
和 Math.floor()
,它们分别用于向上取整、四舍五入和向下取整。现在,让我们逐一分析这些函数对于输入 -0.6
的行为。
Math.ceil(-0.6)
- 这个函数将
-0.6
向上取整到最接近的整数。 - 因为
-0.6
小于0
,所以向上取整的结果是0
(而不是-0
,因为在 JavaScript 中整数和-0
在数值上是相等的,但通常表示为0
)。
- 这个函数将
Math.round(-0.6)
- 这个函数将
-0.6
四舍五入到最接近的整数。 - 因为
-0.6
的小数部分小于0.5
,所以四舍五入的结果是-1
。
- 这个函数将
Math.floor(-0.6)
- 这个函数将
-0.6
向下取整到最接近的整数。 - 因为
-0.6
小于0
,所以向下取整的结果是-1
。
- 这个函数将
所以原来的代码就相对于: console.log(0 + (-1) - (-1));,结果就是0
我们可以记:
floor是地板,向下取。round是左右,大约,要四舍五入。ceil和floor相对,向上取。
加油加油^_^