HTML
- 如何理解 HTML 语义化
- HTML语义化就是使用正确的标签,段落就写 p 标签,标题就写 h1 标签,文章就写 article 标签,视频就写video 标签,等等,这样便于开发者进行阅读和维护
- meta viewport 是做什么用的,怎么写?
- meta viewport是专门为移动设备下的显示所设计的东西
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no">
- name:为viewport,表示供移动设备使用
- content:定义了viewport的属性
- width:表示移动设备下显示的宽度为设备宽度(device-width)
- initial-scale:表示设备与视口的缩放比率
- maximum-scale=1和minimum-scale:分别表示缩放的最大最小值, 要注意的是, maximum必须大于或等于minimum
- user-scalable:表示用户缩放能力, no表示不允许用户缩放网页
不用viewport控制用户不能缩放:用js监听屏幕宽度 window.onresize
- 你用过哪些 HTML5 标签?
display的block、inline和inline-block的区别
(1)block
会独占一行,多个元素会另起一行,可以设置width、height、margin和padding属性
(2)inline
元素不会独占一行,设置width、height属性无效。但可以设置水平方向的margin和padding属性,不可以设置垂直方向的padding和margin
(3)inline-block
将对象设置为inline对象,但对象的内容作为block对象呈现,之后的内联对象会被排列在同一行内
常见的行内元素和块级元素
块级元素:
div、p、h1~h6、ul、li、ol、dd、dt、dl、table、hr、blockquote、address、pre、menu
HTML5中新增的:header、footer、aside、section
常见的行内元素:
span、img、input、a、label、button、select、textarea、sup、sub、abbr、s、i、em、u、strong、small
-
内容相关
- header
- main
- footer
- article
-
功能相关
- canvas
- canvas 如何进行绘制
- canvas
const canvas = document.getElementById('canvas'); // 首先获取到 canvas
const ctx = canvas.getContext('2d'); // 然后获取到 canvas 的 2d 上下文
ctx.fillStyle = 'green'; // 然后设置笔刷的颜色
ctx.fillRect(10, 10, 150, 100); // 然后设置笔刷的范围
- video
- 用 video的时候会加什么属性
<video src="videofile.ogg" autoplay poster="posterimage.jpg"></video>
// src 为视频地址,autoplay为自动播放,poster为封面
<video src="foo.ogg">
<track kind="subtitles" src="foo.en.vtt" srclang="en" label="English">
<track kind="subtitles" src="foo.sv.vtt" srclang="sv" label="Svenska">
</video> // 还可以用track加字幕
- audio
- H5 是什么?
- HTML5 最新的 HTML 标准
- 是 HTML 标签中的 标题标签,代表五级标签
CSS
- 两种盒模型分别说一下。
- CSS 盒模型分两种,一种是 content-box 内容盒,一种是 border-box 边框盒
区别是什么?
content-box 的宽度只包含content, border-box 的宽度包含到 border,包括 content宽度 + padding宽度 + border宽度
- 你一般用哪一个?
我一般用 border-box,因为我觉得 border-box 更灵活些
- 如何垂直居中?
https://juejin.im/post/6882272759901061127/
- 子元素绝对定位,父元素相对定位 + transform: translate(-50%, -50%);
- flex布局:
display:flex;
justify-content:center;
align-items: center;
- flex 怎么用,常用属性有哪些?
常用属性:
排列方式:横向还是纵向
flex-direction:row; // 从左向右
flex-direction:column; // 从右向左
flex-direction:row-reverse; // // 从上到下
flex-direction:column-reverse; // 从下到上
是否换行:
flex-wrap: nowrap; // 不换行(默认)
水平排列方式:
justify-content: flex-start; // 居左
justify-content: flex-end; // 居右
justify-content: center;// 居中
justify-content: space-between; // 两端对齐
justify-content: space-around; // 拉伸分布
垂直排列:
align-items: flex-start; // 开始
align-items: flex-end; // 底部
align-items: center; // 居中
flex-grow:0;(默认值)// 定义子元素放大比例
- BFC 是什么?(不理解)
- CSS 选择器优先级
!important -> 行内样式 -> #id -> .class -> 元素和伪元素 -> * -> 继承 -> 默认
伪元素,选择元素的特定位置,比应用样式
举例:
- 越具体优先级越高
- 写在后面的覆盖前面的
- important! 最高,但是尽量少用
- 清除浮动说一下
.clearfix::after{
content: '';
display: block/table;
clear: both;
}
.clearfix 加到容器上,里面子元素的浮动就被清除了。
- 层叠上下文
所有的盒模型元素都处于三维坐标系中。 除了我们常用的横坐标和纵坐标, 盒模型元素还可以沿着“z 轴”层叠摆放,这里就需要用到 z-index了,z-index数字越大, 元素越接近观察者。
媒体查询: 通过查询当前属于哪种设备, 让网页能够在不同的设备下正常的预览
@media
我用到过 min-width和max-width
-
浏览器渲染原理
-
解析HTML→构建HTML树(DOM)
-
解析CSS→构建CSS树(CSSDOM)
-
将两棵树合并成一颗渲染树(render tree)
-
Layout布局
根据render tree就可以进入Layout布局
Layout流程输出是一个盒模型,Layout计算每个对象的精确位置和大小。
5.Paint绘制
布局好了后,就可以将render tree里的每个对象转换成屏幕的实际像素,paint就是将各个节点绘制到屏幕上。
6.Composite合成
将已经paint的部分根据层叠关系把页面展示出来。
- PC端和移动端的区别
- PC考虑的是浏览器的兼容性,而移动端开发考虑的更多的是手机兼容性
- 在部分事件的处理上,移动端多出来的事件是触屏事件,而缺少的是hover事件
-
window的onload事件和DOMcontentloaded谁先谁后?
DOMcontentloaded先构建html树的时候就开始执行,onload是在页面加载完成后才开始出现 -
line-height 如果设置了 15rem 15em 15px 1.5分别代表什么效果?
rem和em是自适应大小,区别在于rem是相对于根字体,em是相对于父元素而言,没有单位的1.5表示1.5倍行高,如果当前字体10px 1.5就是说行高15px 。15rem 15em 15px 1.5分别相对于 根字体 父辈字体 固定字体 当前字体大小而言。 -
transition 和 animation
随时间改变元素的属性值
- animation配合@keyframe触发。transition 是通过hover或者js事件触发
- animation 可以结合 keyframe 设置每一帧,但是 transition只有两帧
- animation 可以设置很多的属性,比如循环次数,动画结束的状态等等,transition 只能触发一次
原生 JS
- ES 6 语法知道哪些,分别怎么用?
let/const/箭头函数/解构赋值/Promise
解构赋值语法是一种 Javascript 表达式。通过解构赋值, 可以将属性/值从对象/数组中取出,赋值给其他变量。
语法:
var a, b, rest;
[a, b] = [10, 20];
console.log(a); // 10
console.log(b); // 20
[a, b, ...rest] = [10, 20, 30, 40, 50];
console.log(a); // 10
console.log(b); // 20
console.log(rest); // [30, 40, 50]
({ a, b } = { a: 10, b: 20 });
console.log(a); // 10
console.log(b); // 20
详细:
https://es6.ruanyifeng.com/
https://fangyinghang.com/es-6-tutorials/
- Promise、Promise.all、Promise.race 分别怎么用?
Promise的缺点
- promise一旦新建就会立即执行,无法中途取消
- 当处于pending状态时,无法得知当前处于哪一个状态,是刚刚开始还是刚刚结束
- 如果不设置回调函数,promise内部抛出的错误,不会反应到外部
Promise的优点 - 更好地进行错误捕获
- 代码更易读
Promise
Promise 是异步编程的一种解决方案,有三种状态:
待定(pending): 初始状态,既没有被兑现,也没有被拒绝。
已兑现(fulfilled): 意味着操作成功完成。
已拒绝(rejected): 意味着操作失败。
可以通过函数来监听Promise状态的变化
成功执行 then() 函数的回调
失败执行 catch() 函数的回调
Promise的具体用法如下(背代码):
function fn(){
return new Promise((resolve, reject)=>{
成功时调用 resolve(数据)
失败时调用 reject(错误)
})
}
fn().then(success1, fail1).then(success2, fail2)
Promise.all
Promise.all()方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。
Promise.all([promise1, promise2]).then(success1, fail1)
promise.race
Promise.race()方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。
Promise.race([promise1, promise2]).then(success1, fail1)
promise1和promise2只要有一个成功就会调用success1;
promise1和promise2只要有一个失败就会调用fail1;
总之,谁第一个成功或失败,就认为是race的成功或失败。
- 手写函数防抖和函数节流
节约性能
防抖是控制次数,节流是控制频率
// 防抖,指触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。比如:坐电梯时,如果在电梯内持续有人按电梯的楼层号,那么电梯是不会运行的,当没人按楼层号时,电梯会在一小段时间间隔后才会运行,以此达到防抖的效果。
function debounce(fn, delay){
let timerId = null
return function(){
const context = this
if(timerId){window.clearTimeout(timerId)}
timerId = setTimeout(()=>{
fn.apply(context, arguments)
timerId = null
},delay)
}
}
const debounced = debounce(()=>console.log('hi'))
debounced()
debounced()
// 节流(一段时间执行一次之后,就不执行第二次)CD
function throttle(fn, delay){
let canUse = true
return function(){
if(canUse){
fn.apply(this, arguments)
canUse = false
setTimeout(()=>canUse = true, delay)
}
}
}
const throttled = throttle(()=>console.log('hi'))
throttled()
throttled()
- 手写AJAX
可以进行表单验证
AJAX 就是用JS向服务端发起一个请求,并获取服务器返回的内容,它一共分为四个步骤
-
第一步,创建XMLHttpRequest对象
-
第二步,连接服务器
-
第三步,向服务器发送请求send
-
第四步,接受服务器响应的数据
var request = new XMLHttpRequest();
request.open('GET', '/xxxx',false) // 请求方式,路径,true代表异步,false代表同步
request.onreadystatechange = function() {
if (request.readyState === 4) {
console.log('请求完成')
if (request.response.status >= 200 &
console.log('请求成功')
} else {}
}
}
// request.onload = ()=>{console.log('请求成功')} // 简化
request.send()
readyState状态码说明:
0=>初始化 1=>载入 2=>载入完成 3=>解析 4=>完成
- 这段代码里的 this 是什么?
this永远指向的是调用它的对象,也就是看谁调用执行的它
- fn() // this => window/global 普通函数中的 this 都引用 window 对象
- new fn() // this => 新的对象 构造函数中的 this 指向的是它实例化的对象
- obj.fn() // this => obj 作为对象属性值的函数,this 指向的就是这个对象
- fn.call(xx) // this => xx
- fn.apply(xx) // this => xx
- fn.bind(xx) // this => xx 函数调用 apply(), call() 方法后,this 引用为 call apply 方法传进去的第一个参数
- fn = () =>{} // this => 外面的 this
- 闭包
什么是「闭包」。
闭包是一种隐藏局部变量的技术
比如说:函数 A 内部有一个函数 B,函数 B 可以访问到函数 A 中的变量,那么函数 B 就是闭包
举个栗子:
var a = 1
function f1(){
console.log(a)
}
// 1
用途:使用闭包主要是为了设计私有的方法和变量
缺点:函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包
解决方法:在退出函数之前,将不使用的局部变量全部删除
<script>
function f1() {
var a = 1;
return {
function() {
return a
}
}
}
var b = f1()
</script>
- 什么是 JSONP,什么是 CORS,什么是跨域?
htpp proxy代理跨域
跨域就是通过某些手段来绕过同源策略限制,实现不同服务器之间通信的效果
如果两个url的协议、域名、端口号完全一致,那么这两个url就是同源的。
CORS
如何理解CORS?
如果wang.com和ergou.com这两个网站都是我的,我想让这两个网站互相访问,只需要wang.com在响应头里写ergou.com可以访问即可。这就是CORS。
具体语法:
Access-Control-Allow-Origin:
JSONP
原理是利用了script标签的src属性不受浏览器的同源策略限制,来进行数据请求的。
我们在跨域的时候由于某些原因当前浏览器不支持CORS,我们必须使用另一种方式来跨域,前端请求一个js文件,这个js文件会执行一个回调,回调里面就有我们的数据。
回调的名字是什么?
回调的名字可以随机生成的,我们把这个名字当成callback的参数传给后台,后台会把这个函数返回给我们并执行
JSONP的优点是什么?
- 兼容IE
- 可以跨域
JSONP的缺点是什么?
- 因为是script标签,所以读不到AJAX那么精确,拿不到状态码,拿不到header
- 不支持post,只支持get
- async/await 怎么用,如何捕获异常?
async 是“异步”的简写, async 用于申明一个异步的 function
await 可以认为是 async wait 的简写,await 用于等待一个异步方法执行完成
await只能放在async函数里
- 如何实现深拷贝?
浅拷贝
修改新变量的值会影响原有变量的值
默认情况下引用类型都是浅拷贝
展开运算符...
深拷贝
修改新变量的值不会影响原有变量的值
默认情况下基本数据类型都是深拷贝
- 递归
function deepClone(obj) {
let objClone = Array.isArray(obj) ? [] : {}
if (obj && typeof obj === 'object') {
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
// 判断obj子元素是否为对象,如果是,递归复制
if (obj[key] && typeof obj[key] === 'object') {
objClone[key] = deepClone(obj[key])
} else {
objClone[key] = obj[key]
}
}
}
}
return objClone
- 通过 JSON 对象
function deepClone (obj) {
let _obj = JSON.stringify(obj)
let objClone = JSON.parse(_obj)
return objClone
}
- 通过jQuery的extend方法实现深拷贝
var array = [1,2,3,4];
var newArray = $.extend(true,[],array);
- Object.assign()拷贝
当对象中只有一级属性,没有二级属性的时候,此方法为深拷贝,但是对象中有对象的时候,此方法,在二级属性以后就是浅拷贝。
- 如何用正则实现 trim()?
- trim() 方法用于删除字符串的头尾空白符,空白符包括:空格、制表符 tab、换行符等其他空白符等。
- trim() 方法不会改变原始字符串。
- trim() 方法不适用于 null, undefined, Number 类型。
var str = trim(" R ")
function trim(string) {
return string.replace(/^\s+|\s+$/gm,'');
}
console.log(str) // "R"
- 不用 class 如何实现继承?用 class 又如何实现?
不用 class
// Animal 类
function Animal(){
this.a = 1
}
Animal.prototype.move = function(){} // Animal 有个属性 a , 有个原型方法为 move
// Dog 类
function Dog(){
Animal.apply(this, arguments) // 首先调用 Animal
this.d = 2
}
// 实现原型的继承,Dog类 继承 Animal类
let f = function(){
f.prototype = Animal.prototype
Dog.prototype = new f() // Dog 的原型继承 Animal 的原型
Dog.prototype.constructor = Dog
Dog.wangwang = function(){}
}
用class
class Dog extends Animal {
constructor() {
super()
}
}
- 如何实现数组去重?
- 使用set
- 使用map
function unique (array) {
return Array.from(new Set(array))
}
var array = [1,5,2,3,4,2,3,1,3,4];
console.log(unique(array)); // [1, 5, 2, 3, 4]
<script>
let arr = [1, 5, 2, 3, 4, 2, 3, 1, 3, 4];
function unique(arr) {
let map = new Map()
let newArr = []
for (let i = 0; i < arr.length; i++) {
if (!map.has(arr[i])) {
map.set(arr[i])
newArr.push(arr[i])
}
}
return newArr
}
console.log(unique(arr)); // [1, 5, 2, 3, 4]
</script>
- == 相关题目(反着答)
这个我不太清楚, == 规则太复杂了,我平时写代码都用三个等于号,代码更清晰简洁
- 手写一个 Promise(送命题,必须会)放弃
- JS 中使用 typeof 能得到哪些类型?
-
typeof 123 // number
-
typeof 'abc' // string
-
typeof true // boolean
-
typeof Symbol() // symbol
-
typeof undefined // undefined
-
typeof null // object
-
typeof [] // object
-
typeof {} // object
-
typeof console.log // function
- 介绍 js 的基本数据类型
四基两空一对象
number:数字
string:字符串
bool:布尔值
symbol:符号
undefined:未定义
null :空
object:对象
五个falsy值:0, NaN, null, undefined, ''(中间没有空格)
- JS 中有哪些内置函数/对象?
Object 是 JavaScript 中所有对象的父对象
数据封装类对象:
Object
Array
Boolean
Number
String
其他对象:
Function
Arguments
Math
Date
RegExp
Error
- JS 变量按照存储方式区分为哪些类型,并描述其特点
值类型的变量直接存储数据,而引用类型的变量持有的是数据的引用,数据存储在数据堆中
// 值类型
var a = 10
var b = a
a = 11
console.log(b)// 10
// 引用类型
var a = {age:100}
var b = a
b.age = 200
console.log(a.age) // 200
- var、 let、const的区别
- var存在变量提升,let、const不存在
- var可以重复声明,let、const不能
- var、let 的变量值可以修改,const不能
- var 和 let 声明时可以不用设置初始值,const需要
- var 没有块级作用域,let、const有
19.箭头函数和普通函数 - 普通函数的this 指向调用它的那个对象
- 箭头函数不能作为构造函数,不能使用new,没有this
20.立即执行函数是什么?
要成为立即执行函数,需要满足两个条件:
声明一个匿名函数
立马调用这个匿名函数
比如,下面就是一个非常典型的立即执行函数:
(function(){console.log('这是一个立即执行函数')}())
//首先声明一个匿名函数(function(){console.log('这是一个立即执行函数')})
//然后再匿名函数的后面接一对括号(),立马调用这个函数
立即执行函数有什么作用?
立即执行函数的作用只有一个,那就是创建独立的作用域。 让外部无法访问作用域内部的变量,从而避免变量污染。
- 作用域?
指函数在哪些范围内可以用,而在其他部分不可以,要用就得重新定义。
说说你对作用域链的理解
每一个函数都有一个作用域, 如果一个函数内部又嵌套着另外一个函数,
嵌套的函数也会有一个作用域,这样,嵌套函数就能访问到外部函数中的变量,
以及全局作用域中的变量,此时就形成了一条作用域链
作用域链的作用是保证执行环境里有权访问的变量和函数是有序的,作用域链的变量只能向上访问,变量访问到 window 对象即被终止,作用域链向下访问变量是不被允许的。
- 原型与原型链
减少内存开销,实现属性的继承
var obj = {};
var arr = [];
function fn1 () {}
所有的引用类型(数组、对象、函数),都有一个 proto(隐式原型)属性,属性值是一个普通对象
console.log(obj.__proto__);
所有的函数,都有一个 prototype (显式原型)属性,属性值也是一个普通对象
console.log(obj.prototype);
所有的引用类型的proto属性值都指向构造函数的prototype属性值。
console.log(obj.__proto__ === Object.prototype); // true
当试图获取对象属性时,如果对象本身没有这个属性,那就会去他的proto(prototype)中去寻找。
function Dog(name){
this.name = name;
}
Dog.prototype.callName = function (){
console.log(this.name,"wang wang");
}
let dog1 = new Dog("ahuang");
dog1.printName = function (){
console.log(this.name);
}
dog1.callName(); // ahuang wang wang
dog1.printName(); // ahuang
原型链
我找一个属性,首先会在f.proto中去找,因为属性值为一个对象,那么就会去f.proto.proto去找,同理如果还没找到,就会一直向上去查找,直到结果为null为止。这个串起来的链即为原型链。

