HTML部分
1. 你是如何理解 HTML 語義化的?
語義化是指根據(jù)內(nèi)容的結(jié)構(gòu)化(內(nèi)容語義化),選擇合適的標(biāo)簽(代碼語義化),便于開發(fā)者閱讀和寫出更優(yōu)雅的代碼的同時,讓瀏覽器的爬蟲和機(jī)器很好的解析。
標(biāo)題用h1-h5。文章用artical。段落用p。時間用time標(biāo)簽。 header標(biāo)簽,footer標(biāo)簽,main標(biāo)簽, nav,artical標(biāo)簽。
html分的歷史階段:
- 后臺開發(fā)寫前端頁面
使用table標(biāo)簽。會出現(xiàn)table套table的窘境 - 美工階段
div+css布局。不夠語義化。 - 前端階段
語義化標(biāo)簽
2. meta viewport 是做什么用的,怎么寫?
移動設(shè)備上的viewport就是設(shè)備的屏幕上能用來顯示我們的網(wǎng)頁的那一塊區(qū)域。比如瀏覽器的可展示區(qū)域
<meta name="viewport" content="width=device-width,initial-scale=1">
width設(shè)置layout viewport的寬度,為一個正整數(shù),或字符串"width-device"
initial-scale設(shè)置頁面的最大縮放值,為一個數(shù)字,可以帶小數(shù)
minimum-scale允許用戶的最小縮放值,為一個數(shù)字,可以帶小數(shù)
maximum-scale允許用戶的最大縮放值,為一個數(shù)字,可以帶小數(shù)
height設(shè)置layout viewport的高度,這個屬性并不重要,很少使用
user-scalable 是否允許用戶進(jìn)行縮放,值為"no"或"yes"
CSS
兩種盒模型
-
box-sizing: conent-box;將盒子設(shè)置為標(biāo)準(zhǔn)模型(盒子默認(rèn)為標(biāo)準(zhǔn)模型) -
box-sizing: border-box;將盒子設(shè)置為 IE 模型(也叫做怪異盒子)
content-box { width: 100px; height: 100px; border: 50px solid; padding: 50px;}
在標(biāo)準(zhǔn)模型中,它在頁面中實(shí)際占有的寬高為300px
在IE 模型中,它的頁面實(shí)際占有寬度還是100px。由于 border + padding 已經(jīng)等于 100px 了,所以這里 content 已經(jīng)被壓縮到只剩 0 了
什么是邊距重疊
兩種現(xiàn)象
- 同一層相鄰元素
<style>
.box-1 {
width: 100px;
height: 100px;
margin-bottom: 50px; /* 會出現(xiàn)重疊。不會出現(xiàn)100px的合邊距。 只有50px;*/
background-color: aqua;
}
.box-2 {
width: 100px;
height: 100px;
margin-top: 50px; /* 會出現(xiàn)重疊。不會出現(xiàn)100px的合邊距。 只有50px;*/
background-color: blueviolet;
}
</style>
<div class="box-1"></div>
<div class="box-2"></div>
- 父元素和子元素之間沒有內(nèi)容
<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>
實(shí)現(xiàn)垂直居中
如果 .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。那么其浮動的子元素就會被包裹
-
兄弟之間劃清界限
假設(shè)現(xiàn)在有一對兄弟 div,其中一個加了浮動,那么兩個 div 會重疊一部分
4.png
如果讓另一個 div 創(chuàng)建 BFC,那么這兩者就會界限分明。

