【個人筆記】前端開發筆記整理

JavaScript

(參考了《JavaScript高級程序設計》和部分知乎答案)


作用域

指可訪問變量對象函數的集合。

局部作用域:在函數內聲明,只能在函數內部訪問
全局作用域:在函數外定義,所有腳本和函數均可使用(函數內賦值但未聲明,仍為全局變量
變量生命周期:全局變量在頁面關閉后銷毀,局部變量在函數執行完畢后銷毀

ps:在HTML中所有數據屬于window對象


數據類型

原始數據類型:棧,占據空間小,大小固定
String
Number
Boolean
Object
Function


不含值的數據類型:
Undefined:不存在的值,或變量被聲明了但未賦值
Null:一個對象被定義了,但是為空值(沒有任何屬性和方法)


引用對象類型:堆,占據空間大,大小不固定(在棧中儲存了指針,指向堆中的起始位置)
Object
Date
Array


boolean類型轉換
數據類型 true false
Boolean true false
String 任何非字符串 ""(空)
Number 任何非零數字值 0和NaN
Object 任何對象 Null
Undefined n/a(不適用) underfined

例子:

var message = "Hello world!";
if (message) {
  alert("Value is true");
}

正則表達式

由一個字符串序列形成的搜索模式。
如:

var str = "Visit W3cSchool!";
var n = str.search(/W3cSchool/i);
//n=6               (不區分大小寫)

變量提升

函數聲明和變量聲明會被解釋器自動提升到方法體的最頂部

var x;

但是初始化的變量不會提升

var x = 5;
x = 5

為避免問題的出現,通常在作用域開始前聲明變量

注意:函數聲明也會自動提升,而傳遞給初始化變量的函數則不會

function fn () {} //提升

var fn = function () {} //不提升

函數調用的四種方法

1.方法調用模式

var myobject = {
  value: 0,
  inc: function() {
    alert(this.value);
  }
}
myobject.inc();

//this指向myobject

2.函數調用模式

var add = function(a,b) {
  alert(this);
  return a+b;
}
var sum = add(3,4);
arert sum;

3.構造器調用模式(摒棄)

4.apply調用

var arr = [10,20];
var sum = add.apply(myobject,arr);
aleat(sum);

原型鏈

當從一個對象那里讀取屬性或調用方法時,如果該對象不存在這樣的屬性或方法,就會去自己關聯的prototype對象那里尋找,直到找到或追溯過程結束為止。(即對象的屬性和方法追溯機制)

”讀“屬性會沿著原型鏈搜索,”新增“屬性時則不會去看原型鏈

(obj)
name:'obj'        valueOf
__proto__  ——>    toString
                  constructor
                  ...
                  __proto__    ——>    null

閉包

先看兩個典型例子

function foo () {
  var local = 1;
  function bar () {
    local++;
    return local;
  }
 return bar;
}

var func = foo();
func(); //2
func(); //3

bar函數調用了外層函數的local變量,函數運行完畢后local仍然保存在內存中,所以每次運行函數后local都會增加1

var add =(function () {
  var counter = 0;
  return function () {
    return counter += 1;
  }
})();

add(); //1
add(); //2
add(); //3

和上一個例子的原理是一樣的,內層函數調用了外層函數的全局變量count導致其始終存在于內存中,而內部函數的存在也依賴于外層函數,導致其也始終再內存中,不會在調用結束后被垃圾回收機制回收。

這就叫閉包,一句話概括:閉包就是函數函數內部能訪問到的變量的總和。
或者說,如果存在有權訪問另一個函數作用域中變量的函數,那就構成了閉包。

它提供了一中間接的方式能夠訪問到函數內部的數據,有以下兩種情況:
1.函數作為返回值
2.函數作為參數傳遞

正確運用閉包由一個好處,就是讓一些數據更安全,只能通過特定的接口來訪問。

當然,有時候閉包也會導致一些問題,如下面的例子:

for (var i=0; i<10; i++) {
  arr[i] = function() {
    return i;
  }
}

arr[0]; //10
arr[6]; //10

function內訪問了外部變量i,構成了一個閉包,我們先不寫內部的i,每次賦值的結果如下

arr[0] = function() { return i };
arr[1] = function() { return i };
...
arr[10] = function() { return i };

而i的作用域是整個for的花括號內,因此這些函數返回的是同一個i,遍歷完后產生了這11個結果,此時我們再調用函數的時候,i已經為10了,因此無論調用哪個函數,結果都是遍歷完后的i。


this
var obj = {
  foo: function () {
    console.log(this);
  }
}
var bar = obj.foo;

obj.foo(); //obj
bar(); //window

要理解this,首先要知道函數的三種調用形式

func(p1,p2);
obj.child.method(p1,p2);
func.call(context,p1,p2); //正常形式

context就是this,
上面的例子中,bar()等價于func.call(undefined),這種情況下this為window,
而obj.foo()等價于obj.foo.call(obj),this為obj

有一個特例:

function fn() {
  console.log(this);
}
var arr = [fn,fn2];

arr[0]; //這里的this指什么

我們把arr[0]假想為arr.0()
也就相當于arr.0.call(arr)
所以this為arr

對某些框架有其他方法來理解,
如在jQuery,this關鍵字指向的是當前正在執行事件的元素。


new操作

1.創建一個空對象,并且this變量引用該對象,繼承該對象的原型

var obj = {}

2.屬性和方法被加入到this引用的對象中

obj.__proto__ = Base.prototype;

3.新創建的對象又this所引用,并且隱式地返回this

Base.call(obj);

在以下例子中

var o = new myObject();

一旦沒有加上new,myObject()內部的this將指向全局對象


事件類型
UI事件

1.load事件:頁面完全加載后觸發

2.unload事件:頁面完全卸載后觸發

3.resize事件:當瀏覽器窗口被調整到一個新的高度或寬度時觸發

4.scroll事件:文檔被滾動期間觸發

焦點事件

1.focusout:在失去焦點的元素上觸發

2.focusin:在獲得焦點的元素上觸發

3.blur:在失去焦點的元素上觸發

4.DOMFocusOut:在失去焦點的元素上觸發

5.focus:在獲得焦點的元素上觸發

6.DOMFocusIn:在獲得焦點的元素上觸發

鼠標與滾輪事件

1.click:單擊鼠標或按下回車鍵時觸發

2.dbclick:雙擊鼠標按鈕時觸發

3.mousedown:按下任意鼠標按鈕時觸發

4.mouseup:用戶釋放鼠標按鈕時觸發

5.mousewheel:通過鼠標滾輪滾動頁面時觸發

6.mouseenter:鼠標光標首次從元素外部移動到元素范圍內時觸發(只限于被選元素)

7.mouseover:鼠標指針位于一個元素外部,用戶將其首次移入另一個元素邊界之內時觸發(任何元素,不限于被選元素)

8.mouseleave:位于元素上方的鼠標光標移動到元素范圍之外時觸發(只限于被選元素)

9.mouseout:鼠標指針位于一個元素的上方,移入到另一個元素時觸發(任何元素,不限于被選元素)

10.mousemove:鼠標指針在元素內部移動時重復地觸發

鍵盤與文本事件

1.keydown:按下鍵盤的任意鍵時觸發

2.keypress:按下鍵盤的字符鍵時觸發

3.keyup:釋放鍵盤上的鍵時觸發

除此之外,還有

變動事件
H5事件
觸摸與手勢事件

DOM事件處理程序
DOM0級事件處理程序
var btn = document.getElementById("myBtn");

btn.onclick = function () {
  alert("clicked");
}
DOM2級事件處理程序
var btn = document.getElementById("myBtn");

btn,addElementListener("click",function(){
  alert("clicked");
},false);

//true: 在捕獲階段調用事件處理程序
//false: 在冒泡階段調用事件處理程序
跨瀏覽器的事件處理程序(封裝)
var EventUtil = {
  addHandler: function(element,type,hander) {
    if (element.addEventListener) {
      element.addEventListener(type,handler,false);
    } else if (element.attachEvent) {   //IE
      element.attachEvent("on"+type,handler);
    } else {
      element["on"+type] = handler;   //HTML事件
    }
  }
}

事件委托的原理以及優缺點
function delegateEvent (interfaceEle,selector,type,fn) {
  if (interfaceEle.addEventListener) {
    interfaceEle.addEventListener(type,eventfn);
  } else {   //IE
    interfaceEle.attachEvent("on"+type,eventfn);
  }
  function eventfn (e) {
    var e = e || window.event;
    var target = e.target || e.srcElement;   //兼容fireFox
    if (matchSelector(target,selector)) {
      if (fn) {
        fn,call(target,e);   //將fn內部的this指向target
      }
    }
  }
}

var odiv = document.getElementById("iDiv");
delegateEvent(odiv,'click',function(){
  alert("clicked");
});

優點:
1.大量減少內存占用,減少事件注冊
2.新增子對象無需再次對其綁定事件


原生Javascript實現事件代理
<ul id="parentList">
  <li id="post-1">1</li>
  <li id="post-2">2</li>
</ul>

<script>

  function delegateEvent(interfaceEle,type,fn) {
    if(interfaceEle.addEventListener) {
      interfaceEle.addEventListener(type,fn);
    } else {   //IE
      interfaceEle.attachEvent("on"+type,fn);
    }
  }

var parentList = document.getElementById("parentList");

delegateEvent(parentList,"click",function(e){
  var e = e || window.event;   //兼容IE
  var target = e.target || e.srcElement;   //兼容fireFox
  alert(target.id);   
});

</script>

這段代碼監聽了整個<ul>標簽并且啟用了事件代理,點擊<li>標簽的時候會返回具體的li標簽的id,對新增的對象元素也同樣有效


事件冒泡和事件捕獲

事件冒泡:事件開始時由最具體的元素接收,然后逐級向上,傳播到較為不具體的節點

事件捕獲:不太具體的節點更早地接收到事件,而最具體的節點最后接收到事件

DOM事件流:同時支持兩種事件模型:捕獲型事件和冒泡型事件,但是,捕獲型事件先發生。兩種事件流會觸及DOM中的所有對象,從document對象開始,也在document對象結束。

支持W3C標準的瀏覽器在添加事件時用addEventListener(event,fn,useCapture)方法,基中第3個參數useCapture是一個Boolean值,用來設置事件是在事件捕獲時執行,還是事件冒泡時執行。而不兼容W3C的瀏覽器(IE)用attachEvent()方法,此方法沒有相關設置,不過IE的事件模型默認是在事件冒泡時執行的,也就是在useCapture等于false的時候執行,所以把在處理事件時把useCapture設置為false是比較安全,也實現兼容瀏覽器的效果。


JSON

json的全稱為JavaScript Object Notation,即對象表示法,是一種約定的數據格式。


AJAX

ajax的全稱為Asynchronous JavaScript and XML,即異步的JavaScript和XML,
理解它的過程很簡單,就是用JS發起一個請求,并得到服務器返回的內容,原生JS寫法如下:

//第1步 聲明一個對象
var request; 
//第2步 根據瀏覽器賦予對象http請求的方法
if (window.XMLHttpRequest) { //code for IE7+, Firefox, Chrome, Opera, Safari
  request = new XMLHttpRequest();
} else { //code for IE6, IE5
  request = new ActiveXObject("Microsoft.XMLHTTP");
}
//第3步 確定服務器返回的方法
request.onreadystatechange = function () {
  if (this.readyState == 4 && this.status == 200) {
    console.log(request.responseText);
  }
}
//第4步 在之前聲明的基礎上發起請求
request.open("GET","filename",true);
request.send();

注意以下要點:

IE6及以下版本用的是ActiveXObject方法,其余用XMLHttpRequest方法。

XMLHttpRequest對象三個重要的屬性:

onreadystagechange 存儲函數(或函數名),每當 readyState 屬性改變時,就會調用該函數。

readyState 存有 XMLHttpRequest 的狀態。從 0 到 4 發生變化。
0: 請求未初始化
1: 服務器連接已建立
2: 請求已接收
3: 請求處理中
4: 請求已完成,且響應已就緒

status
200:"ok"
404:未找到頁面

XMLHttpRequest對象的open()和send()方法:

open(method,url,async);
//規定請求的類型、URL 以及是否異步處理請求。
//method:請求的類型;GET 或 POST
//url:文件在服務器上的位置
//async:true(異步)或 false(同步)

send(string);   
//將請求發送到服務器。
//string:僅用于 POST 請求

與 POST 相比,GET 更簡單也更快,并且在大部分情況下都能用。
然而,在以下情況中,請使用 POST 請求:
1.無法使用緩存文件(更新服務器上的文件或數據庫)
2.向服務器發送大量數據(POST 沒有數據量限制)
3.發送包含未知字符的用戶輸入時,POST 比 GET 更穩定也更可靠

jQuery封裝了AJAX的方法,只需要一行代碼:

$.get('filename').then(function(response){
  //do something
});

原型繼承與擴展
Child.prototype = new Parent();

把父類對象賦值給子類構造函數的原型,這樣子類就可以訪問到父類以及父類的原型,這就叫原型繼承

function Person(name) {
  this.name = name;
}

Person.prototype.sayHello = function() {
  alert ("hello, I'm" + this.name);
};

var BillGates = new Person("Bill Gates"); //建立對象
BillGates.sayHello(); //hello, I'm Bill Gates

Person.prototype.Retire = function() {
  alert("poor"+this.name+"byebye!");
} //建立對象后再動態擴展

BillGates.Retire(); //poor BillGates byebye!

這種建立對象后再動態擴展的情況,就叫做原型擴展,新方法仍然可被之前建立的對象調用


js延遲加載

defer和async是動態創建dom的兩種方式,defer是延遲加載,async是異步下載腳本
在其他情況下,瀏覽器會按照script元素在頁面中出現的順序依次進行解析


封裝與模塊化開發

使代碼規范好用,使用簡單化,只需要知道參數和返回值,可以轉化編程思維角度

var modulel = (function(){
  var _count = 0;
  var m1 = function(){
  //...
  }
  var m2 = function(){
  //...
  }
  return {
    m1:m1,
    m2:m2
  };
})();

跨域問題的解決方法

1.jsonp(jQuery的$.getScript方法就是利用jsonp跨域解決的)
2.iframe
3.window.name
4.window.postMessage
5.服務器上設置代理頁面


DOM操作

(1)創建新節點

createDocumentFragment() //創建一個DOM片段
createElement() //創建一個具體元素
createTextNode() //創建一個文本節點

(2)添加、移除、替換、插入

appendChild()
removeChild()
replaceChild()
insertBefore() //在已有子節點前插入新的節點

(3)查找

getElementsByTagName() //通過標簽名稱
getElementsByName() //通過元素Name屬性值
getElementById() //通過元素id,唯一,所以Element沒有s

前端模塊化開發
發展歷程

1.函數封裝

function f1 () {
  statement
}
function f2 () {
  statement
}

污染了全局變量,容易發生沖突,且模塊成員之間沒有聯系


2.對象的寫法

var myModule = {
  var1: 1,
  var2: 2,
  fn1: function () { },
  fn2: function () { }
}

調用myModule.fn2(); 避免了變量污染,只需要保證模塊名唯一即可
缺陷是外部可以隨意修改內部成員:

myModule.var1 = 100;



3.立即執行函數的寫法

var myModule = (function(){
  var var1 = 1;
  var var2 = 2;
  function fn1 () { };
  function fn2 () { };
  return {
    fn1: fn1,
    fn2: fn2
  };
}) ();

console.info(myModule.var1); //underfined

這樣就無法修改暴露出來的變量和函數,就是模塊化的基礎。

模塊化的規范 CMD和AMD

commonJS 通用模塊定義
1.定義模塊
每一個模塊都是一個單獨的作用域,無法被其他模塊讀取
2.模塊輸出
模塊只有一個出口,module.exports對象,把模塊希望輸出的全部內容放入該對象
3.加載模塊
加載模塊使用require方法,該方法讀取一個文件并執行返回文件內部的module.exports對象

例子

//模塊定義myModel.js
var name = 'Byron';
function printName () {
  console.log(name);
}
function printFullName(firstName) {
  console.log(firstName + name);
}
module.exports = {
  printName: printName,
  printFullName: printFullName
}

//加載模塊
var nameModule = require(./myModel.js);
nameModule.printName

AMD 異步模塊定義


綜合知識

關于緩存的三個關鍵字

cookie:是儲存在瀏覽器上的一小段數據,用來記錄某些當頁面關閉或刷新后仍然需要記錄的信息。
session:是一種讓服務器能夠識別某個用戶的機制。
localStorage:HTML5本地儲存web storage特性的API之一,用于將大量數據保存在瀏覽器中。


前端性能優化

1.減少http請求次數,JS、CSS源碼壓縮
2.前端模版,JS+數據,減少DOM操作次數,優化js性能
3.用innerHTML代替DOM操作,減少DOM操作次數,優化js性能
4.設置className,少用內聯style
5.少用全局變量,緩存DOM節點查找的結果
6.圖片壓縮和預加載,將樣式表放在頂部,腳本放在底部,加上時間戳
7.避免使用table,顯示比div+css布局慢


頁面加載過程

1.瀏覽器根據請求的URL交給DNS域名解析,找到真實IP,向服務器發起請求
2.服務器交給后臺處理完成后返回數據,瀏覽器接收文件(HTML、JS、CSS、圖片等)
3.瀏覽器對加載的資源進行語法解析,建立相應的內部數據結構
4.載入解析到的資源文件,渲染頁面,完成


瀏覽器渲染過程

1.瀏覽器解析html源碼,然后創建一個DOM樹,每一個標簽都有一個對應的節點,并且每一個文本也有一個對應的文本節點(DOM樹的根節點就是documentElement,對應html標簽)
2.瀏覽器解析CSS代碼,計算最終的樣式數據(對CSS中非法的語法會忽略掉,按優先級排列:瀏覽器默認設置>用戶設置>內聯樣式>外鏈樣式>html中的style)
3.構建渲染樹(忽略不需要渲染的元素)
4.根據渲染樹把頁面繪制到屏幕上


XHTML

可拓展超文本標記語言,將HTML作為XML的應用而重新定義的標準
其中script需要寫成以下形式才能被識別

<script>
  //<![CDATA[
    //內容
  //]]>
</script>

CSS

css定義的權重

div:1
.class:10
#id:100
內聯樣式表:1000
#id div:100+1=101
.class div:10+1=11
.class1 .class2 div:10+10+1=21

權重相同時,最后定義的樣式會起作用


盒模型

標準模式:box-sizing:content-box;

怪異模式:box-sizing:border-box;

兩種模式的區別:

標準模式會被設置的padding撐開,而怪異模式則相當于將盒子的大小固定好,再將內容裝入盒子。盒子的大小并不會被padding所撐開。

.a a a a

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,362評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,577評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,486評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,852評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,600評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,944評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,944評論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,108評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,652評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,385評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,616評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,111評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,798評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,205評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,537評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,334評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,570評論 2 379

推薦閱讀更多精彩內容

  • 在線閱讀 http://interview.poetries.top[http://interview.poetr...
    前端進階之旅閱讀 114,560評論 24 450
  • 1.幾種基本數據類型?復雜數據類型?值類型和引用數據類型?堆棧數據結構? 基本數據類型:Undefined、Nul...
    極樂君閱讀 5,566評論 0 106
  • 長街融融日,小樓淡淡風,這樣的日子適合寫信。 鋪開素靜的白紙,拈起筆來放在唇邊咬了咬,缺發現可以傾訴的人寥寥無幾。...
    唯有孤閱讀 433評論 0 0
  • 很早以前能溝通的工具就是信封。直到現在信息網絡的發達更多人用微信。話語輕而易舉的說出,更多深刻深沉的話語卻無法表達...
    lilinjuan閱讀 349評論 0 1
  • 我們是這個世界中忙碌的人群 習慣著每天看同樣的風景 習慣著每天走一樣的路 習慣著每天 在自己的生活里兜兜轉轉 而我...
    親愛的小千閱讀 370評論 0 0