前端總結一

javascript

1.做用域與做用域鏈

  • 做用域是根據名稱查找變量的一套規則,用於肯定在何處以及如何查找變量(標識符)。若是查找的目的是對變量進行賦值,那麼就會使用 LHS 查詢;若是目的是獲取變量的值,就會使用 RHS 查詢。
  • 當一個塊或函數嵌套在另外一個塊或函數中時,就發生了做用域的嵌套,造成了做用域鏈。其規則就是,在當前做用域中沒法找到某個變量時,引擎就會在外層嵌套的做用域中繼續查找,直到找到該變量,或抵達到全局做用域爲止,此時不管是否找到該變量,都會中止查到。

所以,變量可分爲本地變量與全局變量:javascript

  1. 全局範圍:代碼執行前,變量、函數聲明會提高
  2. 函數範圍:代碼執行前,函數、變量,this、argument 會提高。

注意,函數提高由優先於變量提高,函數表達式不會提高。php

2.做用域提高

舉個例子, var a = 2;JavaScript 引擎會把它分爲兩個單獨的聲明,分別是css

var a a = 2html

第一個是編譯階段的任務,而第二個則是執行階段的任務。 不管做用域中的聲明出如今什麼地方,代碼執行前首先進行編譯處理。 能夠將這個過程形象地想象成全部的聲明(變量和函數)都會被「移動」到各自做用域的最頂端,這個過程被稱爲提高。前端

3.詞法做用域

做用域是由書寫代碼時函數聲明的位置來決定的。編譯的詞法分析階段基本可以知道所有標識符在哪裏以及是如何聲明的,從而可以預測在執行過程當中如何對它們進行查找。html5

4.閉包

4.1什麼是閉包

當函數能夠記住並訪問所在的詞法做用域,即便函數是在當前詞法做用域以外執行,這時就產生了閉包。java

4.2閉包有什麼用

閉包在實際開發中主要用於封裝變量,收斂權限,使用場景:node

4.2.1函數做爲返回值webpack

function isFirstLoad(){
      var _list = []//私有變量
      return function(id){
        if (_list.indexOf(id)>=0){
          return false
        }else{
          _list.push(id)
          return true
        }
      }
    }

    var firstLoad = isFirstLoad()
    firstLoad(10) //true
    firstLoad(10) //false
    firstLoad(20) //true
    //在isFirstLoad函數外面,根本不能修改 _list 的值!
複製代碼

4.2.2函數做爲參數傳遞:es6

var fn;
    function foo() {
     var a = 2;
     function baz() {
     console.log( a );
     }
     fn = baz; // 將 baz 分配給全局變量
    }
    function bar() {
     fn(); // 媽媽快看呀,這就是閉包!
    }
    bar(); // 2
複製代碼

將內部函數傳遞到所在的詞法做用域之外,它都會持有對原始定義做用域的引用,不管在何處執行這個函數都會使用閉包。

5.原型與原型鏈

5.1什麼是原型和原型鏈

原型:Prototype 是個對象,只有函數上有。它是用來存儲對象的屬性(數據和方法)的地方,是實現JavaScript 原型繼承的基礎。