css優(yōu)先級
內(nèi)聯(lián) > ID選擇器 > 類選擇器 > 標(biāo)簽選擇器。
- 越具體優(yōu)先級越高
- 寫在后面的覆蓋前面的
- important ! 優(yōu)先級最高。少用。
清楚浮動
.clearFix {
content: '';
display: block;
clear: both;
}
js
ES6 語法知道哪些,分別怎么用?
- 塊級作用域
let變量,const常量 - 箭頭函數(shù)
。 默認(rèn)參數(shù)
。 剩余參數(shù): 剩余參數(shù)語法允許我們將一個不定數(shù)量的參數(shù)表示為一個數(shù)組
。 展開運(yùn)算符: 可以展開數(shù)組
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]; // 數(shù)組合并
- 模板字符串
- 對象屬性加強(qiáng)
。 屬性定義支持短語法 obj = { x, y } - 解構(gòu)賦值
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
手寫函數(shù)防抖和函數(shù)節(jié)流
節(jié)流
一段時間執(zhí)行一次之后,就不執(zhí)行第二次
functiong fn() {}
let cd = false // 技能是否在冷卻
button.onclick = function () {
if(cd) {
// 在冷卻,什么也不錯
} else {
fn() // 執(zhí)行函數(shù) 或者fn在setTimeout里面執(zhí)行。相當(dāng)于施法有吟唱時間
cd = true
setTimeout(() => {
cd = false
}, 3000)
}
}
防抖
用戶在1s內(nèi)連續(xù)點(diǎn)擊兩次。只執(zhí)行最后一次。等一秒之后再執(zhí)行。如果一秒內(nèi)再次觸發(fā)。則清除上次的執(zhí)行timeout
比如再拖動窗口的時候。用戶再一秒內(nèi)可能改變了很多次窗口的大小。此時我只執(zhí)行最后一次
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 = () => { // 監(jiān)聽狀態(tài)
if (request.readyState === 4) { // 0:代理創(chuàng)建 1:open方法被調(diào)用 2:send方法被調(diào)用 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'); // 設(shè)置請求頭
request.send(data) // 要傳的參數(shù) 可以使用JSON.stringify()和JSON.parse()進(jìn)行轉(zhuǎn)換
}
this是什么
閉包/立即執(zhí)行函數(shù)是什么?
「函數(shù)」和「函數(shù)內(nèi)部能訪問到的變量」(也叫環(huán)境)的總和,就是一個閉包。
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('我是匿名函數(shù)')}) () //用括號把函數(shù)包起來
!function(){alert('我是匿名函數(shù)')}() // 求反,我們不在意值是多少,只想通過語法檢查。 常用形式
+function(){alert('我是匿名函數(shù)')}()
-function(){alert('我是匿名函數(shù)')}()
~function(){alert('我是匿名函數(shù)')}()
立即執(zhí)行函數(shù)的作用 創(chuàng)建一個獨(dú)立的作用域。
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的核心是動態(tài)添加<script>標(biāo)簽來調(diào)用服務(wù)器提供的js腳本。
例子一
跨域服務(wù)器
文件:remote.js
代碼:
alert('我是遠(yuǎn)程文件');
本地
<script type="text/javascript" src="跨域服務(wù)器/remote.js"></script>
例子二
跨域服務(wù)器
文件:
remote.js
代碼:
localHandler({"result":"我是遠(yuǎn)程js帶來的數(shù)據(jù)"});
本地
<script type="text/javascript">
var localHandler = function(data){
alert('我是本地函數(shù),可以被跨域的remote.js文件調(diào)用,遠(yuǎn)程js帶來的數(shù)據(jù)是:' + data.result);
};
</script>
<script type="text/javascript" src="跨域服務(wù)器/remote.js"></script>
例子三(我需要告訴服務(wù)器我的回調(diào)名稱及參數(shù))
跨域服務(wù)器
文件:flightResult.php
代碼:
flightHandler({ "code":"CA1998", "price": 1780, "tickets": 5 });
本地
<script type="text/javascript">
// 得到航班信息查詢結(jié)果后的回調(diào)函數(shù)
var flightHandler = function(data){
alert('你查詢的航班結(jié)果是:票價 ' + data.price + ' 元,' + '余票 ' + data.tickets + ' 張。');
};
// 提供jsonp服務(wù)的url地址(不管是什么類型的地址,最終生成的返回值都是一段javascript代碼)
var url = "跨域服務(wù)器/flightResult.php?code=CA1998&callback=flightHandler";
// 創(chuàng)建script標(biāo)簽,設(shè)置其屬性
var script = document.createElement('script');
script.setAttribute('src', url);
// 把script標(biāo)簽加入head,此時調(diào)用開始
document.getElementsByTagName('head')[0].appendChild(script);
</script>
CORS是什么
它允許瀏覽器向跨源服務(wù)器。
瀏覽器將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
對于簡單請求,瀏覽器直接發(fā)出CORS請求。具體來說,就是在頭信息之中,增加一個Origin字段。
Origin字段用來說明,本次請求來自哪個源(協(xié)議 + 域名 + 端口)。服務(wù)器根據(jù)這個值,決定是否同意這次請求。
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指定的源,不在許可范圍內(nèi),服務(wù)器會返回一個正常的HTTP回應(yīng)。瀏覽器發(fā)現(xiàn),這個回應(yīng)的頭信息沒有包含Access-Control-Allow-Origin字段(詳見下文),就知道出錯了,從而拋出一個錯誤,被XMLHttpRequest的onerror回調(diào)函數(shù)捕獲。
如果Origin指定的域名在許可范圍內(nèi),服務(wù)器返回的響應(yīng),會多出幾個頭信息字段。
//它的值要么是請求時Origin字段的值,要么是一個*,表示接受任意域名的請求。
Access-Control-Allow-Origin: http://api.bob.com 該字段是必須的。
// 該字段可選。它的值是一個布爾值,表示是否允許發(fā)送Cookie。
Access-Control-Allow-Credentials: true
withCredentials 屬性
CORS請求默認(rèn)不發(fā)送Cookie和HTTP認(rèn)證信息。
一方面服務(wù)器端需要同意,設(shè)置
Access-Control-Allow-Credentials: true
另一方面前端開發(fā)設(shè)置
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
非簡單請求
比如請求方法是
PUT或DELETE,或者Content-Type字段的類型是application/json。
非簡單請求的CORS請求,會在正式通信之前,增加一次HTTP查詢請求,稱為"預(yù)檢"請求(preflight)
服務(wù)器收到"預(yù)檢"請求以后,檢查了
Origin(來源)、Access-Control-Request-Method(請求方法)和Access-Control-Request-Headers(額外發(fā)送的頭信息)字段以后,確認(rèn)允許跨源請求,就可以做出回應(yīng)。
一旦服務(wù)器通過了"預(yù)檢"請求,以后每次瀏覽器正常的CORS請求,就都跟簡單請求一樣
深拷貝
JSON.parse(JSON.stringify())
能完成大部分?jǐn)?shù)據(jù)得深拷貝。但存在問題
1.undefined、function、symbol這三種類型的值就是非安全的,所以格式化后,就被過濾掉了
- set、map這種數(shù)據(jù)格式的對象,也并沒有被正確處理,而是處理成了一個空對象
- 循環(huán)引用報錯
- 相同的引用會被重復(fù)復(fù)制
**寫一個遞歸調(diào)用得函數(shù)進(jìn)行深拷貝
function deepCopy(data) {
if(typeof data !== 'object' || data === null){
throw new TypeError('傳入?yún)?shù)不是對象')
}
let newData = {};
const dataKeys = Object.keys(data);
dataKeys.forEach(value => {
const currentDataValue = data[value];
// 基本數(shù)據(jù)類型的值和函數(shù)直接賦值拷貝
if (typeof currentDataValue !== "object" || currentDataValue === null) {
newData[value] = currentDataValue;
} else if (Array.isArray(currentDataValue)) {
// 實(shí)現(xiàn)數(shù)組的深拷貝
newData[value] = [...currentDataValue];
} else if (currentDataValue instanceof Set) {
// 實(shí)現(xiàn)set數(shù)據(jù)的深拷貝
newData[value] = new Set([...currentDataValue]);
} else if (currentDataValue instanceof Map) {
// 實(shí)現(xiàn)map數(shù)據(jù)的深拷貝
newData[value] = new Map([...currentDataValue]);
} else {
// 普通對象則遞歸賦值
newData[value] = deepCopy(currentDataValue);
}
});
return newData;
}
測試數(shù)據(jù)
// 測試數(shù)據(jù)項
var data = {
age: 18,
name: "liuruchao",
education: ["小學(xué)", "初中", "高中", "大學(xué)", 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("玩滑板");}
}
如何用正則實(shí)現(xiàn) trim()?
function trim(string){
return string.replace(/^\s+|\s+$/g, '')
}
不用 class 如何實(shí)現(xiàn)繼承?用 class 又如何實(shí)現(xiàn)?
不用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實(shí)現(xiàn)繼承
class Animal{
constructor(color){
this.color = color
}
move(){}
}
class Dog extends Animal{
constructor(color, name){
super(color)
this.name = name
}
say(){}
}
數(shù)組去重
- 利用indexOf實(shí)現(xiàn)去重。
indexOf()方法返回在數(shù)組中可以找到一個給定元素的第一個索引,如果不存在,則返回-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進(jìn)行排序
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>
用戶點(diǎn)擊,當(dāng)father和child都存在點(diǎn)擊事件時,先執(zhí)行哪一個事件
事件冒泡認(rèn)為應(yīng)該先從子元素開始執(zhí)行。往后面冒泡。
事件捕獲則是從父元素開始執(zhí)行。最后執(zhí)行子元素。
event.stopPropagation()可組織事件冒泡或者捕獲。
在子元素點(diǎn)擊事件執(zhí)行時添加stopPropagation就可以組織父元素的點(diǎn)擊事件執(zhí)行
addEventListener第三個參數(shù)可以設(shè)置事件冒泡或者事件捕獲
ul.addEventListener('click', function(e){
if(e.target.tagName.toLowerCase() === 'li'){
fn() // 執(zhí)行某個函數(shù)
}
}) // 默認(rèn)為false。事件冒泡
高階版
當(dāng)li里面有個span。點(diǎn)擊了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 狀態(tài)碼知道哪些?分別什么意思?
- 100 Continue
這個臨時響應(yīng)表明,迄今為止的所有內(nèi)容都是可行的,客戶端應(yīng)該繼續(xù)請求,如果已經(jīng)完成,則忽略它。 - 102 Processing
此代碼表示服務(wù)器已收到并正在處理該請求,但沒有響應(yīng)可用。 - 200 OK
請求成功 - 201 Created
該請求已成功,并因此創(chuàng)建了一個新的資源。這通常是在POST請求,或是某些PUT請求之后返回的響應(yīng)。 - 204 No content
服務(wù)器成功處理了請求,但不需要返回任何實(shí)體內(nèi)容 - 301 Moved Permanently
被請求的資源已永久移動到新位置. - 302 Found
請求的資源現(xiàn)在臨時從不同的 URI 響應(yīng)請求。由于這樣的重定向是臨時的,客戶端應(yīng)當(dāng)繼續(xù)向原有地址發(fā)送以后的請求。 - 400 Bad Request
1、語義有誤,當(dāng)前請求無法被服務(wù)器理解。除非進(jìn)行修改,否則客戶端不應(yīng)該重復(fù)提交這個請求。
2、請求參數(shù)有誤。 - 403 Forbidden
服務(wù)器已經(jīng)理解請求,但是拒絕執(zhí)行它。權(quán)限 - 404 No Found
請求失敗,請求所希望得到的資源未被在服務(wù)器上發(fā)現(xiàn)。 - 500 Internal Server Error
服務(wù)器遇到了不知道如何處理的情況。
2開頭一般表示成功。3開頭表示需要進(jìn)一步的操作。4開頭表示客戶端錯誤。5開頭表示服務(wù)器端錯誤。
