笔试题记录
1. 空元素 Empty Element
(滴滴笔试)
空元素是
HTML/SVG
里的不可能存在子节点的元素。
个人理解就是:自闭和标签
HTML
中的空元素:
<br/>
<hr>
<img>
<input/>
<link>
<meta>
<area>
<source>
<track>
<wbr>
<base>
<param>
<keygen>
<col>
<colgroup>
<command>
<embed>
2. <video src="movie.ogg" controls="controls">
(滴滴笔试)
<video>
video是闭合标签</video>
,不用必须指定宽高
类似,<audio></audio>
也是闭合标签
video
和audio
都有的属性:
autoplay
loop
src
controls
3. 否定伪类 :not()
伪类
pseudo Class
为一个元素的特定状态应用样式
伪元素pseudo Element
为一个元素的特定部分应用样式
伪类:
:active
:hover
:focus
:visited
:enabled
disabled
:invalid
:lang()
:not()
:optional
:out-of-range
:readonly
:read-write
:required
:root
:scope
:target
:valid
:checked
:default
:defined
:empty
:first
:focus-within
:host
:indeterminate
:in-range
:left
:link
- 长子
first-child
嫡长子first-of-type
幼子:last-child
嫡幼子:last-of-type
- 自定义规则
:nth-child()
:nth-of-type()
从后往前:nth-last-child()
:nth-last-of-type()
- 独子
:only-child
:only-of-type
伪元素:
::after
::before
::first-letter
::first-line
::selection
::slotted
4. 状态码 (头条面试)
301 永久移动
302 临时移动
304 Not Modified
502 Bad Gateway
503 Service Unavailable
5. 获取元素?getElementByLabel()?
document.getXXX
系列:
getElementById()
// idgetElementsByClassName()
// 类名getElementsByName()
// name属性getElementsByTagName()
// 标签名getElementsByTagNameNS()
// 使用命名空间的XML文档
获取元素还有Selector
:
document.queySelector()
document.querySelectorAll()
6. GET和POST区别 (腾讯、头条面试)
GET - 从指定的资源请求数据
POST - 向指定资源提交要被处理的数据
GET:
- 请求可被缓存
- 请求保留在浏览器历史记录中
- 可被收藏成书签
- 不应用于敏感数据
- 请求有长度限制
- 只应当用于取数据
- 请求参数只能是ASCII码,所以需要encode编码
POST:
- 请求不会被缓存
- 不保留在历史记录中
- 不能被收藏成书签
- 对数据长度无要求
7. 死锁
死锁产生的四个必要条件:
- 互斥条件
- .不可剥夺条件
- 请求和保持条件
- 循环等待条件
死锁预防:
- 破坏“不可剥夺”:一个进程不能获得所需的全部资源便处于等待状态,等待期间他占有的资源被隐式地释放
- 破坏“请求与保持”:一、静态分配:每个进程在开始执行时就申请他所需的全部资源。二、动态分配:每个进程在申请所需资源时它本身不占用系统资源。
- 破坏“循环等待”:按编号顺序进行
8. CSS优先级问题(伪类+属性选择器)
<div class="main"> <div class="test"></div> </div> <style> .main div{ width: 200px; height: 200px; border: 1px red solid; } .test { border: 1px green solid; } </style>
.main div
要比.test
优先级高
ICE(Id > Class > Element)
<div class="text"> <p>伪类与类的优先级相等</p> <p>所以后者起作用</p> </div> <style> .text p{ color: red; } p:first-child{ color: green; } </style>
类和伪类优先级一致;元素和伪元素优先级一致
<div> <p class="text" id="zpj">属性选择器</p> </div> <style> p[class="text"]{ color: green; } [id="zpj"]{ color: blue; } .text{ color: red; } </style>
属性选择器的优先级等于类选择器
9. innerHTML
和innerText
共同点是都可以读写。
text表文本;html表格式;inner是标签内部;outer包含标签本身;value只用于input和textarea
innerText
: 只要文本innerHTML
: HTML格式outerText
:包含标签自己outerHTML
:包含标签自己value
: input和textarea
10. 箭头函数
- 箭头函数更适用于那些本来需要匿名函数的地方
- 箭头函数不能用作构造函数
- 没有自己的this、arguments、super和new.target
- 箭头函数不会创建自己的
this
,只能从自己的作用域链上一层继承this - 使用剩余参数相较于使用
arguments
是更好的选择 - 箭头函数不要用作对象方法,this指向问题
- 箭头函数没有
prototype
属性 - 箭头函数不能使用
yield
关键字,不能用作生成器
高级用法:
// 加括号的函数体返回对象字面量 () => ({name: 'zpj'}); // 支持剩余参数和默认参数 (a =1,b =true,...rest) => {}; // 支持参数列表解构 ([a,b]=[1,2], {name: c} ={name: a+b}) => a+b+c;
说到this,提一下setTimeout
setTimeout
调用的代码运行在与所在函数完全分离的执行环境上。这会导致代码中的this指向window
bind改变this指向,只改变一次
new.target
:在普通函数调用中,指向undefined; 在类的构造方法中,指向被new执行的构造函数
// 1. 使用new.target来保证构造函数正确使用 function Foo(){ if(!new.target) throw "Foo() must be called with new"; // construction } // 2. 使用instanceof & new操作符干了什么(作业帮面试) function User(name, pw){ var self = this instanceof User ? this : Object.create(User.prototype); self.name = name; self.password = pw; return self; }
11. 能冒泡的事件
先说
on
和addEventListener/attachEvent
的区别
on+事件
,只能绑定一个事件,后面的会覆盖前面的addEventListener(eventName, function, useCapture)
可以绑定多个事件- 移除事件有
removeEventListener/detachEvent()
事件模型一般分为
capture -> target -> bubble
的过程
注意到useCapture
,true
是在捕获阶段处理事件,默认false
是在冒泡阶段处理事件
有的事件没有冒泡过程。每个event
都有一个event.bubles
属性,可以知道他是否可以冒泡。
不冒泡的事件有:
abort
blur
error
focus
load
mouseenter
mouseleave
resize
unload
12. 组合选择器 (美团面试)
A,B
任意选择器, 所有A or BA B
后代选择器, A后代中的BA>B
子选择器,A的第一代BA+B
毗邻选择器,弟弟选择器,next-sibling,A后的第一个B
13. <input/>
标签的type类型 (头条面试)
button
checkbox
color
date
datetime
datetime-local
email
file
hidden
image
month
number
password
radio
range
reset
search
submit
tel
text
ime
url
week
注意: 没有textarea
, <textarea> </textarea>
是独立的一个标签
14. Array.from()
Object.keys()
(京东面试)
一、 Array.from(arrayLike, mapFunc, thisArg)
- 字符串、set、map、arguments
Array.from('foo'); // ['f', 'o', 'o'] let s = new Set(['foo', window]); Array.from(s); // ["foo", Window] let m = new Map([[1,2],[3,4],[5,6]]); Array.from(m); // [[1, 2], [2, 4], [4, 8]] function f(){ return Array.from(arguments); } f(1,2,3); // [1,2,3]
如何将
arguments
转化成真正的数组:Array.from(arguments)
Array.prototype.slice.call(arguments)
说到arguments
,讲一下arguments
和函数形参的联系
在非严格模式下,
arguments
指向的是形参的引用地址,一个改变,另一个跟着改变;
严格模式下,arguments
是静态副本,二者互相独立。
function add(a,b){ console.log(a,b); // 1 2 console.log(arguments); // 1 2 arguments[0] = 10; console.log(a,b); // 10 2 console.log(arguments); // 10 2 return a+b; } add(1,2); // 12 // 严格模式 'use strict' function add(a,b){ console.log(a,b); // 1 2 console.log(arguments); // 1 2 arguments[0] = 10; console.log(a,b); // 1 2 console.log(arguments); // 10 2 return a+b; } add(1,2); // 3
二、Object.keys(obj)
- 遍历自身的可枚举属性,顺序和
for-in
一致,区别在于for-in会遍历原型链上的可枚举属性// simple Array Object.keys([1,2,3]); // ['0', '1', '2'] // array like object Object.keys({0: 1, 1: 2, 2: 3}); // ["0", "1", "2"] // array like object with random key ordering Object.keys({100: 'a', 2: 'b', 7: 'c'}); // ["2", "7", "100"]
【注意】:想要拿到不可枚举属性,使用getOenPropertyNames()
也就是说,遍历对象属性的三种方法:
for-in
:遍历自身和原型链上的可枚举属性,一般配合hasOwnProperty()
使用Object.keys()
:遍历自身的可枚举属性Object.getOwnPropertyNames()
:遍历自身的所有属性,包括不可枚举属性
15. instanceof
运算符 typeof
操作符 (京东面试)
一、 instanceof
测试构造函数的prototype属性是否出现在对象的原型链中的任何位置
object instanceof constructor
检测constructor.prototype
是否存在于object
的原型链上
实际上就是在问:constructor.prototype.isPrototypeOf(object);
function Car(){}; var c = new Car(); c instanceof Car; c instanceof Object; // Object.prototype.isPrototypeOf(c);
二、 typeof
返回操作数的类型
类型 | 结果 |
---|---|
Undefined | "undefined" |
Null | "object" |
Boolean | "boolean" |
Number | "number" |
BigInt | "bigint" |
String | "string" |
Symbol | "symbol" |
Function | "function" |
其余复杂对象(如:数组,Set, Map) | "object" |
typeof NaN === "number" typeof Number(1) === "number" typeof null === "object" typeof /s/g === "object"
三、 Object.prototype.toString.call()
- 判断类型最全面的方法:返回值为
"[object Type]"
Object.prototype.toString.call(1); // "[object Number]" Object.prototype.toString.call(/s/); // "[object RegExp]"
四、Array.isArray()
判断数组
五、isNaN()
判断NaN
16. 严格模式
问题 | 严格模式 | 非严格模式 |
---|---|---|
with | 禁止with | 不禁止 |
变量声明 | 变量必须声明 | 未声明的变量将隐式声明为全局变量 |
this 指向 | 普通函数(非方法、非构造函数)中的this 指向undefined | this 指向全局对象 |
this 指向 | call 和apply 传入null 和undefined ,保持原样 | 会被转换成全局对象 |
不可扩展 | 给只读属性和不可扩展对象创建新成员,抛错 | 静默失败 |
eval | eval 中不能定义变量和函数 | 变量和函数定义在新的作用域中 |
arguments | arguments 拥有参数的静态副本 | arguments 和参数指向同一个值 |
delete | delete 不可配置属性会抛错 | 静默失败,返回false |
对象字面量 | 定义多个同名属性会报错 | 保留最后一个 |
函数多个同名参数 | 报错 | 最后一个为准 |
八进制字面量 | 禁止 | 允许 |
关键字 | eval arguments 不能作变量名· | - |
17. 语义化 (头条面试)
- 语义化的优点:
- 易于阅读,样式丢失也能呈现清晰的结构
- SEO,搜索引起根据标签来确定上下文和各个关键字的权重
- 便于多设备解析
- 利于代码维护
- 常见语义化标签
<header> <nav> <main> <article> <aside> <footer> <section>
18. 宏任务和微任务(setTimeout
和 Promise
的区别)(快手面试)
Event Loop
事件循环有很多tick,每个tick包括一队宏任务和一队微任务- 传统异步(
setTimeout
)是事件循环(宏任务) promise
是任务队列(微任务)
任务队列是挂在事件循环队列的每个tick之后的一个队列。在事件循环的每个tick中,可能出现的异步动作不会导致一个完整的新事件添加到事件循环队列中,而是会生成一个微任务,挂在当前事件循环的后面。
事件循环队列类似于一个游乐园游戏:玩过了滑滑梯之后,你需要跑到队尾才能再玩一次。而任务队列等于玩过之后直接插队继续玩。
console.log(1); // 当前tick宏任务 setTimeout(function(){ console.log(2); // 下一个tick宏任务 }, 0); var p = new Promise(function(resolve, reject){ console.log(3); // 当前tick宏任务 resolve(); }); p.then(res => { console.log(4); // 当前tick微任务 }); console.log(5); // 当前tick宏任务 // 1 3 5 4 2
19. 强缓存和协商缓存 cache-control
(头条面试)
请求设置
字段名 | 说明
- | -
no-cache
| 告知(代理)服务器,不要直接使用缓存,要求向原服务器发起请求no-store
| 所有内容不会被保存max-age=delta-seconds
| 客户端会缓存delta秒
响应设置
字段名称 | 说明
- | -
public
| 公开,任何情况下都缓存该资源must-revalidate
| 当前资源一定是向原服务器发去验证的,请求失败返回504
20. JSON.parse()
解析数字 (360笔试)
- 键:JSON中字段名只允许双引号包裹
"name"
- 值:数字直接写,字符串双引号
JSON.parse('{"age": 23}'); // -> {age: 23} JSON.parse('{"age": "23"}'); // -> {age: "23"}
21. 默认inherit
的css属性 (360笔试)
- 并非所有未定义的css属性会默认
inherit
color text-indent text-align line-height list-style-type list-style-image list-style cursor
direction word-spacing text-transform white-space border-collapse
22. url()
的写法 (360笔试)
资源地址可以使用单引号或双引号包起来,也可以不使用任何引号
url('image.gif)
url("image.gif")
url(image.gif)
使用@import
:
@import url("global.css)
@import url(global.css)
@import "global.css"
23. for-in
和for-of
的比较 (流利说面试)
一、forEach
遍历数组,无法使用return
和break
挑出循环
二、for-in
遍历普通对象
- index是字符串,而不是数字
- 作用于数组的for-in循环还会遍历自定义属性,以及原型链属性
- 随机顺序遍历数组
三、for-of
和Iterator
Iterator
一是为各种数据结构提供一个统一的访问接口;二是使数据结构成员能按某种次序排序for-of
只遍历拥有Symbol.iterator
属性的对象- 原生具备Iterator接口的数据结构:
Array Map Set String TypedArray arguments NodeList
- 阮一峰ES6
24. animation
动画 (美团面试)
@keyframes mymovie{ from {top: 0px;} to {top: 200px;} } div { animation: mymovie 2s infinite; position: relative; }
两件事:1. 定义关键帧; 2. animation播放设置
animation: name duration timing-function delay iteration-count direction;
值 | 描述 |
---|---|
animation-name | keyframe 名 |
animation-duration | 持续时间,带单位 2s |
animation-timing-function | 速度曲线 linear ease ease-in ease-out ease-in-out |
animation-delay | 延迟 2s |
animation-iteration-count | 播放次数 |
animation-direction | normal alternate |
流利说面试:这道题还牵扯出top和transform的性能问题,transform合成计算,改变偏移量会引发回流重绘。
回流重绘的浏览器优化,维护队列,操作到了一定数量或者到了一定的时间,批处理一个队列。
添加删除可见元素,元素位置改变,尺寸改变,margin、padding、border、content、width、height的改变都会回流。
回流一定重绘,重绘不一定回流。
25. 返回顶部按钮(寒武纪面试)
两种思路:1. scroll API; 2. 锚点标记
<a href="#top"></a>
window.onscroll = function () { var scrollTop = document.documentElement.scrollTop; if (scrollTop < 1200) { document.querySelector('#topbtn').style.display = 'none'; } else { document.querySelector('#topbtn').style.display = 'block'; } } // 定时器实现思路 document.querySelector('#topbtn').onclick = function () { var itvId = setInterval(function () { var scrollTop = document.documentElement.scrollTop; if (scrollTop > 0) { window.scrollTo(0, scrollTop - 20); } else { clearInterval(itvId); } }, 16); } // requestAnimationFrame document.querySelector('#topbtn').onclick = function () { (function smoothscroll() { var currentScroll = document.documentElement.scrollTop || document.body.scrollTop; if (currentScroll > 0) { window.requestAnimationFrame(smoothscroll); window.scrollTo(0, currentScroll - 20); } })(); }
26. margin
可以百分比吗?(爱奇艺笔试)
可以,基于父元素宽度的百分比,包括margin-top
margin-bottom
padding同理。为什么不是高度的百分比,会导致无限循环。
27. 堆排序,建堆过程 (寒武纪面试)
堆是一颗完全二叉树
- 完全二叉树
Complete Binary Tree
:除了最后一层外每一层都被填满,最后一层保持左对齐 - 满二叉树
Perfect Binary Tree
:每一层都被填满 - 满二叉树一定是完全二叉树;完全二叉树不一定是满二叉树
堆排序按原始顺序建立完全二叉树,然后找到第一个非叶子节点,从下至上开始不断调整大小顺序。完全二叉树从零开始排列,可以用一个数组表示,结点元素完全和序列挂钩。
// 建堆注意迭代,换完父节点,注意下一层节点还需要换,知道叶子结点 function bigHeap(array, i, length){ // 不用建树,因为完全二叉树的节点和排序一一对应,所以直接用序列号即可 while(i <= Math.floor(length)/2 - 1){ // i代表父节点,父节点在非叶子节点范围内则迭代 let left = 2*i+1; let right = 2*i+2; let bigChild = left; // 记录被交换的节点序号 if(right < length){ if(array[right] > array[bigChild]){ bigChild = right; } } if(array[bigChild] > array[i]){ let temp = array[bigChild]; array[bigChild] = array[i]; array[i] = temp; } // update i = bigChild; // 被交换的子节点向下迭代 } } var a = [1,2,3,4,5,6,7,8]; // 初始化堆 for(let i = Math.floor(a.length/2)-1; i >= 0; i--){ bigHeap(a, i, a.length); // 从后往前依次建堆 } console.log(a); // 堆排序的话,每次更换堆顶点与堆尾 for(let i = a.length - 1; i > 0; i --){ let temp = a[i]; a[i] = a[0]; a[0] = temp; bigHeap(a, 0, i); // 从后往前依次建堆 }
28. 前端性能优化(寒武纪面试)
- 减少请求资源大小和次数
- 打包工具,合并压缩css和js
- 图片资源懒加载,雪碧图
- 缓存,减少cookie
- 代码优化
- 动画效果用css,不用js
- 减少DOM操作,都是为了减少回流重绘渲染的时间
<script>
defer和async,不阻塞渲染,提升首屏加载速度
- 存储优化
- 利用本地存储storage
29. 实现一个sleep()
函数 (头条面试)
(async function(){ // something A await sleep(); // something B })(); function sleep(seconds){ return new Promise((resolve)=>{ setTimeout( function(){ resolve(); }, seconds); }); }
30. let和var的区别 (流利说面试)
var age = 100; let year = 6; if(age > 12){ let age = 10; var year = age * 3; console.log(age, year); } console.log(age, year)
输出:year
已经被声明
因为let
会生成一个暂时性死区,在let
形成的块级作用域中不能再声明同名变量。
31. 前端性能优化(寒武纪面试)
核心思想:
- 减少请求资源大小和请求次数: 打包工具,合并和压缩css和js;图片懒加载;
- 利用缓存和本地存储:storage/cookie/304
- 代码书写上的优化:使用css做效果不是js(合成计算);回流重绘;defer/async
32. 对称加密(奇安信笔试)
对称加密:加密和解密使用相同的密钥
DES
(Data Encryption Standard
) 数据加密标准,强度不够,能够暴力破解3DES
使用3个密钥进行DES加密,维护3个密钥,增加维护成本AES(Advanced Encription Standard)
高级加密标准
33. animation
:top
和transform
的区别 (流利说面试)
.animation{ animation: myMovie 1s infinite; } @keyframes myMovie{ 0%: {top: 0;} /* 或者 0%: { transform: translate(0, 0);} */ 25%:{top: 100px;} 50%:{top: 200px;} 75%:{top: 300px} 100%:{top: 400px;} }
transform
动画由GPU控制,支持硬件加速,不需要软件方面的渲染
浏览器接收到页面文档后,会将文档中的标记语言解析为DOM树。DOM树和CSS树结合后形成浏览器构建页面的渲染树。渲染树中包含大量的渲染元素,每个渲染元素会被分到一个图层中,每个图层又会被加载到GPU形成渲染纹理。使用transform
的图层不会触发repaint,最终都由独立的合成器进程进行处理。
独立的复合图层
3D
或transform
<video>
和<canvas>
CSS filters
z-index
可以触发GPU加速的CSS属性
transform
opacity
filter
34. mouse
事件 (奇安信)
事件 | 描述 |
---|---|
mousedown | 鼠标按下 |
mouseup | 鼠标弹起,鼠标释放 |
mousewheel | 鼠标滚轮滚动 |
mouseout | 鼠标移出 |
mouseover | 鼠标移动到元素上 |
mousemove | 鼠标在元素内移动 |
35. 值类型和引用类型 (招商银行面试)
var n = 1; // instanceof 和 isPrototypeOf 需要的参数是对象object n instanceof Number; // false Number.prototype.isPrototypeOf(n); // false // 隐式类型转换,原型链属性 n.__proto__ === Number.prototype; // true n.constructor === Number; // true
值类型存储在栈内存中;引用类型存储在堆内存中
深拷贝和浅拷贝
36. a:link
和a:hover
(海康威视笔试)
a标签定义超链接,href
指向url,target
表明打开方式
伪类:
- link 未访问前的样式表属性
- visited 已访问
- hover 鼠标悬浮
- active 鼠标按下,激活连接
定义顺序符合Love/Hate原则:LVHA
37. 多用局部变量,少用全局变量(海康笔试)
- 函数声明时会创建
[[Scope]]
属性,存储作用于信息,是一个对象Variable Object
,列表中有可访问的变量。 - 作用域链最前端是
Activation Object
, 最末端是全局对象Global Object
- 函数被执行时会创建执行对象
Execution Object
- ==全局变量处在作用域链末端,查找变量的速度要比局部变量慢==
在美团面试时,还被问到了,作用域链中未查找到的变量最后会输出什么?
属性查找:静默失败(undefined)
变量查找:分为LHS和RHS
LHS查询:静默创建全局属性(非全局变量)
RHS查询:查不到报错(未声明)
// 不声明anything变量 window.anything; // undefined anything; // ReferenceError: anything is not defined // 属性查找:undefined function run(){ console.log(this.anything) } run(); // undefined // 变量查找:RHS报错 function run(){ console.log(anything); } run(); // ReferenceError: anything is not defined // 变量查找:LHS静默创建全局属性 function run(){ anything = 'zpj'; console.log(anything); } run(); // 'zpj'
全局属性和全局变量的区别:
var
声明全局变量的同时会自动创建同名全局属性,通过window.XXX
访问- ==全局属性可以被
delete
删除,但是全局变量不可以==
function run(){ anything = 'zpj'; console.log(anything); } run(); // 'zpj' anything; // 'zpj' delete anything; // true anything; // ReferenceError var hahaha = 'zpj'; delete hahaha; // false hahaha; // 'zpj'
38. substr()
和substring()
的区别(海康笔试)
substr(start, length)
substring(start, stop)
从stop到stop-1的所有字符,不接受负参数slice(start, end)
含首不含尾,负数表示从后往前splice(start, length)
39. CSS前景色和背景色(度小满笔试)
前景就是文本和边框;当时选项里出现了
foreground-color
做干扰
前景色 color
border-color
: 前景包括文本和边框
背景色 background-color
透明度 opacity
filter: alpha(opacity=80)
40. UNIQUE
和DISTINCT
区别(度小满)
unique
是建表时约束某列值唯一distinct
是查询时过滤重复
41. 什么是shell
?(度小满)
shell是系统跟计算机硬件交互时使用的中间介质。用户直接面对的不是计算机硬件,而是shell,用户把指令告诉shell,然后shell再传给系统内核,接着内核再去支配计算机硬件执行各种操作。
bash
: linux默认安装的shell叫作bash,即Bourne Again Shell
是 Bourne Shell
的增强版本。Bourne Shell
是最早流行的一个shell,创始人是Steven Bourne
42. 提升性能(海康威视)
- 减少HTTP请求(资源大小和请求次数):雪碧图,压缩合并js和css
- 使用CDN(内容分发网略):选择最近的服务器
- 缓存(Expires / cache-control: max-age)
- 压缩(Accept-Encoding:gzip, deflate)(Content-Encoding: gzip)
- 样式表放在头部(减少重绘)
- 脚本放在底部(阻塞DOM树的更新)
- 使用外部脚本和样式文件(重复利用)
- DNS缓存(DNS域名解析)
- 避免重定向(301/302)
43. 行内元素和块级元素的嵌套问题(海康)
p div h1-h6 form ul ol dl dd dt li table tr td th hr blockquote address header section article footer
块级元素:
- 独占一行,没有宽高时默认100%
- 块级元素允许设置宽高,width、height、margin、padding、border都可控制
- 块级元素可以包含行内元素、块级元素
span a img input em b i q select textarea button
行内元素:
- 行内元素不换行
- 不能设置width、height、上下margin和上下padding
- 默认宽度是content宽度
- 行内元素只能包含文字、行内元素、行内块元素
display: inline-block;
行内块元素在行内元素的基础上,可以设置宽高width、height