原型鏈:

  • 每一個函數都能構建一個對象,該對象的__proto__ 屬性指向函數的原型對象(obj. __proto__=== Foo.Prototype
  • 原型對象本質也是一個對象,也是由另外一個構造函數構造出來的,也指向那個構造函數的原型對象
  • 以上,造成一個鏈式結構,就稱爲原型鏈。

5.2原型繼承的方式:

// ES6 以前須要拋棄默認的 Bar.prototype

Bar.ptototype = Object.create( Foo.prototype ); // ES6 開始能夠直接修改現有的 Bar.prototype Object.setPrototypeOf( Bar.prototype, Foo.prototype ); extends Object.getPrototype(); Object.setPrototype()等;

若是忽略掉 Object.create(..) 方法帶來的輕微性能損失(拋棄的對象須要進行垃圾回 收),它實際上比 ES6 及其以後的方法更短並且可讀性更高。不過不管如何,這是兩種完 全不一樣的語法

5.3原型鏈

[[Prototype]] 機制就是存在於對象中的一個內部連接,它會引用其餘對象。 一般來講,這個連接的做用是:若是在對象上沒有找到須要的屬性或者方法引用,引擎就 會繼續在 [[Prototype]] 關聯的對象上進行查找。同理,若是在後者中也沒有找到須要的 引用就會繼續查找它的 [[Prototype]],以此類推。這一系列對象的連接被稱爲「原型鏈」。

6.this

6.1 this是什麼

當一個函數被調用時,會建立一個活動記錄(有時候也稱爲執行上下文)。這個記錄會包含函數在哪裏被調用(調用棧)、函數的調用方法、傳入的參數等信息。this就是記錄的其中一個屬性,會在函數執行的過程當中用到。

6.2 this綁定及優先級

若是要判斷一個運行中函數的 this 綁定,就須要找到這個函數的直接調用位置。找到以後 就能夠順序應用下面這四條規則來判斷 this 的綁定對象。

  1. 由 new 調用?綁定到新建立的對象。
  2. 由 call或者apply(或bind)調用?綁定到指定的對象。
  3. 由上下文對象調用?綁定到那個上下文對象。
  4. 默認:在嚴格模式下綁定到 undefined,不然綁定到全局對象

ES6 中的箭頭函數並不會使用以上四條標準的綁定規則,而是根據當前的詞法做用域來決定 this,具體來講,箭頭函數會繼承外層函數調用的 this 綁定(不管 this 綁定到什麼)。

6.3 綁定例外

  • 間接引用

    function foo() { 
         console.log( this.a );
     }
     var a = 2; 
     var o = { a: 3, foo: foo }; 
     var p = { a: 4 };
     o.foo(); // 3
     (p.foo = o.foo)(); // 2
    複製代碼

賦值表達式 p.foo = o.foo 的返回值是目標函數的引用,所以調用位置是 foo() 而不是p.foo() 或者 o.foo(),這裏會應用默認綁定。

  • 忽略的this

    function foo() { 
      console.log( this.a );
     }
     var a = 2;
     foo.call( null ); // 2
    複製代碼

若是你把 null 或者 undefined做爲this的綁定對象傳入call、apply或者bind,這些值在調用時會被忽略,實際應用的是默認綁定規則.

6.4 當this遇到return

  • return的是基本類型:

    function fn()  {  
     this.user = '追夢子';  
     return 1;
     }
     var a = new fn;  
     console.log(a.user); //追夢子
    複製代碼
  • return的是對象:

    function fn()  {  
     this.user = '追夢子';  
     return function(){};
     }
     var a = new fn;  
     console.log(a.user); //undefined
    複製代碼

若是返回值是一個對象,那麼this指向的就是那個返回的對象,若是返回值不是一個對象那麼this仍是指向函數的實例。

6.5 改變this綁定

#####6.5.1 call() 語法:

fun.call(thisArg, arg1, arg2, ...)
複製代碼

1、使用call方法調用父構造函數:

function Product(name, price) {
      this.name = name;
      this.price = price;
    }
    
    function Food(name, price) {
      Product.call(this, name, price);
      this.category = 'food';
    }
    
    var cheese = new Food('feta', 5);//Food {name: "feta", price: 5, category: "food"}
複製代碼

2、使用call方法調用函數而且指定上下文的'this'

function greet() {   
    var reply = [this.animal, 'typically sleep between', this.sleepDuration].join(' '); 
    console.log(reply); }
     
    var obj = {   
        animal: 'cats', sleepDuration: '12 and 16 hours'
    };
     
    greet.call(obj);  // cats typically sleep between 12 and 16 hours
複製代碼

3、使用call方法調用函數而且沒有肯定第一個參數,this的值將會被綁定爲全局對象,嚴格模式下this的值將會是undefined。

6.5.2 apply()

語法:

func.apply(thisArg, [argsArray])
複製代碼
/* 找出數組中最大/小的數字 */
var numbers = [5, 6, 2, 3, 7];
/* 應用(apply) Math.min/Math.max 內置函數完成 */
var max = Math.max.apply(null, numbers); /* 基本等同於 Math.max(numbers[0], ...) 
var min = Math.min.apply(null, numbers)
複製代碼
6.5.3 bind()

語法:

function.bind(thisArg[, arg1[, arg2[, ...]]])
複製代碼

1、建立綁定函數

this.x = 9;    
    var module = {
      x: 81,
      getX: function() { return this.x; }
    };
    var retrieveX = module.getX;
    retrieveX();   // 返回9 
    
    // 建立一個新函數,把 'this' 綁定到 module 對象
    var boundGetX = retrieveX.bind(module);
    boundGetX(); // 81
複製代碼

2、預設的初始參數

function list() {
  return  Array.prototype.slice.call(arguments);
}
var leadingThirtysevenList = list.bind(null, 37);
var list = leadingThirtysevenList(1, 2, 3); 
// [37, 1, 2, 3]
複製代碼

7.對象的拷貝

7.1 淺拷貝

7.1.1 賦值=

以賦值的形式拷貝引用對象,仍指向同一個地址,修改時原對象也會受到影響

const originArray = [1,2,3,4,5];
const cloneArray = originArray;
console.log(cloneArray); // [1,2,3,4,5]
cloneArray.push(6);
console.log(cloneArray); // [1,2,3,4,5,6]
console.log(originArray); // [1,2,3,4,5,6]
複製代碼
7.1.2 (...)//展開運算符

7.2 深拷貝

徹底拷貝一個新對象,修改時原對象再也不受到任何影響:

7.2.1 JSON.parse(JSON.stringify(obj))//性能最快
/*
JSON.parse 是將一個 JSON 字符串轉成一個 JavaScript 值或對象
JSON.stringify 是將一個 JavaScript 值轉成一個 JSON 字符串
*/
const originArray = [1,2,3,4,5];
const cloneArray = JSON.parse(JSON.stringify(originArray));
console.log(cloneArray === originArray); // false
複製代碼

注意: 一、具備循環引用的對象時,報錯; 二、當值爲函數、undefined、或symbol時,沒法拷貝;

7.2.2 object.assign()
const obj = { a: 1 };
const copy = Object.assign({}, obj);
console.log(copy); // { a: 1 }
copy.a = 2
console.log(copy) //{ a: 2 }
console.log(obj) //{a: 1}
複製代碼
7.2.3 遞歸進行逐一賦值

8.new運算符的執行過程

  • 新生成一個對象
  • 連接到原型: obj.proto = Con.prototype
  • 綁定this: apply
  • 返回新對象(若是構造函數有本身 retrun 時,則返回該值)

9.代碼的複用

當你發現任何代碼開始寫第二遍時,就要開始考慮如何複用。通常有如下的方式:

  • 函數封裝
  • 繼承
  • 複製 extend
  • 混入mixin
  • 借用apply/call

10.繼承

10.1 最有模式:聖盃模式

//c是目標,p是繼承源
var inherit = (function(c,p){
//F函數是一個閉包,僅用作一個緩衝
	var F = function(){};
	return function(c,p){
		F.prototype = p.prototype;
		/*使對象C試圖修改自身屬性時僅僅是以F函數做爲對象進行修改,而不會影響到其餘對象 */
		c.prototype = new F();
		//令目標函數c知道本身的原型
		c.uber = p.prototype;
		c.prototype.constructor = c;
	}
})();

複製代碼

10.2 ES6語法糖

class/estends

11.數據類型

11.1 類型的7種分類

String、Number、Boolean、object、Symbol、Null、Undefined

  • Undefined:未定義;
  • Null:定義了但爲空;
  • String:最大長度爲2^53-1,指的是UTF16編碼長度;
  • Number:浮點數的比較 console.log(Math.abs(0.1+0.2-0.3)<=Number.EPSILON)
  • Symbol:用於api的擴展
/*運算符提供了裝箱操做,它會根據基礎類型構造一個臨時對象,使得咱們能在基礎類型上調用對應對象的方法。*/
    Symbol.prototype.hello = () => console.log("hello");

   var a = Symbol("a");
   console.log(typeof a); //symbol,a 並不是對象
   a.hello(); //hello,有效

複製代碼
  • Object:內置對象以下 Object,Array,Boolean,Number,String,Function,Data,Regexp,Error.

11.2 類型轉換

11.2.1 運算符號轉換

JS 中在使用運算符號或者對比符時,會自帶隱式轉換,規則以下:

  • -、*、/、% :一概轉換成數值後計算
  • +:

數字 + 字符串 = 字符串, 運算順序是從左到右 數字 + 對象, 優先調用對象的valueOf -> toString 數字 +boolean/null -> 數字 數字 + undefined -> NaN

  • 1.toString() === '1'
  • {}.toString() === '[object object]'
  • NaN !== NaN
  • +undefined 爲 NaN
  • +null=0,+""=0
  • 加法運算只要其中一個是字符串,那麼另一個也會轉換爲字符串,而後進行字符串的拼接!
11.2.2 裝箱轉換

每一種基本類型 Number、String、Boolean、Symbol在對象中都有對應的類,所謂裝箱轉換,正是把基本類型轉換爲對應的對象。

全局的 Symbol 函數沒法使用new來調用,但咱們仍可利用裝箱機制來獲得一個 Symbol 對象

var symbolObject = (function(){ return this; }).call(Symbol("a"));

    console.log(typeof symbolObject); //object
    console.log(symbolObject instanceof Symbol); //true
    console.log(symbolObject.constructor == Symbol); //true

複製代碼
11.2.3 ‘== ’ 轉換

若是兩邊類型不一樣,會有隱式轉換髮生。總結以下: 1. 首先看雙等號先後有沒有NaN,若是存在NaN,一概返回false 2. 若是有true或false,轉換爲1或0,再比較。 3. 若是有引用類型,優先調用valueOf。 4. 數字和字符串,轉化爲數字再比較。 5. null和undefined,相等。 6. 5,其他都不相等。

console.log(undefined == false); // false
	console.log(null == false);   // false
	console.log(0 == false);     // true
	console.log(NaN == false);    // false
	console.log("" == false);    // true
	/*
	0 == false之因此爲true根據第2條。
    "" == false之因此爲true根據第2條,變成了""==0,再根據第4條。*/
console.log([[2]] == '2')   //true
/*
[[2]]的valueOf是對象自己,不是基本類型。嘗試調用toString的結果是'2'。所以變成了'2'和數字2的比較。根據第2條,相等*/
複製代碼

#####11.2.4 類型轉換的6個假值 0/+0,-0,「」,false,undefined,NaN.

11.3 類型判斷

  • 基本類型(null): 使用 String(null);

  • 基本類型(string / number / boolean / undefined) + function: 直接使用 typeof便可;

  • 其他引用類型(Array / Date / RegExp /Error): 調用toString

  • 通用但很繁瑣的方法:prototype alert(Object.prototype.toString.call(d) === ‘[object Date]') -------> true;

  • 判斷封裝:

let class2type = {}
'Array Date RegExp Object Error'.split(' ').forEach(e => class2type[ '[object ' + e + ']' ] = e.toLowerCase()) 

function type(obj) {
    if (obj == null) return String(obj)
    return typeof obj === 'object' ? class2type[ Object.prototype.toString.call(obj) ] || 'object' : typeof obj
}
複製代碼

12.模塊化

一般,咱們在瀏覽器中使用ES6的模塊化支持,在 Node 中使用 commonjs 的模塊化支持,分類以下:

  • es6: import / export
  • commonjs: require / module.exports / exports
  • amd: require / defined

其中,require與import的區別:

  • require支持 動態導入,import不支持,正在提案(babel下可支持)
  • require是同步導入,import屬於異步導入
  • require是值拷貝,導出值變化不會影響導入值;import指向 內存地址,導入值會隨導出值而變化

13.ES6/ES7

因爲 Babel 的強大和普及,如今 ES6/ES7 基本上已是現代化開發的必備了。經過新的語法糖,能讓代碼總體更爲簡潔和易讀。

13.1 聲明

  • let / const:塊級做用域、不存在變量提高、暫時性死區、不容許重複聲明
  • const: 聲明常量,沒法修改

13.2 解構賦值

####13.3 class / extend: 類聲明與繼承

13.4 Set / Map: 新的數據結構

13.5 異步解決方案:

  • Promise的使用與實現
  • generator: yield: //暫停代碼 next(): //繼續執行代碼
function* helloWorld() {
  yield 'hello';
  yield 'world';
  return 'ending';
}
const generator = helloWorld();
generator.next()  // { value: 'hello', done: false }
generator.next()  // { value: 'world', done: false }
generator.next()  // { value: 'ending', done: true }
generator.next()  // { value: undefined, done: true }

複製代碼
  • await / async:是generator的語法糖,babel中是基於promise實現。
async function getUserByAsync(){
   let user = await fetchUser();
   return user;
}
const user = await getUserByAsync()
console.log(user)
複製代碼

14.babel編譯原理

  • babylon 將 ES6/ES7 代碼解析成 AST(抽象語法樹:Abstract Syntax Tree)
  • babel-traverse 對 AST 進行遍歷轉譯,獲得新的 AST
  • 新 AST 經過 babel-generator 轉換成 ES5

15.函數柯里化

柯里化是一種在多有參數被提供前,掛起或‘延遲’函數執行,將多參函數轉化爲一元函數序列的編程技術,本質是詞法做用域(閉包)原理。

var add = function(x) {
  return function(y) {
    return function(z) {
      return x + y + z;
    }
  }
}

var addOne = add(1);
var addOneAndTwo = addOne(2);
var addOneAndTwoAndThree = addOneAndTwo(3);
console.log(addOneAndTwoAndThree);  //6

//非柯里化實現參數求和
let add = function(...arg) {
  //得到參數數組
  let _args = [].slice.call(arguments);
  return _args.reduce((sum, i) => {
    return sum + i;
  });
};
console.log(add(1, 2, 3));//6
複製代碼

16.AJAX

16.1 AJAX技術的核心 - XMLHttpRequest對象

XMLHttpRequest對象是瀏覽器提供的一個API,用來順暢地向服務器發送請求並解析服務器響應,整個過程當中,瀏覽器頁面不會被刷新。

XMLHttpRequest只是一個JavaScript對象,確切的說,是一個構造函數,它是由客戶端(即瀏覽器)提供的(而不是JavaScript原生的),除此以外,它有屬性,有方法,須要經過new關鍵字進行實例化。

16.2 建立一個XML對象的實例:

const xhr = new XMLHttpRequest() 該實例的屬性,方法有:

  • 方法
open() //準備啓動一個AJAX請求;
setRequestHeader() //設置請求頭部信息;
send() //發送AJAX請求;
getResponseHeader() //得到響應頭部信息;
getAllResponseHeader() //得到一個包含全部頭部信息的長字符串;
.abort() //取消異步請求;
複製代碼
  • 屬性
responseText //包含響應主體返回文本;
responseXML /*若是響應的內容類型時text/xml或application/xml,該屬性將保存包含着相應數據的XMLDOM文檔;*/
status //響應的HTTP狀態;
statusText //HTTP狀態的說明;
readyState //表示「請求」/「響應」過程的當前活動階段
複製代碼

另外,瀏覽器還爲該對象提供了一個onreadystatechange監聽事件,每當XML實例的readyState屬性變化時,就會觸發該事件的發生。其可取的值以下:

0:未初始化 -- 還沒有調用.open()方法; 1:啓動 -- 已經調用.open()方法,但還沒有調用.send()方法; 2:發送 -- 已經調用.send()方法,但還沒有接收到響應; 3:接收 -- 已經接收到部分響應數據; 4:完成 -- 已經接收到所有響應數據,並且已經能夠在客戶端使用了;

16.3 GET請求 與 POST請求

16.3.1 GET

GET請求用於獲取數據,有時候咱們須要獲取的數據須要經過「查詢參數」進行定位,在這種狀況下,咱們會將查詢參數追加到URL的末尾,令服務器解析。 const query = "example.php?name=tom&age=24"//"?name=tom&age=24"便是一個查詢參數

16.3.2 POST

POST請求用於向服務器發送應該被保存的數據,所以POST請求自然比GET請求多須要一份須要被保存的數據,發送的數據會做爲.send()方法的參數最終被髮往服務器。

須要注意,.send()方法的參數是不可爲空的,也就是說,對於不須要發送任何數據的GET請求,也須要在調用.send()方法時,向其傳入null值;

16.4 Open()

.open()方法接收三個參數:請求方式,請求URL地址和是否爲異步請求的布爾值。

// 該段代碼會啓動一個針對「example.php」的GET同步請求。
xhr.open("get", "example.php", false)
複製代碼

16.5 一個異步的GET請求代碼以下:

const xhr = new XMLHttpRequest()
xhr.onreadystatechange = () => {
    if(xhr.readyState === 4 && xhr.status === 200){
        alert(xhr.responseText);
    }
}
xhr.open("get", "example.php", true)
xhr.send(null)
複製代碼

注意:爲了確保跨瀏覽器的兼容性,必需要在調用.open()方法以前指定事件處理程序。

17.JavaScript單線程和異步機制

所謂的單線程,即程序的執行順序就是從上到下依次執行,同一時間內只能執行一段代碼。

JavaScript是單線程的,可是瀏覽器內部是多線程的,其異步也得靠其餘線程來監聽事件的響應,並將回調函數推入到任務隊列等待執行。

單線程所作的就是執行棧中的同步任務,執行完畢後,再從任務隊列中取出一個事件(沒有事件的話,就等待事件),而後開始執行棧中相關的同步任務,不斷的這樣循環。

17.1 前端使用異步的場景

  • 定時任務 :setTimeout setInverval
  • 網絡請求 :ajax請求,動態加載
  • 事件綁定
一、定時器
	 console.log(100)
	  setTimeout(function(){
	    console.log(200)
	  },1000)
	  console.log(300)
//100
//300
//200
	二、ajax請求
	  console.log('start')
	  $.get('test.json',function(data){
	    console.log(data)
	  })
	  console.log('end')
	三、動態<img>加載
	  console.log('start')
	  var img = document.createElement('img')
	  img.onload = function(){
	    console.log('load')
	
	  }
	  img.src='https://ss0.baidu.com/'
	  console.log('end')
//start
//end
//load
	四、事件綁定
	  console.log('start')
	  var btn1 = document.getElementById('btn1')
	  btn1.addEventListener('click',function () {
	    console.log('clicked')
	  })
	  console.log('end')
//start
//end
//click

複製代碼

18.script標籤的defer和async屬性

  • async屬性

表示後續文檔的加載和渲染與js腳本的加載和執行是並行進行的,即異步執行。

  • defer屬性

加載後續文檔的過程和js腳本的加載(此時僅加載不執行)是並行進行的(異步),但js腳本的執行須要等到文檔全部元素解析完成以後,DOMContentLoaded事件觸發前執行。

區別   1.defer和async在網絡加載過程是一致的,都是異步執行的;   2.二者的區別在於腳本加載完成以後什麼時候執行,defer更符合大多數場景對應用腳本加載和執行的要求;   3.若是存在多個有defer屬性的腳本,那麼它們是按照加載順序執行腳本的;而對於async,它的加載和執行是牢牢挨着的,不管聲明順序如何,只要加載完成就馬上執行。

DOM

1.BOM與DOM區別與關聯

1.1 BOM

  • BOM是Browser Object Model的縮寫,即瀏覽器對象模型。
  • BOM沒有相關標準。
  • BOM的最根本對象是window。 從1能夠看出來:BOM和瀏覽器關係密切。瀏覽器的不少東西能夠經過JavaScript控制的,例如打開新窗口、打開新選項卡(標籤頁)、關閉頁面,把網頁設爲主頁,或加入收藏夾,等等…這些涉及到的對象就是BOM。

從2能夠看出來:因爲沒有標準,不一樣的瀏覽器實現同一功能,能夠須要不一樣的實現方式,就要考慮瀏覽器兼容性了。

1.2 DOM

  • DOM是Document ObjectModel的縮寫,即文檔對象模型。
  • DOM是W3C的標準。
  • DOM最根本對象是document(其實是window.document)。

從1能夠看出來:DOM和文檔有關,這裏的文檔指的是網頁,也就是HTML文檔,和瀏覽器無關。

2.DOM事件模型

javascript中有兩種事件模型:DOM0,DOM2。

2.1 DOM0級事件模型

分爲兩種

  • 行內事件:在標籤中寫事件
  • 元素.on事件名=函數

1.行內

<input type="button" id="btn" value="按鈕" onclick="alert('hello world!')"> 
複製代碼

2.元素.on事件名=函數

document.getElementById("btn").onclick = function () {
alert('hello world!');
} 
複製代碼

注意,一個dom對象只能註冊一個同類型的函數,註冊多個同類型的函數的話,就會發生覆蓋,以前註冊的函數就會無效。

2.2 DOM2級事件模型

2.2.1 事件捕獲和事件冒泡

事件冒泡:當一個元素上的事件被觸發的時候,好比說鼠標點擊了一個按鈕,一樣的事件將會在全部祖先元素中被觸發。

事件捕獲和事件冒泡機制以下圖

此處輸入圖片的描述

2.2.2 DOM2級的註冊事件和解除事件

在DOM2級中使用addEventListener()removeEventListener()來註冊和解除事件(IE8及以前版本如下用attachEvent()添加事件和detachEvent()刪除事件)。DOM2不會發生事件的覆蓋,會依次的執行各個事件函數。   addEventListener('事件名稱','回調','捕獲(true)/冒泡(flase)')。示例以下:

<div id = 'outer' >
    <div id="inner" ></div>
</div>
<script>
    var click = document.getElementById('inner');
    var clickouter = document.getElementById('outer');
    click.addEventListener('click',function(event){
        alert('inner show');
        event.stopPropagation();
    },false);
    clickouter.addEventListener('click',function(){
        alert('outer show');
    },false);
</script>

複製代碼

通常狀況下,咱們在不添加stopPropagation()阻止冒泡函數時,點擊inner,會先彈出inner,再彈出outer。添加了stopPropagation()函數以後,執行完inner的事件函數以後,就不會在執行outer的事件函數了

因爲事件捕獲階段沒有能夠阻止事件的函數,因此通常都是設置爲事件冒泡。

3. 事件委託

事件委託就是利用事件冒泡機制指定一個事件處理程序,來管理某一類型的全部事件。 即:利用冒泡的原理,把事件加到父級上,觸發執行效果。 好處:

  • 只在內存中開闢了一處空間,節省資源同時減小了dom操做,提升性能
  • 動態添加的元素也綁定着事件。 例如,用ul中觸發li來改變他們的背景顏色
<ul id='ul'>
    <li>111111</li>
    <li>222222</li>
    <li>333333</li>
 </ul>
 <button id='button'>添加元素</button>
 
 window.onload = function(){
      let oUl = document.getElementById('ul');
      let aLi = oUl.getElementsByTagName('li');
      let but = document.getElementById('button');
      let now = 3;
      oUl.onmouseover = function(e){
        let ev = e || window.event;
        let target = ev.target || ev.srcElement;
        if(target.nodeName.toLowerCase() == 'li'){
          target.style.background = 'red';
        }
      }
      oUl.onmouseout = function(e){
        let ev = e || window.event;
        let target = ev.target || ev.srcElement;
        if(target.nodeName.toLowerCase() == 'li'){
          target.style.background = '';
        }
      }
      but.onclick = function(){
        now ++;
        let newLi = document.createElement('li');
        newLi.innerHTML = 111111 * now;
        oUl.appendChild(newLi);
      }
    }
複製代碼

WEB

1.HTTP 狀態碼

經常使用的狀態碼。 • 200表示服務端成功響應。 • 301表示永久重定向。 • 302表示臨時重定向。 • 403表示請求被拒絕。 • 404表示服務端找不到請求的資源。 • 500表示處理請求出錯。503表示服務不可用 ,504 表示網關超時。

2.HTTP緩存

2.1 HTTP報文

HTTP報文就是瀏覽器和服務器間通訊時發送及響應的數據塊。 主要分爲兩部分 1.包含屬性的首部(header)--------------------------附加信息(cookie,緩存信息等) 2.包含數據的主體部分(body)-----------------------HTTP請求真正想要傳輸的部分

2.2 HTTP緩存

http緩存能夠理解爲在服務端和客戶端之間一個緩存數據庫,你只須要設置一些參數便可實現,好比緩存/不緩存/時效內緩存/時效外緩存等(默認存在緩存)。緩存規則主要分爲兩類,即強制緩存和對比緩存。

2.2.1 強制緩存

對於強制緩存來講,響應header中會有兩個字段來標明失效規則Expires/Cache-Control

  1. Expires: HTTP 1.0的內容,做用基本忽略。
  2. Cache-Control Cache-Control 是最重要的規則。常見的取值有private、public、no-cache、max-age,no-store,默認爲private。
  • private:客戶端能夠緩存
  • public: 客戶端和代理服務器均可緩存
  • max-age=xxx:緩存的內容將在 xxx 秒後失效
  • no-cache:須要使用對比緩存來驗證緩存數據(通常都設置爲該值,使用緩存前都判斷文件是否爲最新,更爲合理。)
  • no-store:全部內容都不會緩存,強制緩存,對比緩存都不會觸發
2.2.2 對比緩存

對比緩存,顧名思義,須要進行比較判斷是否可使用緩存。 可分爲2種標識:

  1. Last-Modified / If-Modified-Since

Last-Modified:第一次請求時,服務器返回資源的最後修改時間; If-Modified-Since:再次請求時,瀏覽器通知服務器,上次請求時返回資源的最後修改時間。

若是Last-Modified小於等於If-Modified-Since,說明資源又被改動過,則響應整片資源內容,返回狀態碼200;不然,響應HTTP304,告知瀏覽器繼續使用所保存的cache。

  1. Etag/If-None-Match(優先級高於Last-Modified/If-Modified-Since)

Etag:第一次請求時,服務器返回的資源惟一標識符(生成規則由服務器決定) If-None-Match:再次請求服務器時,瀏覽器通知服務器緩存數據的惟一標識。

若是Etag和If-None-Match不一樣,說明資源又被改動過,則響應整片資源內容,返回狀態碼200;不然,響應HTTP304,告知瀏覽器繼續使用所保存的cache。

瀏覽器第一次請求:

此處輸入圖片的描述
瀏覽器再次請求:
此處輸入圖片的描述

總之,對於強制緩存,服務器通知瀏覽器一個緩存時間,在緩存時間內,下次請求,直接用緩存,不在時間內,執行比較緩存策略。 對於比較緩存,將緩存信息中的Etag和Last-Modified經過請求發送給服務器,由服務器校驗,返回304狀態碼時,瀏覽器直接使用緩存。

3.http緩存方案

3.1 md5/hash緩存

經過不緩存html,爲靜態文件添加MD5或者hash標識,解決瀏覽器沒法跳過緩存過時時間主動感知文件變化的問題

webpack提供了webpack-md5-hash插件,能夠幫助咱們在項目發佈時自動修改文件標識。

3.2 CDN緩存

CDN緩存提供了分流以及訪問加速等優點條件,是能夠經過登陸,手動更新CDN緩存的,變相解決了瀏覽器緩存沒法手動控制的問題。

3.3 瀏覽器操做對HTTP緩存的影響

此處輸入圖片的描述

4.從URL到頁面顯示的過程

瀏覽器在獲得用戶請求以後,經歷了下面這些階段:重定向→拉取緩存→DNS查詢→創建TCP連接→發起請求→接收響應→處理HTML元素→元素加載完成

一、首先,在瀏覽器地址欄中輸入url

二、瀏覽器先查看瀏覽器緩存-系統緩存-路由器緩存,若是緩存中有,會直接在屏幕中顯示頁面內容。若沒有,則跳到第三步操做。

三、域名解析(DNS解析),解析獲取相應的IP地址。

四、瀏覽器經過三次握手與遠程Web服務端來創建一個TCP/IP鏈接

五、握手成功後,瀏覽器向服務器發送http請求,請求數據包。

六、服務器處理收到的請求,將數據返回至瀏覽器。

七、瀏覽器進行HTML加載,加載完後開始解析

八、其餘資源下載:html解析遇到外部資源,如css\js\圖片,會啓用其餘線程下載資源。注意,當遇到的js文件,html解析會停下來,直到js文件下載並執行完後,從新開始html的解析工做。

九、Dom樹構建:在html解析同時,解析器會把解析完的html 轉化爲DOM對象,再進一步構建出DOM 樹。

十、CSSOM樹構建:當CSS下載完,解析器對css進行並生產css對象,進一步構建成CSSOM樹。

十一、渲染樹:DOM樹和CSSO樹構建完成後,瀏覽器就會根據這兩棵樹構建一顆渲染樹。

十二、佈局計算:渲染樹構建完成之後,全部元素的位置關係和應用樣式就肯定了,這是瀏覽器會計算全部元素的大小和絕對位置。

1三、渲染:佈局計算完成後,瀏覽器就能夠在頁面上渲染元素。通過渲染引擎的處理後,整個頁面就顯示在屏幕上。

5.web會話跟蹤的方法

HTTP是一種無狀態的協議,爲了分辨連接是誰發起的,需本身去解決這個問題。否則有些狀況下即便是同一個網站每打開一個頁面也都要登陸一下

5.1 Cookie

Cookies是服務器在本地機器上存儲的小段文本,即訪問後網站的相關信息,它隨每個請求發送至同一服務器,是在客戶端保持狀態的方案。 Cookie的主要內容包括:名字,值,過時時間,路徑和域 ,數據大小不能超過4k。

5.2 sessionStorage 和 localStorage

與cookie相似,但不會自動把數據發給服務器,僅在本地保存,數據大小可達5M或以上。

• localStorage 存儲持久數據,瀏覽器關閉後數據不丟失除非主動刪除數據;
• sessionStorage 數據在當前瀏覽器窗口關閉後自動刪除。
複製代碼

5.3 URL重寫

就是首先得到一個進入的URL請求而後把它從新寫成網站能夠處理的另外一個URL的過程。

5.4 隱藏input

隱藏域在頁面中對於用戶是不可見的,在表單中插入隱藏域的目的在於收集或發送信息,以利於被處理表單的程序所使用。瀏覽者單擊發送按鈕發送表單的時候,隱藏域的信息也被一塊兒發送到服務器。

6.GET 和 POST 的區別

GET和POST是HTTP協議中發送請求的兩種方法,它們的區別,簡單的說: GET產生一個TCP數據包;POST產生兩個TCP數據包。

也就是說:對於GET方式的請求,瀏覽器會把http的header和data一併發送出去,服務器響應200(返回數據);而對於POST,瀏覽器先發送header,服務器響應100 continue,瀏覽器再發送data,服務器響應200 ok(返回數據)。

  1. GET與POST都有本身的語義,不能隨便混用。
  2. 據研究,在網絡環境好的狀況下,發一次包的時間和發兩次包的時間差異基本能夠無視。而在網絡環境差的狀況下,兩次包的TCP在驗證數據包完整性上,有很是大的優勢。
  3. 並非全部瀏覽器都會在POST中發送兩次包,Firefox就只發送一次。

具體差別可表現如下5個方面:

  • 緩存上,GET請求會被瀏覽器主動cache,而POST不會,除非手動設置。
  • 編碼方式上,GET請求只能進行url編碼,而POST支持多種編碼方式。
  • 參數長度上,GET請求在URL中傳送的參數是有長度限制的,而POST沒有。
  • 參數的數據類型上,GET只接受ASCII字符,而POST沒有限制。
  • 參數傳遞上,GET參數經過URL傳遞,POST放在Request body中,更安全。

6.網站性能優化

可分爲三個方面,網絡傳輸性能、頁面渲染性能以及JS阻塞性能

6.1 網絡傳輸性能優化

6.1.1瀏覽器緩存:在服務器上設置的Etag字段。

在瀏覽器接收到服務器響應後,會檢測響應頭部(Header),若是有Etag字段,那麼瀏覽器就會將本次緩存寫入硬盤中。 注意,在構建階段,須要爲咱們的靜態資源添加md5 hash後綴,避免資源更新而引發的先後端文件沒法同步的問題。

6.1.2資源打包壓縮:用webpack進行自動化打包編譯

對webpack進行上線配置時,咱們要特別注意如下幾點:

  1. JS壓縮: new webpack.optimize.UglifyJsPlugin()
  2. HTML壓縮:
  • 使用html-webpack-plugin自動化注入JSCSS打包HTML文件
  • 書寫HTML元素的src 或 href 屬性時,能夠省略協議部分
  1. 提取公共資源: new webpack.optimize.CommonsChunkPlugin({ name: 'vendor', filename: 'scripts/common/vendor-[hash:5].js' })
  2. 提取css並壓縮 extract-text-webpack-plugin
  3. 服務器上開啓Gzip傳輸壓縮,但注意,不要對圖片文件進行Gzip壓縮
6.1.3圖片資源優化

1.不要在HTML裏縮放圖像 2.使用雪碧圖(CSS Sprite) 自動化生成雪碧圖的工具 3.使用字體圖標(iconfont); 4.使用WebP 是能夠加快圖片加載速度的圖片格式,叉拍雲 5.使用cdn 同時使用DNS預解析技術DNS Prefetch

6.2頁面渲染性能優化

主要是下降重排和重繪的頻率和成本

1.CSS屬性讀寫分離

2.經過切換class或者使用元素的style.csstext屬性去批量操做元素樣式。

3.DOM元素離線更新 例如display:none對元素隱藏,在元素「消失」後進行相關操做。

4.將沒用的元素設爲不可見:visibility: hidden

5.壓縮DOM的深度 一個渲染層內不要有過深的子元素,少用DOM完成頁面樣式,多使用僞元素或者box-shadow取代。

6.圖片在渲染前指定大小 由於img元素是內聯元素,因此在加載圖片後會改變寬高,嚴重的狀況會致使整個頁面重排,因此最好在渲染前就指定其大小,或者讓其脫離文檔流。

6.3 js阻塞性能

在編程的過程當中,若是咱們使用了閉包後未將相關資源加以釋放,或者引用了外鏈後未將其置空(好比給某DOM元素綁定了事件回調,後來卻remove了該元素),都會形成內存泄漏的狀況發生,進而大量佔用用戶的CPU,形成卡頓或死機。咱們可使用chrome提供的JavaScript Profile進行測試。

7.瀏覽器的渲染機制

CSS

1.CSS盒模型

HTML元素的顯示呈現爲一個矩形,CSS標準中稱之爲Box。一個HTML元素佔據空間的大小由盒模型決定。在盒模型中,一個盒子由內容content、內邊距padding、邊框border和外邊距margin共同構成,其尺寸也是這四部分的尺寸之和。 盒模型是有兩種標準: • 標準模型--盒模型的寬高只是內容(content)的寬高, • IE模型中--盒模型的寬高是內容(content)+填充(padding)+邊框(border)的總寬高。

2.css reset 和 normalize.css 有什麼區別?

Normalize.css只是一個很小的css文件,它在HTML元素樣式上提供了跨瀏覽器的高度一致性。相比於傳統的CSS reset,Normalize.css是一種現代的、爲HTML5準備的優質替代方案。 Normalize vs Reset

  • Normalize.css 保護了有價值的默認值

Reset經過爲幾乎全部的元素施加默認樣式,強行使得元素有相同的視覺效果。相比之下,Normalize.css保持了許多磨人的瀏覽器樣式。這就意味着你不用再爲全部公共的排版元素從新設置樣式。當一個元素在不一樣的瀏覽器中有不一樣的默認值時,Normalize.css會力求讓這些樣式保持一致並儘量與現代標準符合。

  • Normalize.css 修復了瀏覽器的bug

它修復了常見的桌面端與移動端瀏覽器的bug。這每每超出了Reset所能作到的範圍。關於這一點,Normalize.css修復的問題包含了HTML5元素的顯示設置、預格式化文字的font-size問題、在IE9中SVG的溢出、許多出如今各瀏覽器和操做系統中的與表單相關的bug。

  • Normalize.css 不會讓你的調試工具變的雜亂

使用Reset最讓人困擾的地方莫過於在瀏覽器調試工具中大段大段的繼承鏈,在Normalize.css中就不會有這樣的問題。

  • Normalize.css 是模塊化的

這個項目已經被拆分爲多個相關卻又獨立的部分,這使得你可以很容易也很清楚地知道哪些元素被設置了特定的值。所以這能讓你本身選擇性地移除掉某些永遠不會用到的部分(好比表單的通常化)。

  • Normalize.css 擁有詳細的文檔

3.BFC

3.1 定義:

BFC 全稱爲 block formatting context,中文爲「塊級格式化上下文」 若是一個元素具備 BFC,內部子元素再怎麼翻江倒海、翻 雲覆雨,都不會影響外部的元素。

3.2 觸發 BFC 常見的狀況以下:

  • 根元素;
  • float 的值不爲 none;
  • overflow 的值爲 auto、 scroll 或 hidden;
  • display 的值爲 table-cell、 table-caption 和 inline-block 中的任何一個;
  • position 的值不爲 relative 和 static。

3.3 用途:

  • BFC 元素是不會發生 margin 重疊的;
  • BFC 元素能夠用來清除浮動的影響: .lbf-content { overflow: hidden; } /* IE7+ */
  • 實現自適應佈局 普通流體元素在設置了 overflow:hidden 後,會自動填滿容器中除了浮動元素之外的剩餘空間,造成自適應佈局效果.
    此處輸入圖片的描述

4.居中

4.1 行內元素

  1. 父元素設置text-align: center;(只設置水平居中) 優勢:是不用計算子元素尺寸。

  2. 子元素經過absolute配合transform()(一樣適用於塊級元素)

.child{
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
  }
複製代碼

此處輸入圖片的描述
優勢:不用計算當前元素尺寸。 3. 子元素直接使用 absolute(一樣適用於塊級元素)

.child{
    width: 100px;
    height: 100px;
    position: absolute;
    top: 50%;
    left: 50%;
    margin-top: -50px; /*高度的一半*/
    margin-left: -50px; /*寬度的一半*/
  }
複製代碼

注意,須要計算子元素寬高. 4. 父元素使用flex佈局(一樣適用於塊級元素)

//方案一:配合使用 justify-content和 align-items屬性
.father{
    display: flex;
    justify-content: center; /*水平居中*/
    align-items: center; /*垂直居中*/
  }
  //方案二:子元素只用margin屬性,若是瀏覽器不兼容flex屬性,有回退做用
  .father{
    display: flex;
  }
  .child{
    margin: auto;
  }
複製代碼

4.2 塊級元素

  1. 使用margin:0 auto配合元素的width
#center{
    width: 100px;
    margin: 0 auto;
}

複製代碼

注意,當元素處於position:absolute;時,margin:0 auto無效,須要將right於left都設爲0才能夠,以下所示

#center{
    width: 100px;
    margin: 0 auto;
    position:absolute;
    right:0;
    left:0;
}

