前端面试题
1、
由元素内容,border,margin,padding四部分组成盒子模型。
2、
行内元素:a、b、span、img、input、strong、select、label、em、button、textarea
块级元素:div、ul、li、dl、dt、dd、p、h1-h6、blockquote
空元素:即系没有内容的HTML元素,例如:br、meta、hr、link、input、img
3、
src是引入外部资源,比如,js,css。
href是建立和当前元素和跳转页面之间的链接,用于超链接。
4、
1)创建新节点
createDocumentFragment() //创建一个DOM片段
createElement() //创建一个具体的元素
createTextNode() //创建一个文本节点
2)添加、移除、替换、插入
appendChild() //添加
removeChild() //移除
replaceChild() //替换
insertBefore() //插入
3)查找
getElementsByTagName() //通过标签名称
getElementsByName() //通过元素的Name属性的值
getElementById() //通过元素Id,唯一性
5、
[...new Set([1,2,3,1,'a',1,'a'])]
6、
//字符串
var strs = "asdasdadd";
function getmaxstr(str){
if(str.length == 1){return str;}
var newarr = [];
for(var i = 0 ; i<str.length; i++ ){
if(!newarr[str.charAt(i)]){
newarr[str.charAt(i)] = 1;
}else{
newarr[str.charAt(i)] +=1;
}
}
console.log(newarr);
var maxkey='';
var maxvalue=1;//设定一个值
for(var k in newarr){
if(newarr[k]> maxvalue){//根据这个值做判读 将数组中的每个元素 与这个值做比较!
maxvalue = newarr[k];//出现的次数
maxkey = k;//次数最多的 字母
}
}
console.log(maxkey);
return maxvalue;
}
getmaxstr(strs);
//计算数组中每个元素出现的次数
var names = ['Alice', 'Bob', 'Tiff', 'Bruce', 'Alice'];
var countedNames = names.reduce(function (allNames, name) {
console.log(allNames, name)
if (name in allNames) {
allNames[name]++;
}
else {
allNames[name] = 1;
}
return allNames;
}, {});
console.log(countedNames)
7、
function strTrim(str){
if(!String.prototype.trim){
return str.replace(/^\s+/,'').replace(/\s+$/,'');
}else{
return str.trim();
}
}
8、
^[A-Za-z0-9\u4e00-\u9fa5]+@[a-zA-Z0-9_-]+(.[a-zA-Z0-9_-]+)+$
9、
首先在架构项目前思考:
① 如何将一个复杂的页面拆分为一个个独立的页面组件模块
② 如何将分拆后的业务组件模块重新合为一个完整的页面
③ 从重构角度看组件化开发带来的好处
④ 从前端优化的角度看待组件化开发
10、
首先要明白的是什么是物理元素,什么是逻辑元素?title,b,i是物理行为,比如b告诉浏览器我加粗了,而h1,strong,em是逻辑行为,通过语义化方式告诉浏览器我是重要的。
11、
捕获先于冒泡。顶部捕获=>底部冒泡=>第二层捕获=>第二层冒泡。
12、。
viewport 是用户网页的可视区域。
viewport的大小决定了,css中的设置多少像素能刚好占满屏幕。例如,viewport=320,那么设置div的宽度为320px,则div刚好能占满屏幕
viewport的大小由width于scale共同决定,只设置width如果大于屏幕会出现滚动条,rem布局图片,宽高,布局等等,font-size用媒体查询解决。
dpr=物理像素/css像素(window.devicePixelRatio)
13、。
分为强缓存和协商缓存
协商缓存:Etag/If-None-Match
- Etag:web服务器响应请求时,告诉浏览器当前资源在服务器的唯一标识(生成规则由服务器决定,具体下文中介绍)。
- If-None-Match:当资源过期时(使用Cache-Control标识的max-age),发现资源具有Etage声明,则再次向web服务器请求时带上头If-None-Match (Etag的值)。
web服务器收到请求后发现有头If-None-Match 则与被请求资源的相应校验串进行比对,决定返回200或304。
为什么有了Last-Modified还要Etag
你可能会觉得使用Last-Modified已经足以让浏览器知道本地的缓存副本是否足够新,为什么还需要Etag(实体标识)呢?HTTP1.1中Etag的出现主要是为了解决几个Last-Modified比较难解决的问题:
- Last-Modified标注的最后修改只能精确到秒级,如果某些文件在1秒钟以内,被修改多次的话,它将不能准确标注文件的修改时间
- 如果某些文件会被定期生成,当有时内容并没有任何变化,但Last-Modified却改变了,导致文件没法使用缓存
- 有可能存在服务器没有准确获取文件修改时间,或者与代理服务器时间不一致等情形
Etag 的实现
在node 的后端框架express 中引用的是npm包etag,etag 支持根据传入的参数支持两种etag的方式:
一种是文件状态(大小,修改时间),另一种是文件内容的哈希值。
14、。
函数节流是指一定时间内js方法只跑一次。
函数防抖是指频繁触发的情况下,只有足够的空闲时间,才执行代码一次。
15、。
XSS:跨站脚本(Cross-site scripting),通过客户端脚本语言(如JavaScript)在一个论坛发帖中发布一段恶意的JavaScript代码就是脚本注入,如果这个代码内容有请求外部服务器,那么就叫做XSS。
XSS类型:
反射型:经过后端,不经过数据库
存储型:经过后端,经过数据库
DOM:不经过后端
XSS防御:
1.白名单重新整理,用户输入的html,遍历树节点拿到数据,重新构造dom
树,树中标签,属性从白名单中获取,不能识别的则丢弃。
2.过滤器对请求中的特殊字符进行编码转化,如< 转码为 <。.
3.对表单内容做长度校验,长度短,无法输入攻击代码。
CSRF:跨站请求伪造(Cross-site request forgery),冒充用户发起请求,完成一些违背用户意愿的请求(如恶意发帖,删帖,改密码,发邮件等)。
CSRF防御:
1.那就使用token吧,服务端生成随机码给前端。
16、。
target是触发事件对象,冒泡的时候指向子。
currentTarget 恒等于 this ,是绑定事件的对象,冒泡的时候指向父。
17、
- 网络传输:输入网址 =>dns解析ip=>TCP三次握手=>发送http请求=>服务器重定向=>处理请求,返回http响应=>得到数据。
- dom渲染:构建dom树(构建dom节点)=>构建渲染树(解析样式信息)=>布局渲染树(布局dom节点)=>绘制渲染树(绘制dom节点)。
18、。
前端:
var ws = new WebSocket("wss://echo.websocket.org");
ws.onopen = function(evt) {
console.log("Connection open ...");
ws.send("Hello WebSockets!");
};
ws.onmessage = function(evt) {
console.log( "Received Message: " + evt.data);
ws.close();
};
ws.onclose = function(evt) {
console.log("Connection closed.");
};
服务端:
var ws = require("nodejs-websocket");
console.log("开始建立连接...")
var game1 = null,game2 = null , game1Ready = false , game2Ready = false;
var server = ws.createServer(function(conn){
conn.on("text", function (str) {
console.log("收到的信息为:"+str)
if(str==="game1"){
game1 = conn;
game1Ready = true;
conn.sendText("success");
}
if(str==="game2"){
game2 = conn;
game2Ready = true;
}
if(game1Ready&&game2Ready){
game2.sendText(str);
}
conn.sendText(str)
})
conn.on("close", function (code, reason) {
console.log("关闭连接")
});
conn.on("error", function (code, reason) {
console.log("异常关闭")
});
}).listen(8001)
console.log("WebSocket建立完毕")
19、。
① 顺序存储时,相邻数据元素的存放地址也相邻(逻辑与物理统一);要求内存中可用存储单元的地址必须是连续的。
优点:存储密度大(=1),存储空间利用率高。缺点:插入或删除元素时不方便。
②链式存储时,相邻数据元素可随意存放,但所占存储空间分两部分,一部分存放结点值,另一部分存放表示结点间关系的指针。
优点:插入或删除元素时很方便,使用灵活。缺点:存储密度小(<1),存储空间利用率低。
20、。
- 简单请求:get, post
服务端设置:Access-Control-Allow-Origin: "*"
前端不需要。 - 非简单请求:put,delete
服务端设置:Access-Control-Allow-Origin: "*"; 还需要设置method和header
前端需要设置header。
21、。
神奇的Electron。
21、。
如下代码:
class App extends React.Component {
constructor() {
super();
this.state = {
num: 0
}
}
componentDidMount() {
for ( let i = 0; i < 10; i++ ) {
this.setState( {num: this.state.num + 1} );
console.log(this.state.num) // 10次0
}
}
render() {
return ( <div className='App'>
<h1>{this.state.num}</h1>
</div> );
}
}
原因在于,当你传一个普通的对象 this.setState( {num: this.state.num + 1} ) 时,他会进入队列,队列里就做一件事 Object.assign( this.state, stateChange ) ,this.state永远都是之前的0。
100次以后就通过 flush 方法清空队列,包裹flush的是 **Promise.resolve().then(flush) **,使用微异步跳出队列,渲染页面。
- 我们换下代码
componentDidMount() {
for ( let i = 0; i < 10; i++ ) {
this.setState( prevState => {
console.log( prevState.num ); // 打印1-9
return {
num: prevState.num + 1
}
} );
}
}
原来setState支持传函数,这样它内部通过递归方式获取前一个值,就可以做到累加,并且还只会渲染一次页面,多神奇。