面試題目1
面試題
https://juejin.im/post/5c8e409ee51d4534977bc557#heading-1
https://juejin.im/post/5d136700f265da1b7c6128db
https://juejin.im/post/5a6547d0f265da3e283a1df7
https://juejin.im/post/5e55272e6fb9a07ca453436f
一、頁面佈局
(一)三欄佈局
float 佈局
- 簡單且相容性好,需要清除浮動
<div class="box">
<div class="left" style="float: left;">200px</div>
<div class="right">200px</div>
<div class="center" style="float: right;">自適應</div>
</div>
絕對佈局
- 簡單且相容性好,但脫離文件流
<div class="box" style="position: relative;"> <div class="left" style="position: absolute;left: 0;">200px</div> <div class="right" style="position: absolute;right: 0;">200px</div> <div class="center" style="margin: 0 200px;">自適應</div> </div>
flex 佈局
- 簡單,不支援 IE8 及以下
<div class="box" style="display: flex;"> <div class="left" style="width:200px">200px</div> <div class="center" style="flex:1">自適應</div> <div class="right" style="width:200px">200px</div> </div>
grid佈局
- 簡單,不支援 IE8 及以下
<style>
.box {
width: 100%;
display: grid;
grid-template-columns: 200px auto 200px;
grid-template-rows: 400px;
}
</style>
<div class="box">
<div class="left">200px</div>
<div class="right">200px</div>
<div class="center">自適應</div>
</div>
(二)水平垂直居中
絕對定位 position: absolute
+ transform
.container {
position: relative;
}
.box {
position:absolute;
top:50%;
left:50%;
transform:translate(-50%, -50%);
/*已知高度寬度,margin-top margin-left設定為本身高度寬度的1/2負值*/
}
絕對定位 position: absolute
+ margin: auto
.container {
width: 500px;
height: 500px;
border: 1px solid #000;
position: relative;
}
.box {
width: 200px;
height: 200px;
border: 1px solid #000;
/*需知道子元素的寬高*/
position: absolute;
margin: auto;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
table
組合使用display:table-cell和vertical-align、text-align,使父元素內的所有行內元素水平垂直居中
/*利用 table 的單元格居中效果展示*/
.container {
width: 300px;
height: 300px;
border: 1px solid #000;
display: table-cell;
text-align: center;
vertical-align: middle;
}
.box {
width: 100px;
height: 100px;
display: inline-block;
}
flex
.container {
display:flex;
justify-content: center;
align-items:center;
}
grid
/*方法一:父元素指定子元素的對齊方式*/
.container {
width: 500px;
height: 500px;
display:grid;
justify-content: center;
/*整個內容區域在容器裡面的水平位置*/
align-content: center;
/*整個內容區域的垂直位置*/
}
/*方法二:子元素自己指定自己的對齊方式*/
.out{
width: 300px;
height: 300px;
display: grid;
}
.inner{
width: 100px;
height: 100px;
justify-self: center;
/*設定單元格內容的水平位置*/
align-self:center;
/*設定單元格內容的垂直位置*/
}
二、CSS盒模型
(一)基礎概念
盒子模型組成:分為內容(content)、填充(padding)、邊框(border)和邊界(margin)
-
IE盒模型:屬性width,height包含content、border和padding
-
W3C標準盒模型:屬性width,height只包含內容content,不包含border和padding
(二)設定盒模型
/*設定IE模型*/
box-sizing: border-box;
/*設定標準模型*/
box-sizing: content-box;
(三)塊級格式化上下文 Block Formatting Context
頁面的基本單位是Box, 而元素的型別和 display 屬性,決定了 Box 的型別
不同型別的 Box 會參與不同的 Formatting Context ,Box內的元素會以不同的方式渲染
Formatting Context —— CSS2.1 規範中的一個概念。它是頁面中的一塊渲染區域,並且有一套渲染規則,它決定了其子元素將如何定位,以及和其他元素的關係和相互作用
盒子型別
-
block-level box
- display 屬性為 block, list-item, table 等的元素
- 生成 block-level box且參與 block fomatting context
-
inline-level box
- display 屬性為 inline, inline-block, inline-table 等的元素
- 生成 inline-level box且參與 inline formatting context
-
run-in box
BFC的佈局規則
- 內部的盒子從頂端開始垂直地一個接一個地排列
- 盒子之間垂直的間距是由 margin 決定的
- 在同一個 BFC 中,兩個相鄰的塊級盒子的垂直外邊距會發生重疊
- BFC 區域不會和 float box 發生重疊
- BFC 能夠識別幷包含浮動元素,當計算其區域的高度時,浮動元素也參與計算
- BFC在頁面上的一個隔離的獨立容器,容器裡面的子元素不會影響到外面的元素。反之也如此
建立BFC
(1)根元素
(2)浮動元素float=left|right或inherit(≠none)
(3)絕對定位元素position=absolute或fixed
(4)overflow=hidden|auto或scroll(≠visible)
(5)display=inline-block|flex|inline-flex|table-cell或table-caption
BFC 的作用
-
包含浮動元素(清除浮動)
-
浮動元素會脫離文件流(絕對定位元素也會脫離文件流),導致無法計算準確的高度,這種問題稱為高度塌陷
-
解決高度塌陷問題的前提是能夠識別幷包含浮動元素,也就是清除浮動
解決方法:在容器(container)中建立 BFC
-
-
避免外邊距摺疊
外邊距摺疊(Margin collapsing)只會發生在屬於同一BFC的塊級元素之間。如果它們屬於不同的 BFC,它們之間的外邊距則不會摺疊
三、DOM事件
(一)事件流
- 事件冒泡(Event Bubbling)——從下往上的傳播方式,當一個元素(文件中巢狀層次最深的節點)接收到事件的時會將該事件傳給自己的父級直到頂部
- 事件捕獲(Event Capturing)——與事件冒泡相反
(二)事件模型
DOM0級模型
-
繫結監聽函式
- HTML程式碼中直接繫結:
<button onclick="handleClick()">Press me</button>
- JS程式碼指定屬性值:
element.onclick = function(){}
- HTML程式碼中直接繫結:
-
刪除事件處理
element.onclick = null
-
事件不會傳播,即沒有事件流的概念
DOM2級模型
-
繫結監聽函式
element.addEventListener('click', function(){}, false)
-
刪除事件處理
element.removeEventListener('mousedown', handleMouseDown, false)
-
可以新增多個相同事件的處理程式
-
事件傳播:2級DOM的事件傳播分三個階段進行
(三)事件物件
當一個事件被觸發時,會建立一個事件物件(Event Object), 這個物件裡面包含了與該事件相關的屬性或者方法。該物件會作為第一個引數傳遞給監聽函式
- DOM事件模型中的事件物件常用屬性:
type
用於獲取事件型別target
獲取事件目標stopPropagation()
阻止事件冒泡preventDefault()
阻止事件預設行為
- IE事件模型中的事件物件常用屬性:
type
用於獲取事件型別srcElement
獲取事件目標cancelBubble
阻止事件冒泡returnValue
阻止事件預設行為
(四)事件代理 / 委託
事件代理本質
- 利用事件冒泡的機制,父級元素可以通過事件物件獲取到觸發事件的目標元素,可以把子節點的監聽函式定義在父節點上,由父節點的監聽函式統一處理多個子元素的事件
事件代理優勢
- 減少事件註冊,節省記憶體佔用
- 新增子物件時無需再次對其繫結事件,適合動態新增元素
事件代理例項
<ul id="parent">
<li class="child">one</li>
<li class="child">two</li>
<li class="child">three</li>
</ul>
<script type="text/javascript">
//父元素
var dom= document.getElementById('parent');
//父元素繫結事件,代理子元素的點選事件
dom.onclick= function(event) {
var event= event || window.event;
var curTarget= event.target || event.srcElement;
if (curTarget.tagName.toLowerCase() == 'li') {
//事件處理
}
}
</script>
(五)事件廣播
var event= new Event('build');
// listener for the event
element.addEvenetListener('build', function(e) {...}, false);
//Dispatch the event
element.dispatchEvent(event);
四、HTTP協議
五、原型鏈
(一)原型、建構函式、例項、原型鏈
- 每個函式都有一個prototype屬性指向原型物件。原型物件包含所有例項共享的屬性和方法
- 每個原型都有一個constructor指標,用來指向Prototype屬性所在的函式
- 瀏覽器為例項物件提供一個
__proto__
屬性,用來指向建構函式的原型物件- 獲取例項的原型建議使用
Object.getPrototypeOf(obj)
返回指定物件的原型(內部[[Prototype]]
屬性的值)
- 獲取例項的原型建議使用
- 當原型物件等於其他型別的例項,形成遞進關係直到
Object.prototype
,叫做原型鏈
(二)instanceof 的原理
instanceof
用於檢測建構函式的 prototype
屬性是否出現在某個例項物件的原型鏈上
(三) 判斷變數的型別
typeof
- 基礎資料型別:除了
null
返回"object"
,其他的正確返回 - 引用型別:除了函式會返回
"function"
,其他的返回"object"
- 基礎資料型別:除了
instanceof
Date instanceof Object
Object.prototype.toString.call(..)
——tpyeof
返回object
的物件,內部具有[[class]]屬性用於進一步區分型別Object.prototype.toString.call( [1,2,3] ); //"[object Array]"
variableName === void 0
—— 判斷是否等於 undefined
(四) new操作符
new呼叫建構函式的步驟
- 建立空物件
- 將this指向建立的空物件——建構函式作用域賦給空物件
- 執行建構函式的程式碼——為新物件新增屬性
- 返回新物件
手動實現new
function Person(name, age){
this.name = name;
this.age = age;
}
function _new() {
//1.獲取建構函式
let Func = [].shift.call(arguments)
//2.建立一個空物件obj,並讓其繼承Func.prototype
let obj = Object.create(Func.prototype)
// var obj = {}
// obj.__proto__ = Func.prototype
//3.執行建構函式,並將this指向建立的空物件obj
let res = Func.apply(obj, arguments)
//4.如果建構函式返回的值是物件則返回,不是物件則返回建立的物件obj
return typeof res === 'object' ? res : obj
}
var p1 = _new(Person, '小魚', 18)
Object.create()方法建立一個新物件,使用現有的物件來提供新建立的物件的
__proto__
六、面向物件
(一)面向物件 OOP
- 封裝:低耦合高內聚
- 多型:過載和重寫
- 過載:方法名相同,形參的個數或型別相同
- 重寫:在類的繼承中,子類可以重寫父類中的方法
- 繼承:子類繼承父類的方法
(二)建立物件的方法
工廠模式
- 描述:用函式封裝以特定介面建立物件的細節
function createPerson(name, age, job) {
let o = new Object()
o.name = name
o.age = age
o.job = job
o.sayName() {
console.log(this.name);
}
return o
}
var p1 = createPerson('小魚',18,'web');
p1.sayName(); //小魚
var p2 = createPerson('xiaoyu',22,'java');
p2.sayName(); //xiaoyu
- 缺點:不能識別物件型別
建構函式模式
- 描述:建立自定義的建構函式,從而定義特定型別物件的屬性和方法
function Person(name, age, job) {
this.name = name
this.age = age
this.job = job
this.sayName = function() {
console.log(this.name);
}
}
var p1 = new Person('小魚', 18, 'Web');
var p2 = new Person('xiaoyu', 22, 'java');
//建立物件具有特定型別
p1.constructor === Person //true
//不同的例項上的同名函式是不相等的
p1.sayName === p2.sayName;
- 缺點:每個例項的屬性和方法重新建立,浪費記憶體空間
如果將建構函式中的函式定義為全域性的函式,可以解決同名函式不共享的問題。但是破壞了自定義型別的封裝性
原型模式
- 描述:建立的每個函式都有原型屬性prototype,指向特定型別所有共享的屬性和方法
function Person() {}
Person.prototype = {
name:'小魚',
age:18,
job:'Web',
sayName:function(){
console.log(this.name);
}
};
var p1 = new Person();
console.log(p1.constructor); //[Function: Object]
- 缺點:對於引用型別的屬性,一個例項對其進行修改,也會反映在其他例項上
組合使用建構函式和原型模式
- 描述:建構函式模式定義例項屬性,原型模式定義方法和共享的屬性
function Person(name, age, job) {
this.name = name;
this.age = age;
this.job = job;
this.friends = ['Shelby','Court'];
}
Person.prototype = {
constructor:Person,
sayName:function(){
console.log(this.name);
}
};
var p1 = new Person('小魚',18,'Web');
var p2 = new Person('xioayu',22,'Java');
p1.friends.push('biu');
console.log(p1.friends); //[ 'Shelby', 'Court', 'biu' ]
console.log(p2.friends); //[ 'Shelby', 'Court' ]
動態原型模式
- 描述:把所有資訊都封裝在建構函式中,通過判斷某一方法是否存在來決定是否需要初始化原型
function Person(name,age,job){
this.name = name;
this.age = age;
this.job = job;
this.friends = ['Shelby','Court'];
if(typeof this.sayName !== 'function'){
Person.prototype.sayName = function(){
console.log(this.name);
}
}
}
var p1 = new Person('小魚', 18,'Web');
p1.sayName(); //小魚
(三)類的繼承
建構函式繼承
借用建構函式:在子類建構函式內部呼叫超類建構函式