HTML部分
1. 你是如何理解 HTML 语义化的?
语义化是指根据内容的结构化(内容语义化),选择合适的标签(代码语义化),便于开发者阅读和写出更优雅的代码的同时,让浏览器的爬虫和机器很好的解析。
标题用h1-h5。文章用artical。段落用p。时间用time标签。 header标签,footer标签,main标签, nav,artical标签。
html分的历史阶段:
- 后台开发写前端页面
使用table标签。会出现table套table的窘境 - 美工阶段
div+css布局。不够语义化。 - 前端阶段
语义化标签
2. meta viewport 是做什么用的,怎么写?
移动设备上的viewport就是设备的屏幕上能用来显示我们的网页的那一块区域。比如浏览器的可展示区域
<meta name="viewport" content="width=device-width,initial-scale=1">
width设置layout viewport的宽度,为一个正整数,或字符串"width-device"
initial-scale设置页面的最大缩放值,为一个数字,可以带小数
minimum-scale允许用户的最小缩放值,为一个数字,可以带小数
maximum-scale允许用户的最大缩放值,为一个数字,可以带小数
height设置layout viewport的高度,这个属性并不重要,很少使用
user-scalable 是否允许用户进行缩放,值为"no"或"yes"
CSS
两种盒模型
-
box-sizing: conent-box;
将盒子设置为标准模型(盒子默认为标准模型) -
box-sizing: border-box;
将盒子设置为 IE 模型(也叫做怪异盒子)
content-box { width: 100px; height: 100px; border: 50px solid; padding: 50px;}
在标准模型中,它在页面中实际占有的宽高为300px
在IE 模型中,它的页面实际占有宽度还是100px。由于 border + padding 已经等于 100px 了,所以这里 content 已经被压缩到只剩 0 了
什么是边距重叠
两种现象
- 同一层相邻元素
<style>
.box-1 {
width: 100px;
height: 100px;
margin-bottom: 50px; /* 会出现重叠。不会出现100px的合边距。 只有50px;*/
background-color: aqua;
}
.box-2 {
width: 100px;
height: 100px;
margin-top: 50px; /* 会出现重叠。不会出现100px的合边距。 只有50px;*/
background-color: blueviolet;
}
</style>
<div class="box-1"></div>
<div class="box-2"></div>
- 父元素和子元素之间没有内容
<div class="futher">
<div class="child"></div>
</div>
<style>
* { margin: 0; padding: 0;}
.futher {
background: deeppink;
}
.child {
margin-top: 50px; /*父元素也会跟着有个50px的margin-top*/
height: 100px;
background: deepskyblue;
}
</style>
实现垂直居中
如果 .parent 的 height 不写,你只需要 padding: 10px 0; 就能将 .child 垂直居中;
如果父元素height写了高度
<div id="box">
<div id="child"></div>
</div>
#box {
width: 300px;
height: 300px;
background: #ddd;
position: relative;
}
#child {
width: 150px;
height: 100px;
background: orange;
position: absolute;
top: 50%;
margin: -50px 0 0 0;
}
#box {
width: 300px;
height: 300px;
background: #ddd;
position: relative;
}
#child {
background: orange;
position: absolute;
top: 50%;
transform: translate(0, -50%);
}
#box {
width: 300px;
height: 300px;
background: #ddd;
display: flex;
align-items: center;
}
#box {
width: 300px;
height: 300px;
background: #ddd;
position: relative;
}
#child{
background: orange;
position: absolute;
width: 150px;
height: 100px;
margin: auto;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
水平垂直居中
- 水平居中
margin: 0 auto;
<div class="wrap">
<div class="example2">
</div>
</div>
.wrap {
position: relative;
background-color: orange;
width: 300px;
height: 300px;
}
.example2 {
background-color: red;
width: 100px;
height: 100px;
position: absolute;
left: 50%;
top: 50%;
margin: -50px 0 0 -50px;
}
flex布局
<div class="warp">
<div class="example3">
居中显示
</div>
</div>
.warp {
position: relative;
background-color: orange;
width: 200px;
height: 200px;
}
.example3 {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: red;
width: 100px;
height: 100px;
margin: auto;
}
.warp {
position: relative;
background-color: orange;
width: 200px;
height: 200px;
}
.example3 {
position: relative;
top:50%;
transform:translateY(-50%);
background-color: red;
width: 100px;
height: 100px;
margin: 0 auto;
}
BFC
块格式化上下文
1.给父元素overflow:hidden。那么其浮动的子元素就会被包裹
-
兄弟之间划清界限
假设现在有一对兄弟 div,其中一个加了浮动,那么两个 div 会重叠一部分
如果让另一个 div 创建 BFC,那么这两者就会界限分明。
css优先级
内联 > ID选择器 > 类选择器 > 标签选择器。
- 越具体优先级越高
- 写在后面的覆盖前面的
- important ! 优先级最高。少用。
清楚浮动
.clearFix {
content: '';
display: block;
clear: both;
}
js
ES6 语法知道哪些,分别怎么用?
- 块级作用域
let变量,const常量 - 箭头函数
。 默认参数
。 剩余参数: 剩余参数语法允许我们将一个不定数量的参数表示为一个数组
。 展开运算符: 可以展开数组
function multiply(a, b = 1) {
return a * b;
}
console.log(multiply(5)); // 5
function fun1(...theArgs) {
alert(theArgs.length);
}
fun1(5, 6, 7); // 弹出 "3", 因为theArgs有三个元素
function sum(x, y, z) {
return x + y + z;
}
const numbers = [1, 2, 3];
console.log(sum(...numbers));
// expected output: 6
[...iterableObj, '4', ...'hello', 6]; // 数组合并
- 模板字符串
- 对象属性加强
。 属性定义支持短语法 obj = { x, y } - 解构赋值
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
- 类
- Promise
手写函数防抖和函数节流
节流
一段时间执行一次之后,就不执行第二次
functiong fn() {}
let cd = false // 技能是否在冷却
button.onclick = function () {
if(cd) {
// 在冷却,什么也不错
} else {
fn() // 执行函数 或者fn在setTimeout里面执行。相当于施法有吟唱时间
cd = true
setTimeout(() => {
cd = false
}, 3000)
}
}
防抖
用户在1s内连续点击两次。只执行最后一次。等一秒之后再执行。如果一秒内再次触发。则清除上次的执行timeout
比如再拖动窗口的时候。用户再一秒内可能改变了很多次窗口的大小。此时我只执行最后一次
function fn () {}
var timerId = null
button.onclick = function () {
if(timerId) {
window.clearTimeout(timerId)
}
timerId = setTimeout(() => {
fn()
timerId = null
}, 1000)
}
手写一个AJAX
function ajax() {
let request = new XMLHttpRequest()
request.open('get', 'https://www.google.com') // 请求方式和请求路径
request.onreadystatechange = () => { // 监听状态
if (request.readyState === 4) { // 0:代理创建 1:open方法被调用 2:send方法被调用 3:下载中 4: 下载操作已完成
if (request.status >= 200 && request.status <300) {
let string = request.responseText
let object = JSON.parse(string)
}
}
}
request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); // 设置请求头
request.send(data) // 要传的参数 可以使用JSON.stringify()和JSON.parse()进行转换
}
this是什么
闭包/立即执行函数是什么?
「函数」和「函数内部能访问到的变量」(也叫环境)的总和,就是一个闭包。
function foo(){
var local = 1
function bar(){ // bar 和local就形成了闭包。此时我需要把bar返回出去。这样外面就能方问到里面的局部变量
local++
return local
}
return bar
}
var func = foo()
func()
或者
!function(){
var lives = 50
window.奖励一条命 = function(){
lives += 1
}
window.死一条命 = function(){
lives -= 1
}
}()
在其他js文件中就能通过windown.奖励一条命等去操作局部变量 lives
(function(){alert('我是匿名函数')}) () //用括号把函数包起来
!function(){alert('我是匿名函数')}() // 求反,我们不在意值是多少,只想通过语法检查。 常用形式
+function(){alert('我是匿名函数')}()
-function(){alert('我是匿名函数')}()
~function(){alert('我是匿名函数')}()
立即执行函数的作用 创建一个独立的作用域。
var liList = ul.getElementsByTagName('li')
for(var i=0; i<6; i++){
liList[i].onclick = function(){
alert(i) // 为什么 alert 出来的总是 6,而不是 0、1、2、3、4、5。 因为i是全局变量
}
}
var liList = ul.getElementsByTagName('li')
for(var i = 0; i< 6: i++) {
!function(ii){
liList.onclick = function() {
alert(ii) // 0 1 2 3 4 5
}
}(i)
}
JSONP是什么
jsonp的核心是动态添加<script>标签来调用服务器提供的js脚本。
例子一
跨域服务器
文件:remote.js
代码:
alert('我是远程文件');
本地
<script type="text/javascript" src="跨域服务器/remote.js"></script>
例子二
跨域服务器
文件:
remote.js
代码:
localHandler({"result":"我是远程js带来的数据"});
本地
<script type="text/javascript">
var localHandler = function(data){
alert('我是本地函数,可以被跨域的remote.js文件调用,远程js带来的数据是:' + data.result);
};
</script>
<script type="text/javascript" src="跨域服务器/remote.js"></script>
例子三(我需要告诉服务器我的回调名称及参数)
跨域服务器
文件:flightResult.php
代码:
flightHandler({ "code":"CA1998", "price": 1780, "tickets": 5 });
本地
<script type="text/javascript">
// 得到航班信息查询结果后的回调函数
var flightHandler = function(data){
alert('你查询的航班结果是:票价 ' + data.price + ' 元,' + '余票 ' + data.tickets + ' 张。');
};
// 提供jsonp服务的url地址(不管是什么类型的地址,最终生成的返回值都是一段javascript代码)
var url = "跨域服务器/flightResult.php?code=CA1998&callback=flightHandler";
// 创建script标签,设置其属性
var script = document.createElement('script');
script.setAttribute('src', url);
// 把script标签加入head,此时调用开始
document.getElementsByTagName('head')[0].appendChild(script);
</script>
CORS是什么
它允许浏览器向跨源服务器。
浏览器将CORS请求分成两类:简单请求和非简单请求。
只要同时满足以下两大条件,就属于简单请求。
- 请求方法是以下三种方法之一:
HEAD
GET
POST- HTTP的头信息不超出以下几种字段:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain
对于简单请求,浏览器直接发出CORS请求。具体来说,就是在头信息之中,增加一个Origin字段。
Origin字段用来说明,本次请求来自哪个源(协议 + 域名 + 端口)。服务器根据这个值,决定是否同意这次请求。
GET /cors HTTP/1.1
Origin: http://api.bob.com // 来自哪里
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...
如果
Origin
指定的源,不在许可范围内,服务器会返回一个正常的HTTP回应。浏览器发现,这个回应的头信息没有包含Access-Control-Allow-Origin
字段(详见下文),就知道出错了,从而抛出一个错误,被XMLHttpRequest
的onerror
回调函数捕获。
如果Origin指定的域名在许可范围内,服务器返回的响应,会多出几个头信息字段。
//它的值要么是请求时Origin字段的值,要么是一个*,表示接受任意域名的请求。
Access-Control-Allow-Origin: http://api.bob.com 该字段是必须的。
// 该字段可选。它的值是一个布尔值,表示是否允许发送Cookie。
Access-Control-Allow-Credentials: true
withCredentials 属性
CORS请求默认不发送Cookie和HTTP认证信息。
一方面服务器端需要同意,设置
Access-Control-Allow-Credentials: true
另一方面前端开发设置
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
非简单请求
比如请求方法是
PUT
或DELETE
,或者Content-Type
字段的类型是application/json
。
非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求(preflight)
服务器收到"预检"请求以后,检查了
Origin
(来源)、Access-Control-Request-Method
(请求方法)和Access-Control-Request-Headers
(额外发送的头信息)字段以后,确认允许跨源请求,就可以做出回应。
一旦服务器通过了"预检"请求,以后每次浏览器正常的CORS请求,就都跟简单请求一样
深拷贝
JSON.parse(JSON.stringify())
能完成大部分数据得深拷贝。但存在问题
1.undefined、function、symbol这三种类型的值就是非安全的,所以格式化后,就被过滤掉了
- set、map这种数据格式的对象,也并没有被正确处理,而是处理成了一个空对象
- 循环引用报错
- 相同的引用会被重复复制
**写一个递归调用得函数进行深拷贝
function deepCopy(data) {
if(typeof data !== 'object' || data === null){
throw new TypeError('传入参数不是对象')
}
let newData = {};
const dataKeys = Object.keys(data);
dataKeys.forEach(value => {
const currentDataValue = data[value];
// 基本数据类型的值和函数直接赋值拷贝
if (typeof currentDataValue !== "object" || currentDataValue === null) {
newData[value] = currentDataValue;
} else if (Array.isArray(currentDataValue)) {
// 实现数组的深拷贝
newData[value] = [...currentDataValue];
} else if (currentDataValue instanceof Set) {
// 实现set数据的深拷贝
newData[value] = new Set([...currentDataValue]);
} else if (currentDataValue instanceof Map) {
// 实现map数据的深拷贝
newData[value] = new Map([...currentDataValue]);
} else {
// 普通对象则递归赋值
newData[value] = deepCopy(currentDataValue);
}
});
return newData;
}
测试数据
// 测试数据项
var data = {
age: 18,
name: "liuruchao",
education: ["小学", "初中", "高中", "大学", undefined, null],
likesFood: new Set(["fish", "banana"]),
friends: [
{ name: "summer", sex: "woman"},
{ name: "daWen", sex: "woman"},
{ name: "yang", sex: "man" }
],
work: {
time: "2019",
project: { name: "test",obtain: ["css", "html", "js"]}
},
play: function() {console.log("玩滑板");}
}
如何用正则实现 trim()?
function trim(string){
return string.replace(/^\s+|\s+$/g, '')
}
不用 class 如何实现继承?用 class 又如何实现?
不用class
function Animal(name){
this.name = name;
this.colors = ["red", "blue", "green"];
}
Animal.prototype.sayName = function(){
console.log(this.name);
}
function Dog(name, age){
//继承属性
Animal.call(this, name);
this.age = age;
}
let f = function () {}
f.prototype = Animal.prototype
//继承方法
Dog.prototype = new f();
Dog.prototype.constructor = Dog;
Dog.prototype.sayAge = function(){
alert(this.age);
};
用class实现继承
class Animal{
constructor(color){
this.color = color
}
move(){}
}
class Dog extends Animal{
constructor(color, name){
super(color)
this.name = name
}
say(){}
}
数组去重
- 利用indexOf实现去重。
indexOf()方法返回在数组中可以找到一个给定元素的第一个索引,如果不存在,则返回-1。
function unique(arr) {
if (!Array.isArray(arr)) {
console.log('type error!')
return
}
let res = []
for (let i = 0; i < arr.length; i++) {
if (res.indexOf(arr[i]) === -1) {
res.push(arr[i])
}
}
return res
}
- 相邻元素去重
先用sort进行排序
function unique(arr) {
if (!Array.isArray(arr)) {
console.log('type error!')
return
}
arr = arr.sort()
let res = []
for (let i = 0; i < arr.length; i++) {
if (arr[i] !== arr[i-1]) {
res.push(arr[i])
}
}
return res
}
- 使用set
set中的值是唯一的
function unique(arr) {
if (!Array.isArray(arr)) {
console.log('type error!')
return
}
return [...new Set(arr)]
}
DOM
事件冒泡、事件捕获、事件委托
<div class="father">
<div class="child"></div>
</div>
用户点击,当father和child都存在点击事件时,先执行哪一个事件
事件冒泡认为应该先从子元素开始执行。往后面冒泡。
事件捕获则是从父元素开始执行。最后执行子元素。
event.stopPropagation()可组织事件冒泡或者捕获。
在子元素点击事件执行时添加stopPropagation就可以组织父元素的点击事件执行
addEventListener第三个参数可以设置事件冒泡或者事件捕获
ul.addEventListener('click', function(e){
if(e.target.tagName.toLowerCase() === 'li'){
fn() // 执行某个函数
}
}) // 默认为false。事件冒泡
高阶版
当li里面有个span。点击了span
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
}
HTTP
HTTP 状态码知道哪些?分别什么意思?
- 100 Continue
这个临时响应表明,迄今为止的所有内容都是可行的,客户端应该继续请求,如果已经完成,则忽略它。 - 102 Processing
此代码表示服务器已收到并正在处理该请求,但没有响应可用。 - 200 OK
请求成功 - 201 Created
该请求已成功,并因此创建了一个新的资源。这通常是在POST请求,或是某些PUT请求之后返回的响应。 - 204 No content
服务器成功处理了请求,但不需要返回任何实体内容 - 301 Moved Permanently
被请求的资源已永久移动到新位置. - 302 Found
请求的资源现在临时从不同的 URI 响应请求。由于这样的重定向是临时的,客户端应当继续向原有地址发送以后的请求。 - 400 Bad Request
1、语义有误,当前请求无法被服务器理解。除非进行修改,否则客户端不应该重复提交这个请求。
2、请求参数有误。 - 403 Forbidden
服务器已经理解请求,但是拒绝执行它。权限 - 404 No Found
请求失败,请求所希望得到的资源未被在服务器上发现。 - 500 Internal Server Error
服务器遇到了不知道如何处理的情况。
2开头一般表示成功。3开头表示需要进一步的操作。4开头表示客户端错误。5开头表示服务器端错误。