单选题
1. 由于前端直接可被用户访问,攻击者可以轻易得到页面和通讯过程中的相关信息,进而进行恶意的攻击,关于其攻击的方式描述正确的有哪些?
正确答案: A B C D
> > A. 假定站点 foo.com 的服务器架设在公司内网,提供了任意站点截图服务 foo.com/screenshot?url=xxx,恶意修改 url 中的值为内网地址,构成 SSRF 攻击,进而造成数据泄露的风险
> > B. 网站 foo.com 提供 POST 方法的 /tansfer/to/xxx 的转账服务,由于未做 CSRF 的防范,被攻击者重复伪造该请求,形成重放攻击,造成经济损失
> > C. 网站 foo.com 使用了非安全的 HTTP 协议,其中转账服务 POST /transfer/to/xxx,转账金额 money 在 payload 上,假定接口层面采用了随机 token 来防范 csrf 攻击,接口参数未做签名校验,此时攻击者通过篡改 money 的数值,构成中间人攻击
> > D. 借助社会工程学的理论基础,基于用户的贪婪等心理,制作一个 qq.com 的”冒牌”中奖页面,诱导用户输入账号密码进行登录,造成隐私的泄露,属于”钓鱼”的网络欺诈行为
答案解析
前端安全相关---CSRF / XSRF(跨站请求伪造) /* 阐述 CSRF 攻击思想
- 1、浏览并登录信任网站(举例:淘宝)
- 2、登录成功后在浏览器产生信息存储(举例:cookie)
- 3、用户在没有登出淘宝的情况下,访问危险网站
- 4、危险网站中存在恶意代码,代码为发送一个恶意请求(举例:购买商品/余额转账)
- 5、携带刚刚在浏览器产生的信息进行恶意请求
- 6、淘宝验证请求为合法请求(区分不出是否是该用户发送)
- 7、达到了恶意目标 */ 防御措施(推荐添加token / HTTP头自定义属性) 涉及到数据修改操作严格使用 post 请求而不是 get 请求 HTTP 协议中使用 Referer 属性来确定请求来源进行过滤(禁止外域) 请求地址添加 token ,使黑客无法伪造用户请求 HTTP 头自定义属性验证(类似上一条) 显示验证方式:添加验证码、密码等
2. 请选出3的颜色
<style>
ul { color: blue !important; }
ul > li { color: green; }
ul li + li { color: red; }
li { color: yellow; }
</style>
<ul><li>1</li><li>2</li><li>3</li></ul>
正确答案: C
A. 蓝色 B. 绿色 C. 红色 D.黄色
答案解析
!important优先级最高,但被后面的继承覆盖掉了 ,
> ul>li 选择父元素是ul的所有li元素
> ul li+li 相邻兄弟选择器 (+) 介于两个选择器之间,当第二个元素紧跟在第一个元素之后,并且两个元素都是属于同一个父元素的子元素,则第二个元素将被选中。而这里并没有指明第一个元素就是最前面的哪一个li,所以每一个li都会找自己的兄弟,结果就是除了第一个li以外的所有li都被选中。
> li 单个元素选择器
对比优先级:3个元素选择器>2个>1个 所以,1、2、3三个元素的颜色分别为green、red、red
3 下列哪项transform属性可以对元素进行旋转()
正确答案: C
A. translate B. scale C. rotate D. skew
答案解析
transform 属性向元素应用 2D 或 3D 转换。该属性允许我们对元素进行旋转、缩放、移动或倾斜。 使用translate属性对元素定义2D转换,scale定义缩放转换,rotate定义旋转,skew定义倾斜转换 参考:CSS transform 属性
4 哪种方式的CSS优先级最高
正确答案: D
A. link引入 B. @import注入 C. 内联方式引入 D. 行内方式引入
答案解析
CSS样式的优先级应该分成四大类
-第一类!important,无论引入方式是什么,选择器是什么,它的优先级都是最高的。
-第二类引入方式,行内样式的优先级要高于嵌入和外链,嵌入和外链如果使用的选择器相同就看他们在页面中插入的顺序,在后面插入的会覆盖前面的。
-第三类选择器,选择器优先级:id选择器>(类选择器 | 伪类选择器 | 属性选择器 )> (后代选择器 | 伪元素选择器 )> (子选择器 | 相邻选择器) > 通配符选择器 。
-第四类继承样式,是所有样式中优先级比较低的。
5 input元素元素可以设置不同的type类型,下面哪种类型不正确()
正确答案: D
A. submit B. file C. password D. option
答案解析
input元素type属性规定 input 元素的类型。包括button、checkbox、file、hidden、image password、radio、reset、submit、text 参考:HTML 标签
6. js数组中不会改变原有数组的方法是()
正确答案: B A. push B. concat C. sort D. shift
答案解析
7. 下列哪种方法不能改变this指向()
正确答案: A A. eval B. apply C. bind D. call
答案解析
apply 、 call 、bind 三者是用来改变函数的this对象的指向的,而eval方法是全局对象的一个函数属性,eval()函数会将传入的字符串当做 JavaScript 代码进行执行。
8. 下列对js箭头函数描述错误的是()
正确答案: C A. 箭头函数没有原型属性 B. 箭头函数不绑定this,会捕获其所在的上下文的this值,作为自己的this值 C. 箭头函数可以作为构造函数,使用new D. 箭头函数不绑定arguments,取而代之用rest参数解决
答案解析
箭头函数有以下特性: 1、this是静态的,this始终指向函数声明时所在作用域下的this的值 2、不能作为构造实例化对象,和new一起用会抛出错误 3、 不能使用arguments变量 4、 没有prototype属性 5、不能用作函数生成器,不能使用yield关键字。
9. 以下代码的运行结果是?
const promiseA = Promise.resolve('a')
promiseA.then((res) => {
console.log(res)
}).then((res) => {
console.log(res)
})
const promiseB = Promise.resolve('b')
promiseB.then((res) => {
console.log(res)
})
promiseB.then((res) => {
console.log(res)
})
正确答案: A
A. a b b undefined
B. a undefined b b
C. a b undefined undefined
D. a b a b
答案解析
promise.then是微任务,会在所有的宏任务执行完之后才会执行,同时需要promise内部的状态发生变化 首先进入Promise,执行该构造函数中的代码 碰到resolve函数, 将promiseA的状态改变为resolved, 并将结果保存下来 碰到promiseA.then这个微任务,将它放入微任务队列 promiseB是一个新的状态为resolved的Promise 宏任务执行完毕,查找微任务队列,发现promiseA.then这个微任务且状态为resolved,执行它。 promiseB.then两个微任务且状态为resolved,执行它 promiseA.then返回非promise,链式调用.then返回undefined
10. 设任务列表有三个异步的任务,即 taskList = [taskA, taskB, taskC],想使用 async/await 配合 forEach 实现串行执行,以下哪个代码是可行的?
正确答案: D
A. async function run () { taskList.forEach(async (task) => await task()) } run()
B. async function run () { taskList.forEach((task) => await task()) } run()
C. function run () { List.forEach(async (task) => await task()) } run()
D. 其余都不对
答案解析:forEach 不会按顺序执行 而是并发执行异步任务
11. 以下代码执行的结果是:
function fun () {
return () => {
return () => {
return () => {
console.log(this.name)
}
}
}
}
var f = fun.call({name: 'foo'})
var t1 = f.call({name: 'bar'})()()
var t2 = f().call({name: 'baz'})()
var t3 = f()().call({name: 'qux'})
正确答案: A
A. foo foo foo
B. bar bar bar
C. qux qux qux
D. bar baz qux
答案解析
箭头函数没有自己的this。this的指向只有一个,就是函数foo的this,这是因为所有的内层函数都是箭头函数,都没有自己的this,它们的this其实都是最外层foo函数的this。所以不管怎么嵌套,t1、t2、t3都输出同样的结果。如果这个例子的所有内层函数都写成普通函数,那么每个函数的this都指向运行时所在的不同对象。
12. 在 React 项目中,绑定 this 通常有如下两种写法:
class LoggingButton extends React.Component {
handleClick = () => {
console.log('this is:', this)
}
render() {
return (
<button onClick={this.handleClick}>
Click me
</button>
)
}
}
class LoggingButton extends React.Component {
constructor () {
super(props)
this.handleClick = this.handleClick.bind(this)
}
handleClick () {
console.log('this is:', this)
}
render() {
return (
<button onClick={this.handleClick}>
Click me
</button>
)
}
}
哪种写法运行效率更高?
正确答案: B
A. 箭头函数式
B. 非箭头函数式
C. 运行效率相同
D. 无法确定
答案解析
箭头函数找this时需要从上下文推断
13. 已知现有一个大小为4初始状态为空的栈,现在有一组数据经过这个栈后,最终的数据顺序是:2 5 4 1 3,问原始的进栈数据不可能是以下的哪组
正确答案: D
A. 1 4 5 2 3
B. 5 2 3 1 4
C. 3 4 5 2 1
D. 4 1 3 5 2
答案解析
栈后进先出,D选项4、1、3、5、2进,2出,5出,3不能在4之后出。
14. 序列{20, 23, 28, 41, 61, 31, 71, 76, 15, 30}构造为完全二叉树,完全二叉树再变为最小堆后,堆所对应的的中序遍历序列可能为()
正确答案: B
A. 76, 23, 41, 61, 20, 30, 31, 15, 28, 71
B. 76, 23, 41, 20, 61, 30, 15, 31, 28, 71
C. 76, 20, 41, 23, 30, 61, 15, 31, 28, 71
D. 76, 23, 20, 41, 61, 15, 31, 20, 28, 71
答案解析
知识点:完全二叉树变成最小堆。再进行中序遍历:76,23,41,20,61,30,15,31,28,71
15. 有如下递归函数 test(n),其时间复杂度为多少?
int test(int n) {
if (n <= 1) return 1;
return (2 * test(n - 1) + 3 * test(n - 2));
}
正确答案: E
A. O(logn)
B. O(nlogn)
C. O(n^2)
D. O(n^3) E. O(2^n)
答案解析
函数的每一层递归调用了两次递归,所以是2^n
16. 假设一个数组采用快速排序,则下面的选项中,不可能是第3趟排序结果的是
正确答案: A C D
A. 4, 8, 6, 10, 12, 16, 14
B. 10, 4, 6, 8, 12, 14, 16
C. 8, 4, 6, 12, 10, 14, 16
D. 4, 8, 6, 12, 10, 16, 14
答案解析
快速排序一趟确定1个或者2个点的最终位置,如果是第一次,确定1个。 第二次以后,如果基点在最左边或者最右边确定1个点最终位置。 如果在中间,那么确定2个点的最终位置,所以ACD全错 只有B 选项,3个点依次都是在最左边,快速排序可能退化成冒泡排序,是正确的
17. 属于同一进程的两个线程 T1和 T2并发执行,共享初值为 0 的全局变量 X。T1和 T2实现对全局变量 x 加 1 的伪代码分别如下:
T1:
temp1=X;
temp1=temp1+1;
X=temp1;
T2:
temp2=X;
temp2=temp2+1;
X=temp2;
2个线程进行到任意一步都能被对方打断,执行另外一个线程的代码,请问在所有可能的执行序列中,使 x 的值为 2 的序列个数有几种?
正确答案: B
A. 1
B. 2
C. 3
D. 4
E. 5
答案解析
T1执行完执行T2或者T2执行完执行T1
18. 某进程创建的若干个线程,这些线程不能共享的是
正确答案: A B A. 程序计数器 B. 某线程的栈指针 C. 进程打开的文件 D. 全局变量 E. 进程的堆空间
答案解析
同一个进程中的线程不共享的部分是线程的堆栈。堆栈是保证线程独立运行所必须的。线程函数可以调用函数,而被调用函数中又是可以层层嵌套的,所以线程必须拥有自己的函数堆栈,使得函数调用可以正常执行,不受其他线程的影响。
19. tcp发送报文数据时,可能将多个数据包合并成一个大的数据包发送,就有可能发生粘包问题。以下可以用来解决这个问题的是?
正确答案: A B D
A. 发送固定长度的消息
B. 包结尾增加分隔符
C. 慢开始算法
D. 把消息分成消息头和消息体,其中消息头上包含长度
E. 利用滑动窗口实现控制
答案解析
TCP粘包现象:发送方发送的多个数据包,到接收方后粘连在一起,导致数据包不能完整的体现发送的数据。
TCP粘包原因分析:导致TCP粘包的原因,可能是发送方的原因,也有可能是接受方的原因。
发送方:由于TCP需要尽可能高效和可靠,所以TCP协议默认采用Nagle算法,以合并相连的小数据包,再一次性发送,以达到提升网络传输效率的目的。这个合并过程就是在发送缓冲区中进行的,也就是说数据发送出来它已经是粘包的状态了。但是接收方并不知道发送方合并数据包,而且数据包的合并在TCP协议中是没有分界线的,所以这就会导致接收方不能还原其本来的数据包。
接收方:TCP是基于“流”的。网络传输数据的速度可能会快过接收方处理数据的速度,这时候就会导致,接收方在读取缓冲区时,缓冲区存在多个数据包。在TCP协议中接收方是一次读取缓冲区中的所有内容,所以不能反映原本的数据信息。(放数据的速度 > 应用层拿数据速度)
解决TCP粘包 分析了产生TCP粘包的原因之后,针对发生的原因,针对性的采取解决方法。
1.禁用Nagle算法:因为TCP协议采用Nagle算法,导致粘包。所以可以禁用Nagle算法。 这种方法虽然能一定程度上解决TCP粘包,但是并不能完全解决问题。因为接收方也是可能造成粘包的原因,这种方法只是发送方有效。而且禁用Nagle算法,一定程度上使TCP传输效率降低了。所以,这并不是一种理想的方法。
2.设置PUSH标志:PUSH是TCP报头中的一个标志位,发送方在发送数据的时候可以设置这个标志位。该标志通知接收方将接收到的数据全部提交给接收进程。这里所说的数据包括与此PUSH包一起传输的数据以及之前就为该进程传输过来的数据。当Server端收到这些数据后,它需要立刻将这些数据提交给应用层进程,而不再等待是否还有额外的数据到达。 设置PUSH标志也不能完全解决TCP粘包,只是降低了接收方粘包的可能性。实际上现在的TCP协议栈基本上都可以自行处理这个问题,而不是交给应用层处理。所以设置PUSH标志,也不是一种理想的方法。
3.自定协议:自定协议,将数据包分为了封包和解包两个过程。在发送方发送数据时,对发送的数据进行封包操作。在接收方接收到数据时对接收的数据包需要进行解包操作。 自定协议时,封包就是为发送的数据增加包头,包头包含数据的大小的信息,数据就跟随在包头之后。当然包头也可以有其他的信息,比如一些做校验的信息。这里主要讨论TCP粘包的问题,所以不考虑其他的。
20. shell脚本中,需求如下:如果 ls /tmp 执行成功输出True,否则输出Fail,下列哪项正确
正确答案: D
A. ls /tmp; [[ $# -eq 0 ]] && echo True || echo Fail
B. ls /tmp; [[ $* -eq 0 ]] && echo True || echo Fail
C. ls /tmp; [[ $0 -eq 0 ]] && echo True || echo Fail
D. ls /tmp; [[ $? -eq 0 ]] && echo True || echo Fail
答案解析
shell中使用符号“$?”来显示上一条命令执行的返回值,如果为0则代表执行成功,其他表示失败。 结合if-else语句实现判断上一个命令是否执行成功。
编程题
21. 实现简易计算器
本题展示了一个简化版的计算器,需求如下:
1、除法操作时,如果被除数为0,则结果为0
2、结果如果为小数,最多保留小数点后两位,如 2 / 3 = 0.67(显示0.67), 1 / 2 = 0.5(显示0.5)
3、请阅读并根据提示补充完成函数initEvent、result和calculate
4、请不要手动修改html和css
5、不要使用第三方插件
body, ul, li,select {
margin: 0;
padding: 0;
box-sizing: border-box;
}
ul,li {list-style: none;}
.calculator {
max-width: 300px;
margin: 20px auto;
border: 1px solid #eee;
border-radius: 3px;
}
.cal-header {
font-size: 16px;
color: #333;
font-weight: bold;
height: 48px;
line-height: 48px;
border-bottom: 1px solid #eee;
text-align: center;
}
.cal-main {
font-size: 14px;
}
.cal-main .origin-value {
padding: 15px;
height: 40px;
line-height: 40px;
font-size: 20px;
text-align: right;
overflow: hidden;
text-overflow:ellipsis;
white-space: nowrap;
}
.cal-main .origin-type,
.cal-main .target-type {
padding-left: 5px;
width: 70px;
font-size: 14px;
height: 30px;
border: 1px solid #eee;
background-color: #fff;
vertical-align: middle;
margin-right: 10px;
border-radius: 3px;
}
.cal-keyboard {
overflow: hidden;
}
.cal-items {
overflow: hidden;
}
.cal-items li {
user-select: none;
float: left;
display: inline-block;
width: 75px;
height: 75px;
text-align: center;
line-height: 75px;
border-top: 1px solid #eee;
border-left: 1px solid #eee;
box-sizing: border-box;
}
li:nth-of-type(4n+1) {
border-left: none;
}
li[data-action=operator] {
background: #f5923e;
color: #fff;
}
.buttons {
float: left;
width: 75px;
}
.buttons .btn {
width: 75px;
background-color: #fff;
border-top: 1px solid #eee;
border-left: 1px solid #eee;
height: 150px;
line-height: 150px;
text-align: center;
}
.btn-esc {
color: #ff5a34;
}
.btn-backspace {
position: relative;
}
<div class="calculator">
<header class="cal-header">简易计算器</header>
<main class="cal-main">
<div class="origin-value">0</div>
<div class="cal-keyboard">
<ul class="cal-items">
<li data-action="num">7</li>
<li data-action="num">8</li>
<li data-action="num">9</li>
<li data-action="operator">÷</li>
<li data-action="num">4</li>
<li data-action="num">5</li>
<li data-action="num">6</li>
<li data-action="operator">x</li>
<li data-action="num">1</li>
<li data-action="num">2</li>
<li data-action="num">3</li>
<li data-action="operator">-</li>
<li data-action="num">0</li>
<li data-action="operator">清空</li>
<li data-action="operator">=</li>
<li data-action="operator">+</li>
</ul>
</div>
</main>
</div>
var Calculator = {
init: function () {
var that = this;
if (!that.isInited) {
that.isInited = true;
// 保存操作信息
// total: Number, 总的结果
// next: String, 下一个和 total 进行运算的数据
// action: String, 操作符号
that.data = {total: 0, next: '', action: ''};
that.bindEvent();
}
},
bindEvent: function () {
var that = this;
// 请补充代码:获取 .cal-keyboard 元素
var keyboardEl = document.querySelector('.cal-keyboard');
keyboardEl && keyboardEl.addEventListener('click', function (event) {
// 请补充代码:获取当前点击的dom元素
var target = event.target;
// 请补充代码:获取target的 data-action 值
var action = target.dataset.action;
// 请补充代码:获取target的内容
var value = target.innerHTML;
if (action === 'num' || action === 'operator') {
that.result(value, action === 'num');
}
});
},
result: function (action, isNum) {
var that = this;
var data = that.data;
if (isNum) {
data.next = data.next === '0' ? action : (data.next + action);
!data.action && (data.total = 0);
} else if (action === '清空') {
// 请补充代码:设置清空时的对应状态
data.total = '';
data.next = '';
data.action = '';
} else if (action === '=') {
if (data.next || data.action) {
data.total = that.calculate(data.total, data.next, data.action);
data.next = '';
data.action = '';
}
} else if (!data.next) {
data.action = action;
} else if (data.action) {
data.total = that.calculate(data.total, data.next, data.action);
data.next = '';
data.action = action;
} else {
data.total = +data.next || 0;
data.next = '';
data.action = action;
}
// ���补充代码:获取 .origin-value 元素
var valEl = document.querySelector('.origin-value');
valEl && (valEl.innerHTML = data.next || data.total || '0');
},
calculate: function (n1, n2, operator) {
n1 = +n1 || 0;
n2 = +n2 || 0;
if (operator === '÷') {
// 请补充代码:获取除法的结果
if(n2==0) return 0;
return Math.round( n1/n2*100)/100;
return 0;
} else if (operator === 'x') {
// 请补充代码:获取乘法的结果
return Math.round(n1*n2*100)/100;
return 0;
} else if (operator === '+') {
// 请补充代码:获取加法的结果
return Math.round((n1+n2)*100)/100;
return 0;
} else if (operator === '-') {
// 请补充代码:获取减法的结果
return Math.round((n1-n2)*100)/100;
return 0;
}
}
};
Calculator.init();
22. 度度熊请你找出两个数a,b, 满足1<=a,b<=n,且lcm(a,b)-gcd(a,b)尽量大并输出最大值,其中,lcm(a,b)表示a,b的最小公倍数,gcd(a,b)表示a,b的最大公约数。
#include<bits/stdc++.h>
using namespace std;
int main(){
long long n;
int max_ = INT_MIN;
while(cin>>n){
cout<<n*(n-1)-1<<endl;//直接这个公式就可以做出来(数学定理),注意取
}
return 0;
}
JS实现V8引擎不支持BigInt,不知道怎么处理长整型,超时了。
let n = parseInt(readline());
//求最大公约数
function gcd(a,b){
let tmp = 0;
while(b!=0){
tmp = a%b;
a=b;
b=tmp;
}
return a;
}
//最小公倍数
function lcm(a,b){
return ((a*b)/gcd(a,b));
}
let max=0;
for(let i=1;i<=n;i++){
for(let j=1;j<=n;j++){
if(i!=j){
let t = lcm(i,j)-gcd(i,j);
if(t>max){
max=t;
}
}
}
}
print(max);
23. 还原数组
老板给度度熊n个数, 每一次从a[i]中取出一个最大的减去n, 其他的n-1个数加上1, 一直重复直到最大的
a[i]<n, 执行次数记为k。老板想知道最少执行多少次操作使得n个数都小于n呢?
let n = parseInt(readline());
let arr = readline().split(' ');
let k=0;
while(true){
let max = 0;
for(let i=0;i<arr.length;i++){
arr[i]=parseInt(arr[i]);
if(arr[i]>arr[max]) max=i;
}
if(arr[max]<n) break;
//当数值很大,n又很小的时候,k会很大,所以k不能一次只加1,会超时
let step = Math.floor(arr[max]/n);
arr[max]-=step*n;
for(let i=0;i<arr.length;i++){
if(i!=max) arr[i]+=step;
}
k+=step;
}
print(k);
解析不正确或者不够详细的欢迎大家指正补充~