14、介绍下观察者模式和订阅-发布模式的区别,各自适用于什么场景?
答案:观察者模式中主体和观察者是互相感知的,发布-订阅模式是借助第三方来实现调度的,发布者和订阅者之间互不感知:
- 观察者模式就好像 个体奶农和个人的关系。奶农负责统计有多少人订了产品,所以个人都会有一个相同拿牛奶的方法。奶农有新奶了就负责调用这个方法;
- 发布-订阅模式就好像报社, 邮局和个人的关系,报纸的订阅和分发是由邮局来完成的。报社只负责将报纸发送给邮局;
观察者模式为一刀切模式,对所有订阅者一视同仁;
发布订阅模式 可以戴有色眼镜,有一层过滤或者说暗箱操作 。
15、全局作用域中,用 const 和 let 声明的变量不在 window 上,那到底在哪里?如何去获取?
答案:首先我们要知道,在ES5中,顶层对象的属性和全局变量是等价的,var 命令和 function 命令声明的全局变量,自然也是顶层对象:
var a = 12;
function f() {};
console.log(window.a); // 12
console.log(window.f); // f() {}
但ES6规定,var 命令和 function 命令声明的全局变量,依旧是顶层对象的属性,但 let命令、const命令、class命令声明的全局变量,不属于顶层对象的属性:
let aa = 1;
const bb = 2;
console.log(window.aa); // undefined
console.log(window.bb); // undefined
在全局作用域中,用 let 和 const 声明的全局变量并没有在全局对象中,只是一个块级作用域(Script)中,想要获取,直接在块作用域中获取,既然不属于顶层对象,那就不加 window(global)就可以获取到。
16、cookie 和 token 都存放在 header 中,为什么不会劫持 token?
答案:
cookie:登陆后后端生成一个sessionid放在cookie中返回给客户端,并且服务端一直记录着这个sessionid,客户端以后每次请求都会带上这个sessionid,服务端通过这个sessionid来验证身份之类的操作。所以别人拿到了cookie拿到了sessionid后,就可以完全替代你。
token:登陆后后端不返回一个token给客户端,客户端将这个token存储起来,然后每次客户端请求都需要开发者手动将token放在header中带过去,服务端每次只需要对这个token进行验证就能使用token中的信息来进行下一步操作了。
xss:用户通过各种方式将恶意代码注入到其他用户的页面中。就可以通过脚本获取信息,发起请求,之类的操作。
csrf:跨站请求攻击,简单地说,是攻击者通过一些技术手段欺骗用户的浏览器去访问一个自己曾经认证过的网站并运行一些操作(如发邮件,发消息,甚至财产操作如转账和购买商品)。由于浏览器曾经认证过,所以被访问的网站会认为是真正的用户操作而去运行。这利用了web中用户身份验证的一个漏洞:简单的身份验证只能保证请求发自某个用户的浏览器,却不能保证请求本身是用户自愿发出的。csrf并不能够拿到用户的任何信息,它只是欺骗用户浏览器,让其以用户的名义进行操作。
csrf例子:假如一家银行用以运行转账操作的URL地址如下: http://www.examplebank.com/withdraw?account=AccoutName&amount=1000&for=PayeeName
那么,一个恶意攻击者可以在另一个网站上放置如下代码: <img src="<http://www.examplebank.com/withdraw?account=Alice&amount=1000&for=Badman>">
如果有账户名为Alice的用户访问了恶意站点,而她之前刚访问过银行不久,登录信息尚未过期,那么她就会损失1000资金。
以上面的csrf攻击为例:
对cookie来说,用户点击了链接,cookie未失效,导致发起请求后后端以为是用户正常操作,于是进行扣款操作;但是对于token来说,用户点击链接,浏览器不会自动带上token,所以即使发送了请求,后端的token验证也不会通过,所以不进行扣款操作。
但是注意,对于xss来说,token和cookie都没用。xss劫持cookie或者localStorage,从而伪造用户身份相关信息。前端层面token会存在哪儿?不外乎cookie localStorage sessionStorage,这些东西都是通过js代码获取到的。解决方案:过滤标签<>,不信任用户输入, 对用户身份等cookie层面的信息进行http-only处理。
17、请把俩个数组 [A1, A2, B1, B2, C1, C2, D1, D2] 和 [A, B, C, D],合并为 [A1, A2, A, B1, B2, B, C1, C2, C, D1, D2, D]
答案:
const arr1 = ['A1', 'A2', 'B1', 'B2', 'C1', 'C2', 'D1', 'D2'];
const arr2 = ['A', 'B', 'C', 'D'];
const ret = [];
let tmp = arr2[0];
let j = 0;
for (let i = 0; i < arr1.length; i++) {
if (tmp === arr1[i].charAt(0)) { // charAt() 方法用于返回指定索引处的字符
ret.push(arr1[i])
} else {
ret.push(tmp);
ret.push(arr1[i]);
tmp = arr2[++j]
}
if (i === arr1.length - 1) {
ret.push(tmp)
}
}
console.log(ret)