- 异步和单线程
进程:指在系统中正在运行的一个应用程序;程序一旦运行就是进程;进程——资源分配的最小单位。
线程:系统分配处理器时间资源的基本单元,或者说进程之内独立执行的一个单元执行流。线程——程序执行的最小单位。
并发执行:当多个线程同时运行的时候,这样的执行模式成为并发执行
我们可以将同步看成是单线的执行,即要么执行成功,要么执行失败,反正就是要返回一个结果,在没有得到这个结果之前什么都不干,就傻傻的等着。
单线程:就是在同一时间只能做一件事情。
单线程意味这所有的任务都需要排队,执行完一个才能继续执行下一个,但是如果前一个执行很长,后一个任务就需要一直等待。这个时候我们就需要用到异步
常用的异步
setTimeout,setInterval,ajax
为什么js引擎是单线程?
js的主要用途是与用户互动,以及操作DOM,这决定它只能是单线程。例:一个线程要添加DOM节点,一个线程要删减DOM节点,容易造成分歧。
- 数组有哪些方法?
push()方法:尾部添加;
pop()方法:尾部删除;
unshift():头部添加;
shift():头部删除。 - javascript中创建对象的三种方式
- 利用字面量创建对象
var obj = {
name: '123',
gender: '男',
sayHi: function() { //方法
alert('hello!')
}
}
// 2.调用对象
// (1)
console.log(obj.name);
// (2)
console.log(obj['name']);
// (3)调用对象的方法
obj.sayHi();
- 利用new object创建对象
var obj = new Object(); //创建一个空对象
obj.name = '123';
obj.age = '23';
obj.height = '177';
obj.sayHi = function() {
alert('hello');
}
// 2.调用对象
// (1)
console.log(obj.name);
// (2)
console.log(obj['name']);
// (3)调用对象的方法
obj.sayHi();
- 利用函数创建对象
function Star(name, age, gender) {
this.name = name;
this.age = age;
this.gender = gender;
this.sing = function(sang) {
console.log(sang)
}
}
// new Star('123', 23, '男'); //只new不赋值的话,以下的不会执行,算是错误的
//1.构造函数名字首字母大写
// 2.构造函数不需要return
var ldh = new Star('123', 23, '男');
var zxy = new Star('345', 29, '男');
ldh.sing('啦啦啦');
// console.log(typeof(ldh));
console.log(ldh.name);
zxy.sing('你的名字');
- new一个对象的时候发生了什么?
function Person(name, age) {
this.name = name;
this.age = age;
}
let p = new Person("William", 24);
new一个对象的四个过程:
- 创建一个空对象
let obj = {};
- 让构造函数中的this指向新对象,并执行构造函数的函数体
let result = Person.call(obj);
- 设置新对象的proto属性指向构造函数的原型对象
obj.__proto__ = Person.prototype;
- 判断构造函数的返回值类型,如果是值类型,则返回新对象。如果是引用类型,就返回这个引用类型的对象
if (typeof(result) == "object")
p = result;
else
p = obj;
- js为什么需要放到body后?
浏览器的渲染引擎和js解析引擎会冲突。
BODY中编写的都是HTML标签,JS很多时候需要操作这些元素,首先我们要保证元素加载成功,才可以在JS中获取
- js 操作数组的api
https://www.cnblogs.com/10JQKA/archive/2019/04/04/10650340.html
join(), sort(), slice(), splice(), concat(), reverse(), push()+pop(), shift()+unshift(), forEach(), map(), some(), every(), filter(),
- 前端常见的性能优化方式?
1、减少http请求,合理设置 HTTP缓存
2、使用浏览器缓存
3、CSS Sprites,合并 CSS图片,减少请求数
4、CSS放在页面最上部,javascript放在页面最下面
DOM
- 事件委托
DOM 事件模型
DOM事件模型分为捕获和冒泡。一个事件发生后,会在子元素和父元素之间传播,这种传播分为三个阶段。
- 捕获阶段:事件从window对象自上而下向目标节点传播
- 目标阶段:目标节点处理事件
- 冒泡阶段:事件从目标节点自下而上向window对象传播
事件委托
事件委托,由于冒泡阶段事件会从子节点向上传播到父节点,因此可以监听父节点来处理多个子节点的事件。
<style>
ul{
border: 1px solid red;
padding: 10px;
}
li{
border: 1px solid red;
padding: 10px;
}
span{
border: 1px solid black;
padding: 10px;
}
</style>
<body>
<ul class="parent">container
<li class="child">box
<li class="target">target</li>
</li>
</ul>
</body>
</html>
错误版(但是可能能过)
const ul = document.querySelector('ul')
ul.addEventListener('click', function(e){
if(e.target.tagName.toLowerCase() === 'li'){
console.log('hello')
}
})
bug 在于,如果用户点击的是 li 里面的 span,就没法触发 fn,这显然不对。
高级版
function delegate(element, eventType, selector, fn) {
element.addEventListener(eventType, e => {
let el = e.target
while (!el.matches(selector)) {
if (element === el) {
el = null
break
}
el = el.parentNode
}
el && fn.call(el, e, el)
})
return element
}
思路是点击 span 后,递归遍历 span 的祖先元素看其中有没有 ul 里面的 li。
- 用 mouse 事件写一个可拖曳的 div
http://js.jirengu.com/fevayuruci/1/edit?html,css,js,output
HTTP
对器客户端和 服务器端之间数据传输的格式规范,格式简称为“超文本传输协议”
一个请求由什么组成?
请求头,请求体,请求正文,状态码,响应头,响应正文。
请求头和响应头有哪些?
content-type, user-agent,cache-control,host,origin,refer等等
- HTTP 状态码知道哪些?分别什么意思?
-
1 开头:信息状态码
-
2 开头: 成功状态码
-
3 开头: 重定向状态码,进一步操作
-
4 开头: 客户端错误状态码
-
5 开头: 服务端错误状态码
-
100 继续
-
101 切换协议
-
200 成功
-
201 已创建
-
202 已接受,未处理
-
204 无内容
-
300 多种选择
-
301 永久移动
-
302 临时移动
-
303 查看其他位置
-
304 未修改
-
400 错误请求
-
401 未授权
-
403 禁止
-
404 未找到
-
405 方法禁用
-
414 请求 url 过长
-
500 服务器错误
-
502 错误网关
- HTTP 缓存有哪几种?
三种
①- ETag: 值一般是MD5
②- xExpire: 值一般是 日期 // 在某个时间点过期
③- Cache-Control: 最常见的是 max-age=600 // 多少秒内过期
②③区别:②有bug:本地时间是可以设置的,假如今天是2020/10/1,把本地时间设置成2019/10/1,直接就过期了,③是一个相对时间,不存在这个问题
①③区别:③是从浏览器本地缓存,是无请求的,而①还是会发送请求,状态码一般为304
http的缓存机制可以分为两种类型:
强缓存:浏览器判断本地缓存未过期,就直接使用,无需发起http请求
协商缓存: 浏览器判断本地缓存过期,发送http请求,服务器返回304告诉浏览器文件未改变,浏览器继续使用本地缓存
浏览器发送请求时判断缓存顺序:
是否有缓存?——无:发送请求;有:判断缓存
验证Cache-Control中的max-age时间限定、验证Expires到期日?——未过期:使用缓存(200 form-cache);过期:发送缓存信息至服务器验证
验证E-tag和Last-Modified信息?——无更新:304,使用缓存;有更新:200,返回新文件并更新缓存
- GET 和 POST 的区别
get、post、put、patch、delete
错误:
- POST 安全, GET 不安全
- GET URL 有长度限制, POST 没有
- GET 参数是放在 url, POST 是放在消息体里面的
- GET 只需要一个报文, POST 需要两个以上
- GET 幂等,POST 不幂等
正确:
GET 是获取数据, POST 是提交数据
Cookie VS Session
-
Cookie 是服务器发给浏览器的一段字符串,浏览器每次访问服务器的时候都会把字符串带上, Cookie 是在浏览器上
-
Session 是会话,表示浏览器与服务器一段时间内的会话,Session 是在服务器上
Cookie VS LocalStorage -
Session一般是基于Cookie来实现的,就是把Session ID 放到Cookie里面
-
Cookie 限制比较小,一般是 4k 左右,LocalStorage 一般有5M
-
Cookie 一般用来存用户信息,LocalStorage 一般用于存不重要数据
-
Cookie 会被发送到服务器上,LocalStorage不发送到服务器上
LocalStorage VS SessionStorage -
LocalStorage 一般不会过期,SessionStorage 一般会在 Session 结束的时候过期
- HTTP1.x和HTTP2的区别
- HTTP2支持多路复用
- HTTP2支持服务器推送
- 从输入 url 到页面加载显示完成发生了什么
- 查找域名和对应 IP 地址
- 建立连接 (TCP 的三次握手)
- 构建网页
- 断开连接
- 三次握手四次挥手?不记得
框架 Vue
- watch 和 computed 和 methods 区别是什么?
- watch是监听属性,computed是计算属性
- watch不支持缓存,不论监听的数据是否重复都会被监听到,computed支持缓存机制,在监听数据没有改变时不会重新计算
- methods是方法,只要重新渲染就会执行,如需要每次重新计算,用方法
- Vue 有哪些生命周期钩子函数?分别有什么用?
VUE生命周期是VUE实例化或者组件创建到消亡的过程
它的生命周期中有多个事件钩子,让我们在控制整个Vue实例的过程时更容易形成好的逻辑
- beforeCreat:创建前的状态
- created:创建完毕状态
- beforeMount:挂载前状态
- mounted:挂载结束状态,渲染到真正的DOM
- beforeUpdate:可以拿到Vue实例化改变前的状态
- updated:拿到变动完成的状态
- beforeDestroy:消亡前的状态
- destroyed:实例化或组件被摧毁消亡
DOM 渲染哪个周期中就已经完成?
一般在mounted周期内请求数据,因为这个周期开始时,当前组件已经被挂载到真实的元素上了
第一次页面加载会触发哪几个钩子?
第一次页面加载时会触发 beforeCreate, created, beforeMount, mounted 这几个钩子
- Vue 如何实现组件间通信?
父子组件:使用 v-on 通过事件通信
爷孙组件:使用两次 v-on 通过爷爷爸爸通信,爸爸儿子通信实现爷孙通信
任意组件:使用 eventBus = new Vue() 来通信,eventBus.$on 和 eventBus.$emit 是主要API
任意组件:使用 Vuex 通信
- Vue 数据响应式/双向绑定原理?
简单来说,数据响应式是指页面视图会随着数据的变化而变化
数据响应式原理:
- 把一个普通的 JavaScript 对象传入 Vue 实例作为 data 选项,Vue 将遍历此对象所有的 property,使用 Object.defineProperty 把这些属性全部转为 getter/setter
- 对于已经创建的实例,Vue 不能检测到对象属性的添加或删除,解决方法是手动调用 Vue.set 或者 this.$set
- Vue.set 是做什么用的?
对于已经创建的实例,Vue 不允许动态添加根级别的响应式,解决方法是手动调用 Vue.set 或者 this.$set - Vuex 你怎么用的?
Vuex 是一个专为 Vue.js 应用程序开发的状态管理工具。
它包括State/Getter/Mutation/Action/Module
Mutation/Action的区别
- mutation 有一个固有参数 state,接收的是 Vuex 中的 state 对象
- action 也有一个固有参数 context,但是 context 是 state 的父级,包含 state、getters
- VueRouter 你怎么用的?
Vue Router 是 Vue.js 官方的路由管理器。
说出核心概念的名字和作用:History 模式/导航守卫/路由懒加载
常用 API:router-link/router-view/this.router.replace/this.$route.params
this.router.replace(path): 用新路由替换当前路由(不可以返回到当前路由界面)
this.router.go(-1): 请求(返回)上一个记录路由
this.$router.go(1): 请求下一个记录路由
- 路由守卫是什么?
导航守卫就是路由跳转过程中的一些钩子函数。
- router.beforeEach 全局前置守卫
- router.beforeResolve 全局解析守卫
- router.afterEach 全局后置钩子
- beforeRouteEnter
beforeRouteUpdate (2.2 新增)
beforeRouteLeave路由独享的守卫
- VueRouter怎么做懒加载?
把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件
- router 和 route 的区别
$route对象表示当前的路由信息,包含了当前 URL 解析得到的信息。包含当前的路径,参数,query对象等。
$router对象是全局路由的实例,是router构造方法的实例。
-
v-if和v-for
相同点: 两者都是在判断DOM节点是否要显示。不同点:
a.实现方式: v-if是根据后面数据的真假值判断直接从Dom树上删除或重建元素节点。 v-show只是在修改元素的css样式,也就是display的属性值,元素始终在Dom树上。
b.编译过程:v-if切换有一个局部编译/卸载的过程,切换过程中合适地销毁和重建内部的事件监听和子组件; v-show只是简单的基于css切换;
c.编译条件:v-if是惰性的,如果初始条件为假,则什么也不做;只有在条件第一次变为真时才开始局部编译; v-show是在任何条件下(首次条件是否为真)都被编译,然后被缓存,而且DOM元素始终被保留;
d.性能消耗:v-if有更高的切换消耗,不适合做频繁的切换; v-show有更高的初始渲染消耗,适合做频繁的额切换;
- vue.js 的两个核心是什么?
- 数据驱动:在vue中,数据的改变会驱动视图的自动更新
- 组件化:组件化开发,将常用的代码封装成组件之后,就能高度的复用,提高代码的可重用性
12.说出至少 4 种 vue 当中的指令和它的用法
v-if(判断是否隐藏)
v-for(把数据遍历出来)
v-bind(绑定属性)
v-model(实现双向绑定)
- 什么是组件以及如何使用组件
组件就是把一个很大的界面拆分为多个小的界面, 每一个小的界面就是一个组件
将大界面拆分成小界面就是组件化
组件化的好处是可以简化Vue实例的代码,可以提高代码复用性
- 单页面应用和多页面应用有哪些优缺点?
概念:只有一个html页面,所有跳转方式都是通过组件切换完成的。
优点:页面之间跳转流畅、组件化开发、组件可复用、开发便捷、易维护。
缺点:首屏加载较慢,加载整个项目中使用的css、js
概念:整个项目有多个html,所有跳转方式都是页面之间相互跳转的。
优点:首屏加载较快,只加载本页所使用的的css、js
缺点:页面跳转较慢,工作量比较大
框架 React
- 受控组件 V.S. 非受控组件
<FInput value={x} onChange={fn}/> 受控组件
<FInput defaultValue={x} ref={input}/> 非受控组件
区别受控组件的状态由开发者维护,非受控组件的状态由组件自身维护(不受开发者控制)
- React 有哪些生命周期函数?分别有什么用?(Ajax 请求放在哪个阶段?)
- 组件将要挂载时触发的函数:componentWillMount
- 组件挂载完成时触发的函数:componentDidMount
- 是否要更新数据时触发的函数:shouldComponentUpdate
- 将要更新数据时触发的函数:componentWillUpdate
- 数据更新完成时触发的函数:componentDidUpdate
- 组件将要销毁时触发的函数:componentWillUnmount
- 父组件中改变了props传值时触发的函数:componentWillReceiveProps
在componentDidMount钩子里请求数据,因为这个周期开始时,当前组件已经被挂载到真实的元素上了
- React 如何实现组件间通信?
父子靠 props 传函数
爷孙可以穿两次 props
任意组件用 Redux(也可以自己写一个 eventBus)
- shouldComponentUpdate 有什么用?
用于在没有必要更新 UI 的时候返回 false,以提高渲染性能 - 虚拟 DOM 是什么?
虚拟 DOM 就是用来模拟 DOM 的一个对象,这个对象拥有一些重要属性,并且更新 UI 主要就是通过对比(DIFF)旧的虚拟 DOM 树 和新的虚拟 DOM 树的区别完成的。 - 什么是高阶组件?
高阶组件就是一个函数,且该函数接受一个组件作为参数,并返回一个新的组件。
举例:React-Redux 里 [connect 就是一个高阶组件],比如 connect(mapState)(MyComponent)
接受组件 MyComponent,返回一个具有状态的新 MyComponent 组件。
-
React diff 的原理是什么?
-
Redux 是什么?redux - 是怎么实现的, 实现过程
Redux 是 JavaScript 状态容器,提供可预测化的状态管理。重点是『状态管理』。
说出核心概念的名字和作用:Action/Reducer/Store/单向数据流
说出常用 API:store.dispatch(action)/store.getState()
- connect 的原理是什么?
react-redux 库提供的一个 API,connect 的作用是让你把组件和store连接起来,产生一个新的组件(connect 是高阶组件)
10.vue和react的主要区别
-
vue是响应式的数据双向绑定系统,而react是单向数据流,没有双向绑定。
-
vue的语法较为简单,适用于小型项目创建,而react更适用于Web端和原生App的开发,侧重于大型应用。
-
useEffect()怎么使用?
-
setState()函数是同步的还是异步的?
TypeScript
- never 类型是什么?
不应该出现的类型
- TypeScript 比起 JavaScript 有什么优点?
- 提供了类型约束,因此更可控、更容易重构、更适合大型项目、更容易维护
Webpack
webpack 是什么,做了什么?
是一个模块化管理工具兼打包工具
它做的事情是,分析你的项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Scss,TypeScript等),并将其打包为合适的格式以供浏览器使用。
- 有哪些常见 loader 和 plugin,你用过哪些?
file-loader:把文件输出到一个文件夹中,在代码中通过相对 URL 去引用输出的文件
url-loader:和 file-loader 类似,但是能在文件很小的情况下以 base64 的方式把文件内容注入到代码中去
source-map-loader:加载额外的 Source Map 文件,以方便断点调试
image-loader:加载并且压缩图片文件
babel-loader:把 ES6 转换成 ES5
css-loader:加载 CSS,支持模块化、压缩、文件导入等特性
style-loader:把 CSS 代码注入到 JavaScript 中,通过 DOM 操作去加载 CSS。
eslint-loader:通过 ESLint 检查 JavaScript 代码
define-plugin:定义环境变量
mini-css-extract-plugin:抽取css代码,变成一个文件
html-webpack-plugin:用来生成html文件
- 英语题:loader 和 plugin 的区别是什么?
- loader是"加载器",plugin是插件
- 加载器是用来load一个文件的,比如说babel-loader是把高级的变成IE支持的js,css-loader和style-loader是用来加载CSS然后变为页面中的标签
- 插件是用来扩展webpack功能的,比如 html-webpack-plugin,它是用来生成HTML文件的,还有一个mini-css-extract-plugin,它是用来抽取css代码,变成一个文件的
- 如何按需加载代码?
- Vue UI组件库的按需加载,为了快速开发前端项目,经常会引入现成的UI组件库,但是只需要几个组件就行了,造成不必要的开销,现在很多组件库已经提供了现成的解决方案,Element UI里的[babel-plugin-component],只需要在参数中进行设置,即可实现组件按需加载了
- 单页应用的按需加载,现在很多前端项目都是通过单页应用的方式开发的,但是随着业务的不断扩展,会面临一个问题——首次加载的代码量会越来越多,影响用户的体验。可以用懒加载
- 如何提高构建速度?
- 压缩代码。删除多余的代码、注释、简化代码的写法等等方式。
- 删除多余的代码。将代码中永远不会走到的片段删除掉。
5.与webpack类似的工具还有哪些?谈谈你为什么最终选择(或放弃)使用webpack? - webpack适用于大型复杂的前端站点构建
- parcel适用于简单的实验性项目,他可以满足低门槛的快速看到效果
由于parcel在打包过程中给出的调试信息十分有限,所以一旦打包出错难以调试,所以不建议复杂的项目使用parcel
安全
- 什么是 XSS?如何预防?
跨站脚本攻击(Cross Site Scripting)
对特殊字符进行转译
- 什么是 CSRF?如何预防?
跨站请求伪造 (Cross-site request forgery)
使用 post 接口
增加验证,例如密码、短信验证码、指纹等
开放题目
- 你遇到最难的问题是怎样的?
在做记账项目的时候,需要引入SVG,但是我按照官网上提供的方法写完代码后,怎么样都无法在页面显示,这个问题困扰了我一下午,于是在网上搜了好久,最后终于在一个答案中发现要加svg-sprite-loader。 - 你在团队的突出贡献是什么?
我没有团队,一个人开发的
我在我的前端团队组织了定期的前端分享,帮助大家了解最新的前端技术
- 最近在关注什么新技术
- 有没有看什么源码,看了后有什么记忆深刻的地方,有什么收获
变量命名很烂,平时会避免这样命名
- 谈谈你的缺点?
node.js不太了解,不过最近正在学。
- 有什么想问的吗?
公司主要用什么框架
刁钻题目
[1,2,3].map(parseInt) // [1, NaN,NaN]
var a = {name: "a"}
a.x = a = {}
a.x 是多少? // undefined
- (a ==1 && a==2 && a==3) 可能为 true 吗?
- 利用 == 会调用 valueOf() 的特性
var a = {
value: 1,
valueOf(){
return this.value++
}
}
a ==1 && a==2 && a==3 // true
- 利用 a 会读取 window.a 的特性
var value = 1;
Object.defineProperty(window, 'a', {
get(){
return value++;
}
})
a ==1 && a== 2 && a==3 // true
// 或者
a ===1 && a=== 2 && a===3 // true
超纲题(放弃)
- JS 垃圾回收机制
- Eventloop 说一下
算法和数据结构
1.手写选择排序和冒泡排序,快速排序
网友评论