京东前端一面高频面试题(附答案)
text-align: center
定宽块状元素: 左右 margin
值为 auto
不定宽块状元素: table
布局,position + transform
/* 方案1 */
.wrap {
text-align: center
}
.center {
display: inline;
/* or */
/* display: inline-block; */
}
/* 方案2 */
.center {
width: 100px;
margin: 0 auto;
}
/* 方案2 */
.wrap {
position: relative;
}
.center {
position: absulote;
left: 50%;
transform: translateX(-50%);
}
----问题知识点分割线----
代码输出结果function Person(name) {
this.name = name
}
var p2 = new Person('king');
console.log(p2.__proto__) //Person.prototype
console.log(p2.__proto__.__proto__) //Object.prototype
console.log(p2.__proto__.__proto__.__proto__) // null
console.log(p2.__proto__.__proto__.__proto__.__proto__)//null后面没有了,报错
console.log(p2.__proto__.__proto__.__proto__.__proto__.__proto__)//null后面没有了,报错
console.log(p2.constructor)//Person
console.log(p2.prototype)//undefined p2是实例,没有prototype属性
console.log(Person.constructor)//Function 一个空函数
console.log(Person.prototype)//打印出Person.prototype这个对象里所有的方法和属性
console.log(Person.prototype.constructor)//Person
console.log(Person.prototype.__proto__)// Object.prototype
console.log(Person.__proto__) //Function.prototype
console.log(Function.prototype.__proto__)//Object.prototype
console.log(Function.__proto__)//Function.prototype
console.log(Object.__proto__)//Function.prototype
console.log(Object.prototype.__proto__)//null
这道义题目考察原型、原型链的基础,记住就可以了。
----问题知识点分割线----
介绍一下 webpack scope hosting作用域提升,将分散的模块划分到同一个作用域中,避免了代码的重复引入,有效减少打包后的代码体积和运行时的内存损耗;
----问题知识点分割线----
原型JavaScript中的对象都有一个特殊的 prototype 内置属性,其实就是对其他对象的引用
几乎所有的对象在创建时 prototype 属性都会被赋予一个非空的值,我们可以把这个属性当作一个备用的仓库
当试图引用对象的属性时会出发get操作,第一步时检查对象本身是否有这个属性,如果有就使用它,没有就去原型中查找。一层层向上直到Object.prototype顶层
基于原型扩展描述一下原型链,什么是原型链,原型的继承,ES5和ES6继承与不同点。
----问题知识点分割线----
display的block、inline和inline-block的区别(1)block: 会独占一行,多个元素会另起一行,可以设置width、height、margin和padding属性;
(2)inline: 元素不会独占一行,设置width、height属性无效。但可以设置水平方向的margin和padding属性,不能设置垂直方向的padding和margin;
(3)inline-block: 将对象设置为inline对象,但对象的内容作为block对象呈现,之后的内联对象会被排列在同一行内。
对于行内元素和块级元素,其特点如下:
(1)行内元素
设置宽高无效;可以设置水平方向的margin和padding属性,不能设置垂直方向的padding和margin;不会自动换行;(2)块级元素
可以设置宽高;设置margin和padding都有效;可以自动换行;多个块状,默认排列从上到下。----问题知识点分割线----
为什么 React 元素有一个 $$typeof 属性目的是为了防止 XSS 攻击。因为 Synbol 无法被序列化,所以 React 可以通过有没有 $$typeof 属性来断出当前的 element 对象是从数据库来的还是自己生成的。如果没有 $$typeof 这个属性,react 会拒绝处理该元素。在 React 的古老版本中,下面的写法会出现 XSS 攻击:// 服务端允许用户存储 JSON
let expectedTextButGotJSON = {
type: 'div',
props: {
dangerouslySetInnerHTML: {
__html: '/* 把你想的搁着 */'
},
},
// ...
};
let message = { text: expectedTextButGotJSON };
// React 0.13 中有风险
<p>
{message.text}
</p>
----问题知识点分割线----
懒加载与预加载的区别这两种方式都是提高网页性能的方式,两者主要区别是一个是提前加载,一个是迟缓甚至不加载。懒加载对服务器前端有一定的缓解压力作用,预加载则会增加服务器前端压力。
懒加载也叫延迟加载,指的是在长网页中延迟加载图片的时机,当用户需要访问时,再去加载,这样可以提高网站的首屏加载速度,提升用户的体验,并且可以减少服务器的压力。它适用于图片很多,页面很长的电商网站的场景。懒加载的实现原理是,将页面上的图片的 src 属性设置为空字符串,将图片的真实路径保存在一个自定义属性中,当页面滚动的时候,进行判断,如果图片进入页面可视区域内,则从自定义属性中取出真实路径赋值给图片的 src 属性,以此来实现图片的延迟加载。预加载指的是将所需的资源提前请求加载到本地,这样后面在需要用到时就直接从缓存取资源。 通过预加载能够减少用户的等待时间,提高用户的体验。我了解的预加载的最常用的方式是使用 js 中的 image 对象,通过为 image 对象来设置 scr 属性,来实现图片的预加载。----问题知识点分割线----
对类数组对象的理解,如何转化为数组一个拥有 length 属性和若干索引属性的对象就可以被称为类数组对象,类数组对象和数组类似,但是不能调用数组的方法。常见的类数组对象有 arguments 和 DOM 方法的返回结果,函数参数也可以被看作是类数组对象,因为它含有 length属性值,代表可接收的参数个数。
常见的类数组转换为数组的方法有这样几种:
通过 call 调用数组的 slice 方法来实现转换Array.prototype.slice.call(arrayLike);
通过 call 调用数组的 splice 方法来实现转换Array.prototype.splice.call(arrayLike, 0);
通过 apply 调用数组的 concat 方法来实现转换Array.prototype.concat.apply([], arrayLike);
通过 Array.from 方法来实现转换Array.from(arrayLike);
----问题知识点分割线----
CSS3的新特性transition
:过渡transform
: 旋转、缩放、移动或倾斜animation
: 动画gradient
: 渐变box-shadow
: 阴影border-radius
: 圆角word-break
: normal|break-all|keep-all
; 文字换行(默认规则|单词也可以换行|只在半角空格或连字符换行)text-overflow
: 文字超出部分处理text-shadow
: 水平阴影,垂直阴影,模糊的距离,以及阴影的颜色。box-sizing
: content-box|border-box
盒模型媒体查询 @media screen and (max-width: 960px) {}
还有打印print
----问题知识点分割线----
Ajax它是一种异步通信的方法,通过直接由 js 脚本向服务器发起 http 通信,然后根据服务器返回的数据,更新网页的相应部分,而不用刷新整个页面的一种方法。面试手写(原生):
//1:创建Ajax对象
var xhr = window.XMLHttpRequest?new XMLHttpRequest():new ActiveXObject('Microsoft.XMLHTTP');// 兼容IE6及以下版本
//2:配置 Ajax请求地址
xhr.open('get','index.xml',true);
//3:发送请求
xhr.send(null); // 严谨写法
//4:监听请求,接受响应
xhr.onreadysatechange=function(){
if(xhr.readySate==4&&xhr.status==200 || xhr.status==304 )
console.log(xhr.responsetXML)
}
jQuery写法
$.ajax({
type:'post',
url:'',
async:ture,//async 异步 sync 同步
data:data,//针对post请求
dataType:'jsonp',
success:function (msg) {
},
error:function (error) {
}
})
promise 封装实现:
// promise 封装实现:
function getJSON(url) {
// 创建一个 promise 对象
let promise = new Promise(function(resolve, reject) {
let xhr = new XMLHttpRequest();
// 新建一个 http 请求
xhr.open("GET", url, true);
// 设置状态的监听函数
xhr.onreadystatechange = function() {
if (this.readyState !== 4) return;
// 当请求成功或失败时,改变 promise 的状态
if (this.status === 200) {
resolve(this.response);
} else {
reject(new Error(this.statusText));
}
};
// 设置错误监听函数
xhr.onerror = function() {
reject(new Error(this.statusText));
};
// 设置响应的数据类型
xhr.responseType = "json";
// 设置请求头信息
xhr.setRequestHeader("Accept", "application/json");
// 发送 http 请求
xhr.send(null);
});
return promise;
}
----问题知识点分割线----
VDOM:三个 part虚拟节点类,将真实DOM
节点用 js
对象的形式进行展示,并提供 render
方法,将虚拟节点渲染成真实 DOM
节点 diff
比较:对虚拟节点进行 js
层面的计算,并将不同的操作都记录到 patch
对象re-render
:解析 patch
对象,进行 re-render
补充1��VDOM 的必要性?
创建真实DOM的代价高 :真实的DOM
节点 node
实现的属性很多,而 vnode
仅仅实现一些必要的属性,相比起来,创建一个 vnode
的成本比较低。触发多次浏览器重绘及回流 :使用 vnode
,相当于加了一个缓冲,让一次数据变动所带来的所有 node
变化,先在 vnode
中进行修改,然后 diff
之后对所有产生差异的节点集中一次对 DOM tree
进行修改,以减少浏览器的重绘及回流。补充2:vue 为什么采用 vdom?
引入Virtual DOM
在性能方面的考量仅仅是一方面。性能受场景的影响是非常大的,不同的场景可能造成不同实现方案之间成倍的性能差距,所以依赖细粒度绑定及 Virtual DOM
哪个的性能更好还真不是一个容易下定论的问题。Vue
之所以引入了 Virtual DOM
,更重要的原因是为了解耦 HTML
依赖,这带来两个非常重要的好处是:不再依赖 HTML
解析器进行模版解析,可以进行更多的 AOT
工作提高运行时效率:通过模版 AOT
编译,Vue
的运行时体积可以进一步压缩,运行时效率可以进一步提升;可以渲染到 DOM
以外的平台,实现 SSR
、同构渲染这些高级特性,Weex
等框架应用的就是这一特性。综上,Virtual DOM
在性能上的收益并不是最主要的,更重要的是它使得 Vue
具备了现代框架应有的高级特性。
----问题知识点分割线----
SSL 连接断开后如何恢复一共有两种方法来恢复断开的 SSL 连接,一种是使用 session ID,一种是 session ticket。
通过session ID
使用 session ID 的方式,每一次的会话都有一个编号,当对话中断后,下一次重新连接时,只要客户端给出这个编号,服务器如果有这个编号的记录,那么双方就可以继续使用以前的秘钥,而不用重新生成一把。目前所有的浏览器都支持这一种方法。但是这种方法有一个缺点是,session ID 只能够存在一台服务器上,如果我们的请求通过负载平衡被转移到了其他的服务器上,那么就无法恢复对话。
通过session ticket
另一种方式是 session ticket 的方式,session ticket 是服务器在上一次对话中发送给客户的,这个 ticket 是加密的,只有服务器能够解密,里面包含了本次会话的信息,比如对话秘钥和加密方法等。这样不管我们的请求是否转移到其他的服务器上,当服务器将 ticket 解密以后,就能够获取上次对话的信息,就不用重新生成对话秘钥了。
----问题知识点分割线----
async/awaitGenerator
函数的语法糖。有更好的语义、更好的适用性、返回值是 Promise
。await 和 promise 一样,更多的是考笔试题,当然偶尔也会问到和 promise 的一些区别。await 相比直接使用 Promise 来说,优势在于处理 then 的调用链,能够更清晰准确的写出代码。缺点在于滥用 await 可能会导致性能问题,因为 await 会阻塞代码,也许之后的异步代码并不依赖于前者,但仍然需要等待前者完成,导致代码失去了并发性,此时更应该使用 Promise.all。一个函数如果加上 async ,那么该函数就会返回一个 Promiseasync => *
await => yield
// 基本用法
async function timeout (ms) {
await new Promise((resolve) => {
setTimeout(resolve, ms)
})
}
async function asyncConsole (value, ms) {
await timeout(ms)
console.log(value)
}
asyncConsole('hello async and await', 1000)
下面来看一个使用 await
的代码。
var a = 0
var b = async () => {
a = a + await 10
console.log('2', a) // -> '2' 10
a = (await 10) + a
console.log('3', a) // -> '3' 20
}
b()
a++
console.log('1', a) // -> '1' 1
首先函数b
先执行,在执行到 await 10
之前变量 a
还是 0
,因为在 await
内部实现了 generators
,generators
会保留堆栈中东西,所以这时候 a = 0
被保存了下来因为 await
是异步操作,遇到await
就会立即返回一个pending
状态的Promise
对象,暂时返回执行代码的控制权,使得函数外的代码得以继续执行,所以会先执行 console.log('1', a)
这时候同步代码执行完毕,开始执行异步代码,将保存下来的值拿出来使用,这时候 a = 10
然后后面就是常规执行代码了优缺点:
async/await
的优势在于处理 then 的调用链,能够更清晰准确的写出代码,并且也能优雅地解决回调地狱问题。当然也存在一些缺点,因为 await 将异步代码改造成了同步代码,如果多个异步代码没有依赖性却使用了 await 会导致性能上的降低。async原理
async/await
语法糖就是使用Generator
函数+自动执行器来运作的// 定义了一个promise,用来模拟异步请求,作用是传入参数++
function getNum(num){
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(num+1)
}, 1000)
})
}
//自动执行器,如果一个Generator函数没有执行完,则递归调用
function asyncFun(func){
var gen = func();
function next(data){
var result = gen.next(data);
if (result.done) return result.value;
result.value.then(function(data){
next(data);
});
}
next();
}
// 所需要执行的Generator函数,内部的数据在执行完成一步的promise之后,再调用下一步
var func = function* (){
var f1 = yield getNum(1);
var f2 = yield getNum(f1);
console.log(f2) ;
};
asyncFun(func);
在执行的过程中,判断一个函数的promise
是否完成,如果已经完成,将结果传入下一个函数,继续重复此步骤每一个 next()
方法返回值的 value
属性为一个 Promise
对象,所以我们为其添加 then
方法, 在 then
方法里面接着运行 next
方法挪移遍历器指针,直到 Generator
函数运行完成----问题知识点分割线----
短轮询、长轮询和 WebSocket 间的区别1. 短轮询
短轮询的基本思路:
浏览器每隔一段时间向浏览器发送 http 请求,服务器端在收到请求后,不论是否有数据更新,都直接进行 响应。这种方式实现的即时通信,本质上还是浏览器发送请求,服务器接受请求的一个过程,通过让客户端不断的进行请求,使得客户端能够模拟实时地收到服务器端的数据的变化。优缺点
版权声明
本文仅代表作者观点,不代表博信信息网立场。