js中new一個物件的過程
使用new關鍵字呼叫函式(new ClassA(…))的具體步驟:
1. 建立空物件;
var obj = {};
2. 設定新物件的constructor屬性為建構函式的名稱,設定新物件的__proto__屬性指向建構函式的prototype物件;
obj.__proto__ = ClassA.prototype;
3. 使用新物件呼叫函式,函式中的this被指向新例項物件:
ClassA.call(obj);  //{}.建構函式();
4. 將初始化完畢的新物件地址,儲存到等號左邊的變數中
複製程式碼
什麼是閉包?閉包的優缺點
答:閉包是將外部作用域中的區域性變數封閉起來的函式物件。被封閉起來的變數與封閉它的函式物件有相同的生命週期。
優點:一個是前面提到的可以讀取函式內部的變數,另一個就是讓這些變數的值始終保持在記憶體中,不會在f1呼叫後被自動清除。
缺點:
- 由於閉包會使得函式中的變數都被儲存在記憶體中,記憶體消耗很大,所以不能濫用閉包,否則會造成網頁的效能問題,在IE中可能導致記憶體洩露。解決方法是,在退出函式之前,將不使用的區域性變數全部刪除。
- 閉包會在父函式外部,改變父函式內部變數的值。所以,如果你把父函式當作物件(object)使用,把閉包當作它的公用方法(Public Method),把內部變數當作它的私有屬性(private value),這時一定要小心,不要隨便改變父函式內部變數的值。
什麼是盒子模型?CSS-標準盒模型和怪異盒模型的區別?哪個css可以改變盒子模型?
css盒子模型 又稱為框模型(Box Model),包含了元素內容(content)、內邊距(padding)、邊框(border)、外邊距(margin)幾個要素。
標準盒模型
怪異盒模型
區別:當不對doctype進行定義時,會觸發怪異模式。
- 在標準模式下,一個塊的總寬度= width + margin(左右) + padding(左右) + border(左右)
- 在怪異模式下,一個塊的總寬度= width + margin(左右)(即width已經包含了padding和border值)
怎麼使div水平居中,垂直居中,水平垂直居中?
以一個分頁dom為例
dom結構
<div class="pagination">
<ul>
<li><a href="#">1</a></li>
<li><a href="#">2</a></li>
<li><a href="#">3</a></li>
<li><a href="#">4</a></li>
<li><a href="#">5</a></li>
</ul>
</div>
複製程式碼
水平居中
垂直居中
水平垂直居中
position取值
- static 預設值 沒有定位
- inherit 規定應該從父元素繼承position屬性的值
- relative 生成相對定位的元素,相對於其正常位置進行定位
- absolute 絕對定位 相對於static以外的第一個父元素進行定位
- fixed 絕對定位 相對於瀏覽器視窗進行定位
sticky佈局
法一:
dom結構
<div class="wrapper">
<header>header</header>
<section style="height:300px">內容</section>
</div>
<footer>designer by echo hu</footer>
複製程式碼
css
/*相同dom不同css*/
第一種樣式
footer {
height: 7em;
background: #3c3c3c;
}
.wrapper {
width: 100%;
min-height: calc(100vh - 7em);
}
第二種樣式
html,body{
height:100%;
}
footer{
height:7em;
}
.wrapper{
height:calc(100% - 7em);
}
複製程式碼
法二:
dom結構
<div class="wrapper">
<div class="main">
<div class="content"></div>
</div>
<div class="close"></div>
</div>
複製程式碼
css樣式
.wrapper{
width:100%;
height:100%;
}
.main{
min-height:100%;
}
.close{
width:100%;
height:32px;
margin-top:-32px;
}
複製程式碼
flex佈局
what is flex?
flex是Flexible Box的縮寫,意為彈性佈局。
任何一個容器都可指定為flex佈局
.box{
display:flex;
}
複製程式碼
行內元素也可以使用flex佈局
.box{
display:inline-flex;
}
複製程式碼
注意:設為flex佈局後,子元素的clear,float,vertical-align屬性將失效
容器的屬性
+ flex-direction
+ flex-wrap
+ flex-flow
+ justify-content
+ align-items
+ align-content
複製程式碼
flex-direction
屬性決定主軸的方向
.box{
flex-direction: row | row-reverse | column | column-reverse
}
複製程式碼
它有四個值
+ row(預設值):主軸為水平方向,起點在左端
+ row-reverse:主軸為水平方向,起點在右端。
+ column:主軸為垂直方向,起點在上沿。
+ column-reverse:主軸為垂直方向,起點在下沿。
複製程式碼
flex-wrap
屬性定義,如果一條軸線排不下,如何換行。預設情況下,專案都排在一條線上
.box{
flex-wrap: nowrap(不換行) | wrap(換行,第一行在上方) | wrap-reverse(換行,第一行在下方)
}
複製程式碼
flex-flow
屬性是flex-direction
和flex-wrap
的簡寫,預設row nowrap
.box {
flex-flow: <flex-direction> || <flex-wrap>;
}
複製程式碼
justify-content
屬性定義了專案在主軸上的對齊方式。
它有五個值,具體對齊方式與軸的方向有關。下面假設主軸為從左往右。
+ flex-start(預設值):左對齊
+ flex-end:右對齊
+ center:居中
+ space-between:兩端對齊,專案之間的間隔都相等
+ space-around:每個專案兩側的間隔相等。所以,專案之間的間隔比專案與邊框的間隔大一倍。
複製程式碼
align-items
屬性定義專案在交叉軸上如何對齊
它可能取5個值。具體的對齊方式與交叉軸的方向有關,下面假設交叉軸從上到下。
+ flex-start:交叉軸的起點對齊。
+ flex-end:交叉軸的終點對齊。
+ center:交叉軸的中點對齊。
+ baseline: 專案的第一行文字的基線對齊。
+ stretch(預設值):如果專案未設定高度或設為auto,將佔滿整個容器的高度。
複製程式碼
align-content
屬性定義了多根軸線的對齊方式。如果專案只有一根軸線,該屬性不起作用。
該屬性可能取6個值。
+ flex-start:與交叉軸的起點對齊。
+ flex-end:與交叉軸的終點對齊。
+ center:與交叉軸的中點對齊。
+ space-between:與交叉軸兩端對齊,軸線之間的間隔平均分佈。
+ space-around:每根軸線兩側的間隔都相等。所以,軸線之間的間隔比軸線與邊框的間隔大一倍。
+ stretch(預設值):軸線佔滿整個交叉軸。
複製程式碼
專案的屬性
以下6個屬性設定在專案上。
+ order 定義專案的排列順序。數值越小,排列越靠前,預設為0
+ flex-grow 屬性定義專案的放大比例,預設為0,即如果存在剩餘空間,也不放大。
+ flex-shrink 屬性定義了專案的縮小比例,預設為1,即如果空間不足,該專案將縮小
+ flex-basis 屬性定義了在分配多餘空間之前,專案佔據的主軸空間
+ flex 是flex-grow, flex-shrink 和 flex-basis的簡寫,預設值為0 1 auto
+ align-self 屬性允許單個專案有與其他專案不一樣的對齊方式,可覆蓋align-items屬性。預設值為auto,表示繼承父元素的align-items屬性,如果沒有父元素,則等同於stretch。
複製程式碼
display取值,元素預設是什麼,內聯元素塊級元素可變元素有哪些?img是什麼?
img是內聯元素
display CSS屬性指定用於元素的呈現框的型別。在 HTML 中,預設的 display 屬性取決於 HTML 規範所描述的行為或瀏覽器/使用者的預設樣式表。
預設值是inline
display取值如下:
none 此元素不會被顯示。
block 此元素將顯示為塊級元素,此元素前後會帶有換行符。
inline 預設。此元素會被顯示為內聯元素,元素前後沒有換行符。
inline-block 行內塊元素。(CSS2.1 新增的值)
list-item 此元素會作為列表顯示。
run-in 此元素會根據上下文作為塊級元素或內聯元素顯示。
compact CSS 中有值 compact,不過由於缺乏廣泛支援,已經從 CSS2.1 中刪除。
marker CSS 中有值 marker,不過由於缺乏廣泛支援,已經從 CSS2.1 中刪除。
table 此元素會作為塊級表格來顯示(類似 <table>),表格前後帶有換行符。
inline-table 此元素會作為內聯表格來顯示(類似 <table>),表格前後沒有換行符。
table-row-group 此元素會作為一個或多個行的分組來顯示(類似 <tbody>)。
table-header-group 此元素會作為一個或多個行的分組來顯示(類似 <thead>)。
table-footer-group 此元素會作為一個或多個行的分組來顯示(類似 <tfoot>)。
table-row 此元素會作為一個表格行顯示(類似 <tr>)。
table-column-group 此元素會作為一個或多個列的分組來顯示(類似 <colgroup>)。
table-column 此元素會作為一個單元格列顯示(類似 <col>)
table-cell 此元素會作為一個表格單元格顯示(類似 <td> 和 <th>)
table-caption 此元素會作為一個表格標題顯示(類似 <caption>)
inherit 規定應該從父元素繼承 display 屬性的值。
複製程式碼
float:left情況下是怎樣的,此時如果超出了寬度範圍
該元素從網頁的正常流動中移除,儘管仍然保持部分的流動性
css3的transform
CSS transform 屬性允許你修改CSS視覺格式模型的座標空間。使用它,元素可以被轉換(translate)、旋轉(rotate)、縮放(scale)、傾斜(skew)。
輸入一個URL後會發生什麼?
總體來說分為以下幾個過程:
-
DNS解析
-
TCP連線
-
傳送HTTP請求
-
伺服器處理請求並返回HTTP報文
-
瀏覽器解析渲染頁面
-
連線結束
tcp 協議,http協議
hit-alibaba.github.io/interview/b…
tcp協議即是傳輸控制協議,
http協議:
HTTP構建於TCP/IP協議之上,預設埠號是80 HTTP是無連線無狀態的
寫一個繼承函式
原型鏈繼承基本思想就是讓一個原型物件指向另一個型別的例項
function Parent() {
this.property = true
}
Parent.prototype.getParentValue = function () {
return this.property
}
function Child() {
this.Childproperty = false
}
Child.prototype = new Parent()
Child.prototype.getChildValue = function () {
return this.Childproperty
}
var instance = new Child()
console.log(instance.getParentValue()) // true
複製程式碼
寫一個快速排序
"快速排序"的思想很簡單,整個排序過程只需要三步:
(1)在資料集之中,選擇一個元素作為"基準"(pivot)。
(2)所有小於"基準"的元素,都移到"基準"的左邊;所有大於"基準"的元素,都移到"基準"的右邊。
(3)對"基準"左邊和右邊的兩個子集,不斷重複第一步和第二步,直到所有子集只剩下一個元素為止。
複製程式碼
function quickSort(arr) {
if(arr.length < 2) {
return arr;
} else {
const pivot = arr[0]; // 基準值
const pivotArr = []; // 一樣大的放中間
const lowArr= []; // 小的放左邊
const hightArr = []; // 大的放右邊
arr.forEach(current => {
if(current === pivot) pivotArr.push(current);
else if(current > pivot) hightArr.push(current);
else lowArr.push(current);
})
return quickSort(lowArr).concat(pivotArr).concat(quickSort(hightArr));
}
}
複製程式碼
寫一個js判斷全等的方法
//利用JSON.stringify,將兩個物件轉化為字串。
字串相等的話,說明兩個物件全等。
let a = {a:0,b:1,c:2};
let b = {a:0,b:1,c:2};
let c = {a:1,b:1,c:2};
let x = JSON.stringify(a) == JSON.stringify(b);
let y = JSON.stringify(a) == JSON.stringify(c);
console.log(x);
console.log(y);
複製程式碼
遍歷物件的方法
var obj={a:'A',b:'B',c:'C'};
1. for ... in 迴圈
for(key in obj){
console.log(key);// a,b,c
}
2. Object.keys()
Object.keys(obj);//["a", "b", "c"]
複製程式碼
防抖和節流
1、防抖
觸發高頻事件後n秒內函式只會執行一次,如果n秒內高頻事件再次被觸發,則重新計算時間
- 思路
每次觸發事件時都取消之前的延時呼叫方法
function debounce(fn) {
let timeout = null; // 建立一個標記用來存放定時器的返回值
return function () {
clearTimeout(timeout); // 每當使用者輸入的時候把前一個 setTimeout clear 掉
timeout = setTimeout(() => { // 然後又建立一個新的 setTimeout, 這樣就能保證輸入字元後的 interval 間隔內如果還有字元輸入的話,就不會執行 fn 函式
fn.apply(this, arguments);
}, 500);
};
}
function sayHi() {
console.log('防抖成功');
}
var inp = document.getElementById('inp');
inp.addEventListener('input', debounce(sayHi)); // 防抖
複製程式碼
2、節流
高頻事件觸發,但在n秒內只會執行一次,所以節流會稀釋函式的執行頻率
- 思路
每次觸發事件時都判斷當前是否有等待執行的延時函式
function throttle(fn) {
let canRun = true; // 通過閉包儲存一個標記
return function () {
if (!canRun) return; // 在函式開頭判斷標記是否為true,不為true則return
canRun = false; // 立即設定為false
setTimeout(() => { // 將外部傳入的函式的執行放在setTimeout中
fn.apply(this, arguments);
// 最後在setTimeout執行完畢後再把標記設定為true(關鍵)表示可以執行下一次迴圈了。當定時器沒有執行的時候標記永遠是false,在開頭被return掉
canRun = true;
}, 500);
};
}
function sayHi(e) {
console.log(e.target.innerWidth, e.target.innerHeight);
}
window.addEventListener('resize', throttle(sayHi));
複製程式碼
- 問題
為什麼要 fn.apply(this, arguments);而不是這樣 fn()
答:加上 apply 確保 在 sayHi 函式裡的 this 指向的是 input物件(不然就指向 window 了,不是我們想要的)。 這裡的箭頭函式依舊是指向 input 物件。
https怎麼保證安全的?
什麼情況下會碰到跨域問題?有哪些解決方法?
- 跨域問題是這是瀏覽器為了安全實施的同源策略導致的,同源策略限制了來自不同源的document、指令碼,同源的意思就是兩個URL的域名、協議、埠要完全相同。
- script標籤jsonp跨域、nginx反向代理、node.js中介軟體代理跨域、後端在頭部資訊設定安全域名、後端在伺服器上設定cors。
如何判斷一個變數是物件還是陣列?
function isObjArr(value){
if (Object.prototype.toString.call(value) === "[object Array]") {
console.log('value是陣列');
}else if(Object.prototype.toString.call(value)==='[object Object]'){//這個方法相容性好一點
console.log('value是物件');
}else{
console.log('value不是陣列也不是物件')
}
}
//ps:千萬不能使用typeof來判斷物件和陣列,因為這兩種型別都會返回"object"。
複製程式碼
事件迴圈機制
html事件迴圈:
一個瀏覽器環境,只能有一個事件迴圈,而一個事件迴圈可以多個任務佇列(task queue),每個任務都有一個任務源(task source)。
相同任務源的任務,只能放到一個任務佇列中。
不同任務源的任務,可以放到不同任務佇列中。
EcmaScript規範中指出:
任務佇列(Job queue)是一個先進先出的佇列,每一個任務佇列是有名字的,至於有多少個任務佇列,取決於實現。每一個實現至少應該包含以上兩個任務佇列。
結論:EcmaScript的Job queue與HTML的Task queue有異曲同工之妙。它們都可以有好幾個,多個任務佇列之間的順序都是不保證的。
例子:
setImmediate(function(){
console.log(1);
},0);
setTimeout(function(){
console.log(2);
},0);
new Promise(function(resolve){
console.log(3);
resolve();
console.log(4);
}).then(function(){
console.log(5);
});
console.log(6);
process.nextTick(function(){
console.log(7);
});
console.log(8);
結果:3 4 6 8 7 5 2 1
事件註冊順序如下:
setImmediate - setTimeout - promise.then - process.nextTick
優先順序關係:
process.nextTick > promise.then > setTimeout > setImmediate
V8實現中,兩個佇列各包含不同的任務:
macrotasks(巨集任務): script(整體程式碼),setTimeout, setInterval, setImmediate, I/O, UI rendering
microtasks(微任務): process.nextTick, Promises, Object.observe, MutationObserver
執行過程如下:
js引擎首先從macrotask queue中取出第一個任務,執行完畢後,將microtask queue中的所有任務取出,按順序全部執行;然後再從macrotask queue中取下一個,執行完畢後,再次將microtask queue中的全部取出; 迴圈往復,直到兩個queue中的任務都取完。
setTimeout會預設延遲4毫秒(ms)。
問題:
process.nextTick也會放入microtask quque,為什麼優先順序比promise.then高呢?
答:process.nextTick 永遠大於promise.then,原因其實很簡單。
在Node中,_tickCallback在每一次執行完TaskQueue中的一個任務後被呼叫,而這個_tickCallback中實質上幹了兩件事:
1. nextTickQueue中所有任務執行掉(長度最大1e4,Node版本v6.9.1)
2. 第一步執行完後執行_runMicrotasks函式,執行microtask中的部分(promise.then註冊的回撥)
所以很明顯process.nextTick > promise.then
複製程式碼
深拷貝和淺拷貝
區別
1.淺拷貝: 將原物件或原陣列的引用直接賦給新物件,新陣列,新物件/陣列只是原物件的一個引用
2.深拷貝: 建立一個新的物件和陣列,將原物件的各項屬性的“值”(陣列的所有元素)拷貝過來,是“值”而不是“引用”
為什麼要使用深拷貝?
我們希望在改變新的陣列(物件)的時候,不改變原陣列(物件)
深拷貝的要求程度
我們在使用深拷貝的時候,一定要弄清楚我們對深拷貝的要求程度:是僅“深”拷貝第一層級的物件屬性或陣列元素,還是遞迴拷貝所有層級的物件屬性和陣列元素?
怎麼檢驗深拷貝成功
改變任意一個新物件/陣列中的屬性/元素, 都不改變原物件/陣列
只做第一層深拷貝
深拷貝陣列(只拷貝第一級陣列元素)
- 直接遍歷
var arr = [1,2,3,4];
function copy(arg){
var newArr = [];
for(var i = 0; i < arr.length; i++) {
newArr.push(arr[i]);
}
return newArr;
}
var newArry = copy(arr);
console.log(newArry);
newArry[0] = 10;
console.log(newArry); // [10,2,3,4]
console.log(arr) // [1,2,3,4]
複製程式碼
- slice()
var arr = [1,2,3,4]
var copyArr = arr.slice();
copyArr[0] = 10;
console.log(copyArr); // [10,2,3,4]
console.log(arr); // [1,2,3,4]
// slice() 方法返回一個從已有的陣列中擷取一部分元素片段組成的新陣列(不改變原來的陣列!)
用法:array.slice(start,end) start表示是起始元素的下標, end表示的是終止元素的下標
當slice()不帶任何引數的時候,預設返回一個長度和原陣列相同的新陣列
複製程式碼
- concat()
var arr = [1,2,3,4]
var copyArr = arr.concat();
copyArr[0] = 10;
console.log(copyArr); // [10,2,3,4]
console.log(arr); // [1,2,3,4]
//concat() 方法用於連線兩個或多個陣列。( 該方法不會改變現有的陣列,而僅僅會返回被連線陣列的一個副本。)
用法:array.concat(array1,array2,......,arrayN)
因為我們上面呼叫concat的時候沒有帶上引數,所以var copyArray = array.concat();實際上相當於var copyArray = array.concat([]);
也即把返回陣列和一個空陣列合並後返回
複製程式碼
深拷貝物件
1.直接遍歷
var obj = {
name: "張三",
job: "學生"
}
function copy (obj) {
let newobj = {}
for(let item in obj) {
newobj[item] = obj[item];
}
return newobj;
}
var copyobj = copy(obj)
copyobj.name = "李四"
console.log(copyobj) // {name: '李四', job:: '學生'}
console.log(obj) // {name: '張三', job:: '學生'}
複製程式碼
- ES6的Object.assign
var obj = {
name: '張三',
job: '學生'
}
var copyobj = Object.assign({},obj)
copyobj.name = '李四'
console.log(copyobj) // {name: '李四', job:: '學生'}
console.log(obj) // {name: '張三', job:: '學生'}
Object.assign:用於物件的合併,將源物件(source)的所有可列舉屬性,複製到目標物件(target),並返回合併後的target
用法: Object.assign(target, source1, source2); 所以 copyObj = Object.assign({}, obj); 這段程式碼將會把obj中的一級屬性都拷貝到 {}中,然後將其返回賦給copyObj
複製程式碼
- ES6擴充套件運算子:
var obj = {
name: '張三',
job: '學生'
}
var copyobj = {...obj}
copyobj.name = '李四'
console.log(copyobj)
console.log(obj)
擴充套件運算子(...)用於取出引數物件的所有可遍歷屬性,拷貝到當前物件之中
複製程式碼
ajax請求
// 1.XMLHttpRequest物件用於在後臺與伺服器交換資料
var xhr = new XMLHttpRequest();
// 2.
xhr.open('GET', url, true);
//3.傳送請求
xhr.send();
//4.接收返回
//客戶端和伺服器端有互動的時候會呼叫onreadystatechange
xhr.onreadystatechange = function() {
// readyState == 4說明請求已完成
if (xhr.readyState == 4 && xhr.status == 200 || xhr.status == 304) {
// 從伺服器獲得資料
fn.call(this, xhr.responseText);
}
};
複製程式碼