複製代碼

法2.3.4.同上

4.3 垂直居中

  1. 經過line-height
#main{
    height: 200px;
    line-height: 200px;
}

複製代碼

缺點:須要固定父元素的height值,而且居中元素若是是多行文本將錯亂。僅適合小元素,單行文本。

法2.3.4.同上。

5.清除浮動

兩大基本方法

  • 元素添加僞類
.clearfix:after{content:'';display:table;clear:both} //ie8+
.clearfix{*zoom:1;}
複製代碼

2.父元素BFC

.lbf-content { overflow: hidden; }//IE7+
複製代碼

6.css優先級計算規則

6.1 選擇器類型

  • id選擇器(#myid)、
  • 類選擇器(.myclassname)、屬性選擇器(a[rel=」external」])、僞類選擇器(a:hover, li:nth-child)
  • 標籤選擇器(h1)、僞元素(::before)
  • 相鄰選擇器(h1 + p)、
  • 子選擇器(ul > li)、
  • 後代選擇器(li a)、
  • 通配符選擇器(*)、

6.2 優先級

ID選擇器 > 類選擇器|屬性選擇器|僞類 > 標籤|僞元素 > 通配符

css規則由選擇器和聲明塊組成:

此處輸入圖片的描述

css優先級就是經過選擇器的特殊值計算的,選擇器的特殊性值表述爲4個部分,用0,0,0,0表示:

  • ID選擇器的特殊性值,加0,1,0,0。
  • 類選擇器、屬性選擇器或僞類,加0,0,1,0。
  • 標籤和僞元素,加0,0,0,1。
  • 通配選擇器*對特殊性沒有貢獻,即0,0,0,0。
  • 最後比較特殊的一個標誌!important(權重),它沒有特殊性值,但它的優先級是最高的,能夠認爲它的特殊性值爲1,0,0,0,0。
a{color: yellow;} /*特殊性值:0,0,0,1*/
div a{color: green;} /*特殊性值:0,0,0,2*/
.demo a{color: black;} /*特殊性值:0,0,1,1*/
.demo input[type="text"]{color: blue;} /*特殊性值:0,0,2,1*/
.demo *[type="text"]{color: grey;} /*特殊性值:0,0,2,0*/
#demo a{color: orange;} /*特殊性值:0,1,0,1*/
div#demo a{color: red;} /*特殊性值:0,1,0,2*/
複製代碼

選擇器特殊性值是從左向右排序的,也就是1,0,0,0大於以0開頭的全部特殊性值,行間樣式的特殊性是1,0,0,0,比ID選擇器優先級高。

6.3 層疊

假如特殊性相同的兩條規則應用到同一個元素,css會先查看規則的權重(!important),加了權重的優先級最高;當權重相同的時候,css規則會按順序排序,後聲明的規則優先級高。

例如,僞類,:link、:visited、:hover、:active,都遵循「愛恨原則LVHA」(LoVe HAte),特殊性值相同,後聲明的規則優先級高,就能夠覆蓋前面的。

7.gif/png/jpge

HTML

1. 標籤分類

• 文檔元信息:一般是出如今head標籤種,包含了描述文檔自身的一些信息,諸如 title、meta、style、link、base ; • 語義相關:擴展了純文本,表達文章結構、不一樣語言要素的標籤,諸如 section、nav 的標籤; • 連接:提供到文檔內和文檔外的的連接; • 替換型標籤:引入聲音、圖片、視頻等外部元素替換自身的一類標籤; • 表單:用於填寫和提交信息的一類標籤; • 表格:表頭、表尾、單元格等表格的結構。

2.HTML 語義化

語義化標籤是純文本的補充,好比標題,天然段,章節等,這些內容是純文字沒法表達的,咱們就須要語義標籤表達.

正確使用優勢以下: • 便於團隊維護和開發 • 去掉css樣式後網頁結構完整 • 便於閱讀機器閱讀,適合搜索引擎檢索seo

相反,錯誤地使用語義標籤,會給機器閱讀形成混淆、增長嵌套,給 Css編寫加劇負擔。 但現代互聯網產品裏,HTML用於描述「軟件界面」多過於「富文本",而軟件界面裏的東西,實際上幾乎是沒有語義的。好比說,咱們作了一個購物車功能,必定要用給商品套上ul嗎?好比,加入購物車的按鈕,必定要用button嗎?

實際上,我認爲是不必,由於這個場景裏,跟文本的列表以及表單的button,已經相差很遠了。因此,在軟件界面,能夠直接用div和span。

3.meta viewport 是作什麼用的,怎麼寫?

在移動瀏覽器中使用viewport元標籤控制佈局,包含如下內容:

<meta name="viewport" content="with=device-with,initial-scale=1,maximum-scale=1">
複製代碼

4.html5爲何只須要寫<!DOCTYPE>

HTML5不基於SGML,所以不須要對DTD進行引用,可是須要doctype來規範瀏覽器的行爲 因此,html5只有一種:<!DOCTYPE> 可是html4.01有三種,分別是strict、transitional、frameset。

5.html5新特性、移除元素,HTML5新標籤的瀏覽器兼容

實現上:h5再也不是SGML的子集。 一、新特性:主要是關於圖像,位置,存儲,多任務等功能的增長,如: • 繪畫canvas • 用於媒介回放的video和audio元素 • 本地離線存儲localStorage,長期存儲,瀏覽器關閉以後數據不丟失 sessionStorage的數據在瀏覽器關閉後自動刪除 • 語意化更好的內容元素,好比 article、footer、header、nav、section • 表單控件,calendar、date、time、email、url、search; • 新的技術webworker, websocket, Geolocation; 二、移除的元素: 純表現的元素:basefont,big,center,font, s,strike,tt,u; 對可用性產生負面影響的元素:frame,frameset,noframes; 三、處理兼容性: • IE8/IE7/IE6支持經過document.createElement方法產生的標籤,能夠利用這一特性讓這些瀏覽器支持HTML5新標籤,瀏覽器支持新標籤後,還須要添加標籤默認的樣式。 • 使用html5shim,可讓IE9或更低版本能支持html5 <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>

6.行內元素、塊級元素、空(void)元素

• 行內元素有:a,b,span,img(我曾覺得是block),input,strong,select
• 塊級元素有:div、ul(無序)、ol(有序)、li、p等
• 空元素:<br><hr><link><script>
空元素定義:html元素的內容就是其兩個標籤之間的content,因此,標籤之間沒有內容的就是空元素
複製代碼

7.頁面導入樣式時,使用link@import的區別

寫法上:

<link rel="stylesheet" href="路徑" />
<style type="text/css">
    @import '路徑'
</style>
複製代碼

本質上:link屬於XHTML標籤,除了加載css以外,還能定義RSS,定義rel鏈接屬性等做用。而@import是css提供的,只能用於加載css; 解析上:link是跟着頁面加載同時加載的,可是@import會等到頁面加載完再加載 兼容上:@import IE5以上才能識別,link無限制

相關文章
相關標籤/搜索