前言 在看書的過程中,發現有一些內容屬於那種邊邊角角容易忘記卻又非常重要。 所以,在這裡留下一篇筆記,以便查閱。 第1章 js簡介 js組成部分:ECMAScript、DOM、BOM 瀏覽器就是js的解釋器。 DOM是文檔對象模型,通過它來操作網頁對象上的元素,這些元素就是HTML上的各種標簽。 B ...
前言
在看書的過程中,發現有一些內容屬於那種邊邊角角容易忘記卻又非常重要。
所以,在這裡留下一篇筆記,以便查閱。
第1章 js簡介
js組成部分:ECMAScript、DOM、BOM
瀏覽器就是js的解釋器。
DOM是文檔對象模型,通過它來操作網頁對象上的元素,這些元素就是HTML上的各種標簽。
BOM是瀏覽器對象模型,可以操作瀏覽器,其中XMLHttpRequest這個對象很重要,ajax非同步處理技術就會用到它。
第2章 在HTML中使用js
js腳本預設是從上到下依次執行的,如果寫在head里,就會堵塞。
script元素用來將js腳本插入HTML文件。
script中的async屬性的作用是非同步載入,不用等待,不用排隊,要註意的是它不保證哪一個腳本先執行完畢,所以在載入期間不要改DOM。
script中的defer屬性的作用是延遲載入,相當於放在body元素的底部位置,等頁面全部呈現了才會執行。它也不保證誰先執行完畢。
綜上,最後把腳本放在body元素內的底部,即主體內容後面,</body>
的前面。
noscript元素內的文本會在瀏覽器不支持js的情況下顯示出來。
第3章 基本概念
標識符就是變數、函數、屬性、函數參數的名字。
區分大小寫。
字母數字下劃線和美元符號。
其中,數字不可以作為開頭。
最好用小駝峰,像這樣:myName,hisAge。
保留字、關鍵字、布爾值(true、false)、null不可以做標識符。
嚴格模式:"use strict"
對那些不確定的行為和不安全的方式加以限制,如果發生會報錯,讓代碼更強壯。
語句最好加分號。
關鍵字就是像聲明時用的var、let、function……
保留字就是暫時還沒有規定用途的準關鍵字。
未初始化的變數(就是沒有給值的變數)保存了undefined。
在函數中不加var來聲明的變數,就會保存到window上,變成全局變數。
全局變數哪都能用。
typeof操作符可以判斷:undefined boolean number string function object
其中null經過typeof也返回給你object,因為它被當成一個空的引用。
數組、函數、對象都是對象,它在記憶體上保存的僅僅是一個引用地址,通過這個引用才可以找到真正的值。
undefined == null => true
undefined === null => false
NaN === NaN => false
+0 === -0 => true
Object.is()用來判斷兩者是否相等。
Object.is(NaN, NaN); => true
Object.is(+0, -0); => false
parseInt(開頭不是數字的字元串); => NaN
parseFloat(開頭不是數字的字元串); => NaN
null和undefined沒有toString()方法。
var o = new Object();
var o = new Object; // 可以省略 但最好不要省略
Object相當於Object類,而o就是Object這個構造函數原型派生出來的一個對象。
Object的實例的屬性方法:
o.constructor:構造函數,保存著當前實例的函數。比如上面的Object。
o.hasOwnProperty(propertyName):檢查當前實例上是否存在給定的屬性。(跟原型無關)
Object.prototype.isPrototypeOf(o):用於測試一個對象是否存在於另一個對象的原型鏈上。
toString():返回字元串表示。
valueOf():返回當前對象的字元串、數組或布爾值表示。
var a=0
++a; // 0
a // 1
var b=0
b++; // 1
b // 1
與&&
或||
非! !true === false
邏輯短路:
true && 1 => 1
true || 1 => true
false && 2 => false
false || 2 => 2
2**3 => 8
23 < 3 => false
"23" < 3 => false 先把"23"轉換成數字23,然後比較
"a" < 3 => false "a"轉換成數字變成NaN,NaN不等於任何數字
"23" < "3" => true 都是字元串就比較字元編碼的大小
如果是對象的比較,先執行valueOf(),如果沒有valueOf()方法,那麼就調用toString()方法。然後用基本類型值繼續比較。
三元運算符:var value = 5 > 10? '5勝出!' : '10勝出';
迴圈語句可以重覆做一件事情,這樣就不用每一次代碼都寫出來了。
有固定次數時,使用for迴圈,否則用while迴圈。
迴圈中有兩種特殊用途的語句:break語句和continue語句。
break語句跳出當前迴圈體,不迴圈了。
continue語句跳過當前一輪的迴圈,進行下一輪迴圈。
函數是一組邏輯的封裝,一般一個函數就代表一個功能。通過執行函數來實現對應的功能。
函數放在對象里,就稱為對象的方法。執行對象里的函數,我們稱之為調用對象的方法。
函數無需指定返回值,因為它沒有指定返回值類型這一說,但最好有返回值,格式是return 返回值。
如果沒有指定返回值,那麼會預設返回一個undefined作為返回值。
return語句後面的語句永遠不會執行。
函數的實參可以隨便傳幾個,它們會被保存在arguments對象里,arguments是一個類數組。(一個有length屬性,類似數組,保存著實參的列表。)
如果沒有傳遞參數,和var未初始化一樣,會被賦值為undefined。
Java中可以定義函數簽名(接受參數的類型和數量),只要簽名不同,就可以同時存在同名的函數,
但是JS中不可以!它的函數參數是一個類數組,因此JS沒有函數重載,重名會被後者覆蓋!
第4章 變數作用域和記憶體問題
變數的值分兩種,一種是基本數據類型值,一種是引用類型值。
基本數據類型值是按值訪問的,它可以直接操作保存在變數中的實際的值。他們被放在棧記憶體中。
引用類型值是按引用訪問的,只能操作它的引用地址,不能操作對象的記憶體空間。他們被放在堆記憶體中。
引用類型會有各種屬性和方法。
當我們複製基本類型值時,原來的值和複製得到的值是相互獨立、互不幹擾的,是兩碼事。
當我們複製引用類型值時,複製的值只是一個指針一個地址而已,這兩個指針指向同一個對象。當操作任何一個變數時,都會互相發生作用。
js中的所有函數參數都是按值傳遞的,這意味著函數執行後並不會改變作為參數傳遞進去的那個外部的變數值。
通過instanceof操作符檢測對象的類型,看它是哪個構造函數的實例對象。(instance就是例子的意思。)
如果用基本類型就會返回false,因為基本類型不是對象。基本類型使用typeof來檢測。
執行環境又叫執行上下文, 環境中的變數和函數可以訪問其他數據,而每個環境中都有一個對應的變數對象(VO)。這個變數對象里保存著環境中所有的變數和函數。
按規則在瀏覽器中,window對象被認為是全局的執行環境,所以所有的全局變數和函數都是掛載在window對象上的。這個window對象就是全局環境中的變數對象。
這就是當你var value = 123;時,你就能訪問到window.value是123的原因。
每個函數都有自己的執行環境。當執行函數時,函數會產生一個環境,這個環境被推入到一個環境棧中(此時它掌握控制權),而函數一旦執行完成,函數環境就會從環境棧中彈出。
註意,當環境出現時,就會隨之產生一個變數對象,通過變數對象的作用域鏈,我們可以訪問所有的變數和函數。
活動對象:如果這個執行環境是函數產生的,它的變數對象就是活動對象(AO),這裡面一開始只有一個arguments對象(全局環境中並沒有它),沿著作用域鏈可以找到上一層的變數對象,最外層就是全局的變數對象(GO)。(全局的變數對象始終是作用域鏈的最後一個對象。)
原生JS中只有全局作用域和函數作用域。(函數作用域也叫局部作用域)
簡而言之就是,每一個環境下(不管是全局環境還是函數的局部環境),都會對應有一個變數對象,變數對象包含著當前作用域中所有的變數和函數。
比如,全局環境下的變數對象就有全局中所有的變數和函數。
特殊一點的是,在執行函數時會產生函數環境,它的變數對象叫做活動對象,與全局環境不同的是,arguments對象是函數變數對象的專屬。
在函數環境中,可以訪問到父級作用域內變數的原因就是作用域鏈,沿著它就能訪問上一層作用域的變數了。這就是為什麼函數內部可以訪問全局變數的原因。
另外,外部環境是沒有辦法反過來訪問到內部環境中的變數的。函數一旦執行完畢,函數環境內的變數就會被銷毀。
但是如果在執行函數時,函數內部的變數被返回出來,因為它是連著活動對象的作用域鏈,所以這時外部就能訪問內部的值,這就是閉包。
(上面的變數包括基本類型和引用類型,執行環境也叫作作用域。)
原生JS只有全局作用域和局部作用域(函數),但是沒有塊級作用域,這就意味著類似於for迴圈這種代碼塊里的變數可以被全局使用,這樣代碼塊里的變數就很容易被污染。
標記清除,給當前不適用的值加上標記,然後再回收記憶體。(主流)
引用計數,當聲明一個變數並引用值給它時,就會產生1個引用計數,變數每次被引用時次數+1,使用完成後次數-1,當計數為0時意味著它的記憶體被回收。(幾乎不用)
JS的記憶體分配和回收會自動執行,它有自動垃圾收集機制。
第5章 引用類型
對象是引用類型的值,它是某個特定引用類型的實例。
對象是描述了一類事物的屬性和方法。
新對象通過new+構造函數來創建。
var person = new Perosn(); // person就是Person這個構造函數的實例/對象。
對象還可以用對象字面量表示法來創建,var perosn = {};
訪問對象的方法:第一種是點表示法,第二種是方括弧表示法。
點表示法:obj.propertyName
方括弧表示法:obj[propertyName] //註意:方括弧里不僅可以放字元串,放一個值為字元串的變數也是可以的!
數組也是對象的一種,new Array()得到數組實例。
new Array(20)表示一個length長度為20的數組。
數組字面量表示法:var arr = [1,2,3,4];
數組的下標從0開始,比如你要訪問第一個數組項arr[0],如果是第二個呢?那就是arr[1]。
數組的最後一項下標是length-1
檢測數組的方式一:arr instanceof Array
檢測數組的方式二:Array.isArray(arr)
因為數組也是對象,因此它繼承了Object原型對象中的方法toString()、valueOf()等方法。
toString()方法可以把數組內的數組項按照字元串形式返回,預設是用逗號分隔的。
數組的join()方法可以指定分隔符將數組項以字元串形式返回。
數組屬性和方法
函數也是對象。每個函數都是Function類型的實例。
函數的聲明方式有兩種,一種是函數聲明,一種是函數表達式。
函數聲明:function f() {};
函數表達式:var f = function(){}
還有一種方式不推薦:var sum = new Function('n1', 'n2', 'return n1+n2'); // 函數是對象,函數名是指針。
JS有個規則是聲明提升,意思是說js在解析過程中會進行預先的編譯(預編譯)找到那些聲明,並把它們提升到頂部。
函數聲明的優先順序大於函數表達式,函數聲明在執行代碼之前就可以訪問,但是函數表達式不行,它必須要等到執行到那一行才可以,否則在這之前都是undefined。
函數內部有兩個特殊的對象:this和arguments。
this引用的是函數執行的環境對象,一般來說這個this對象是window,但是如果被其他對象調用,那麼this就指向那個調用它的對象。
註意,函數名實際上是一個含有指針的變數,它是指向一個函數的,雖然調用它的可能是不同的人讓this對象發生了變化,但是這個函數名背後的函數一直是同一個函數。
函數的屬性:length和prototype
length是指它的形參長度。
prototype是指它的原型對象,所有對象都有toString()方法,這個toString()方法實際上就保存在prototype里。
函數的方法:apply()和call()
它們的作用都是在特定作用域中調用函數,這樣就可以設置函數體內this對象的值。
這就意味著對象不用在內部定義一堆方法,可以通過call方法調用其他作用域中的函數。
apply和call的第一個參數都是目標對象,第二個參數略有不同。
apply的第二個參數可以傳入一個arguments對象,也可以傳入一個數組。
call只能一個一個傳值。
bind()方法可以將this綁定到它給定的對象上。它會返回這個函數的的實例。
基本包裝類有Boolean、Number、String。它們是比較特殊的引用類型。
new Boolean()、new Numeber()、new String()
當給他們這些引用類型去賦值或者調用方法時,都會經歷一個過程:創建一個相關實例,實例調用指定方法,銷毀這個實例。
引用類型和包裝類型的主要區別在於對象的生存周期。
new出來實例會一直保存在記憶體中,直到當前作用域消失。
包裝類型的對象只會存在於一行代碼執行的瞬間,然後立即銷毀。(這就是為什麼給包裝類指定了屬性再訪問它卻只是輸出undefined的原因,當你去訪問時那個實例早就消失了。)
當我們用typeof去檢測包裝類的類型時,返回object。
轉型函數:var str = '25'; var num = Number(str); // num=25
保留2位有效數字字元串:num.toFixed(2);
字元串屬性和方法
兩個內置對象:Global對象和Math對象。
Global對象通過window對象來訪問,全局變數和函數都是Global對象的屬性。
未完待續。。。