前面的话
题目都是选自牛客。
解析
(1) 跨域请求中,需要设置哪个属性为true,才能携带cookie信息?
解析:跨域请求要想带上cookie,必须将withCredential属性设置为true。
例如ajax请求:
$.ajax({
type:"post",
url:"",
xhrFields:{
withCredentials:true
}
// ...
})
(2) 下面代码的结果是什么?
console.log(1);
new Promise(function (resolve, reject){
reject();
resolve();
}).then(function(){
console.log(2);
}, function(){
console.log(3);
});
console.log(4);
解析:这题考查异步,Promise.then是微任务属于异步,而console.log(1)、console.log(4)都是同步,所以先打印1、4。最后看Promise对象。
Promise对象只有三种结果:Pending(进行中)、Fulfilled(已成功)、Rejected(已失败)。对象的状态变化只有两种:从Pending —— Fulfilled(Resolved);从Pending —— Rejected。
构造函数Promise接受一个函数作为参数,并且该函数有两个参数resolve 和 reject。resolve是异步操作成功时调用,reject是异步操作失败时调用。Promise实例对象的then方法中的两个函数分别指定Resolved状态(成功)和Rejected状态(失败)的回调函数。
回到本题:在Promise构造函数中reject()比resolve()先执行,会执行Rejected状态的回调,即console.log(3),打印3。前面说了Promise对象状态改变只有两种情况,执行reject()后,Promise对象状态变为了Rejected。所以后面的resolve()不会执行。最终结果为:1、4、3。
(3)下列代码的执行结果是什么?
var a = 1
function fn1() {
console.log(this.a)
}
const fn2 = ()=> {
console.log(this.a)
}
const obj = {
a: 10,
fn1: fn1,
fn2: fn2
}
fn1()
fn2()
obj.fn1()
obj.fn2()
解析:本题考查this指向问题,以及箭头函数中this指向。
箭头函数中的this始终指向其父级作用域中的this。换句话说,箭头函数会捕获其所在的上下文的this值,作为自己的this值。在箭头函数中调用 this 时,仅仅是简单的沿着作用域链向上寻找,找到最近的一个 this 拿来使用,它与调用时的上下文无关。
- fn1()中,this指向window,所以打印1
- fn2()中,fn2是一个箭头函数,this指向作用域链上最近的this,这里为window,所以打印1.
- obj.fn1()中,fn1是一个普通函数,this指向obj,即obj.a。所以打印10。
- obj.fn2()中,fn2是一个箭头函数,this会继承父级作用域中的this,为window。所以打印1.
- 本题最终结果:1 、1、10、1
(4)下面代码的结果的结果是什么?
const a = {
valueOf() {
return 'valueOf'
},
toString() {
return 'toString'
},
get() {
return 'get'
}
}
alert(a)
这题考查valueOf()与toString()的区别。
在不重写这两个方法时:
- toString()方法:返回对象的字符串表示
- valueOf()方法:返回指定对象的原始值。
默认情况,会调用toString()方法。例如:
var cc = {};
alert(cc);// [object Object]
var fun = function() {} ;
alert(fun);// function() {}
var arr = [1];
alert(arr); // 1
从上面的代码来看,默认情况会调用对象的toString()方法,返回对象的字符串表示。
下面看看重写对象的toString()与valueOf()方法,并且同时存在时会发生什么:
var bbb = {
i: 10,
toString: function() {
console.log('toString');
return this.i;
},
valueOf: function() {
console.log('valueOf');
return this.i;
}
}
alert(bbb);// 10 toString
alert(+bbb); // 10 valueOf
alert(''+bbb); // 10 valueOf
alert(String(bbb)); // 10 toString
alert(Number(bbb)); // 10 valueOf
alert(bbb == '10'); // true valueOf
二者并存的情况下,在数值运算中,优先调用了valueOf,字符串运算中,优先调用了toString。而’ '+bbb是字符串操作,为啥也是调用valueOf,那是因为,存在操作符,valueOf的优先级高于toString。
回到本题: alert(obj)不存在数值运算,和其他操作符,所以默认调用toString方法。
结果为:toString。
(5) 小易有个32G字节的文件,需要从电脑1传送到电脑2,假设两者之间是1024Mbit/s的网络,那么需要多久能传输完?
解析:本题考查计算单位之间转换。
- 1Byte = 8 Bit
- 1KB = 1024 byte
- 1MB = 1024 KB
- 1GB = 1024MB
(6) 下面代码的执行结果?
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'})
解析:本题考查箭头函数的this问题。
前面说过箭头函数的this是继承父级作用域的this,而不是指向调用者。
- var f = fun.call({name: ‘foo’})这一句 会将this指向{name: ‘foo’}。
- var t1 = f.call({name: ‘bar’})()(),执行f(),之后返回的都是箭头函数,所以直到最后,父级作用域上的this还是指向{name: ‘foo’}。打印:foo。
- 下面两个同样,因为t1、t2、t3都是箭头函数,使用call()方法不能改变this指向,作用域链上最近的this还是指向{name:‘foo’}。
- 本题结果:foo foo foo
(6)从输入url到页面展现发生了什么?其中在页面渲染以及网络请求响应的性能优化方面,我们分别可以做哪些优化工作?
解析:
问题一:从输入url到页面展现发生了什么?
1、域名解析 ip地址
2、tcp连接
3、http请求
4、http响应
5、断开tcp连接
6、渲染页面
问题二:
在页面渲染方面的性能优化:
(1) 防止阻塞渲染
- 将css文件放在首部,提前加载。通常情况下 CSS 被认为是阻塞渲染的资源,在CSSOM 构建完成之前,页面不会被渲染,放在顶部让样式表能够尽早开始加载。
- 将js文件放在底部,防止阻塞html的解析。
(2)减少重绘和回流
- 将动画效果应用到position属性为absolute或fixed的元素上,避免影响其他元素的布局,这样只是一个重绘,而不是回流
- CSS3 硬件加速(GPU加速)
- js尽量少访问dom节点和css属性
还有很多,可以参照谈谈什么是重绘与回流,以及怎么优化
网络请求方面的性能优化:
(1)静态资源
-
拼接、合并、压缩、制作雪碧图:减少http请求数和减少包体积
拼接、合并、压缩: 在现代的前端工程化开发流程中, 使用webpack或者gulp等打包工具对资源(js、css、图片等)进行打包、合并、去重、压缩。
雪碧图:对于图片资源,可以制作雪碧图,将页面上的小图标集成到一张图片上。有利于减少图片的请求数,降低网络延迟。
-
CDN资源分发
将一些静态资源文件托管在第三方CDN服务中,一方面减少服务器压力;另一方面,CDN优势在于能够实时地根据网络流量和各节点的连接、负载状况以及用户的距离和响应时间等综合信息将用户的请求重新导向离用户最近的服务节点上,保证资源的加载速度和稳定性。 -
缓存
缓存的范围很广:DNS解析缓存、代理服务器缓存、客户端的浏览器本地缓存、服务器端的缓存 -
分片:将资源分布到不同的主机。为了突破同一台主机建立tcp连接的数量限制,一般是6~8个。现代网站的资源数量有50 ~100个很常见,将资源分布到不同主机上,可以建立更多的tcp请求,降低请求耗时,从而提升网页速度。
-
升级协议
升级网络协议,例如使用HTTP2.0代替HTTP1.1
(2)业务数据
- 首屏直出
首屏渲染速度对于提升用户体验很重要。所以用户进来的页面,可以使用SSR服务器渲染)方式来加快首屏渲染的速度。 - 接口合并
代理服务器实现请求合并,即后台的接口只需要保证健壮和分布式,而由nodejs(当然也可以使用其他语言)建设一层代理中间层,流程如下图所示:
前端只需要按找约定的规则,向代理服务器发起一次请求,由代理服务器向接口服务器发起三次请求,再将目标数据返回给客户端。这样做的好处是:一方面是代理服务器代替前端做了接口合并,减少了前端的请求数量;另一方面代理服务器可以脱离HTTP的限制,使用更高效的通信协议与服务器通信;
本题解析参考:页面渲染机制与性能优化