最近在看《JavaScript高級程序設計》這本書,面對着700多頁的厚書籍,內心有點壓力,因此我決定梳理一下。。探究一下到底怎麼讀這本書。本書的內容好像只有到ES5。。。因此只能之後慢慢加了。。。javascript
這一系列文章主要圍繞:html
在看書以前,先大致看一下目錄,將全書劃分一下,對每個有大致的瞭解。可分爲:java
把握重點
由於語法是個死的東西,因此在我看來,前面5章的內容是基礎中的基礎,然後面的6-7章的內容則是傳達的一種思想-面向對象。因此在學習的時候,先把握重點。web
好了如今進入正題,如今能夠打開書的第一章了,而後看完下面的預備知識,再看書。數組
預備知識:
Netscape Navigator是一個瀏覽器,瀏覽器!!!如下簡稱NN瀏覽器。瀏覽器
總結梳理
關於版本的更新問題,有人作了一張圖,拿來了,不知道有沒有問題。
服務器
關注的重點
這裏面有一個重要的知識就是MIME類型,在後面會遇到,若是忘了的話,會看的很糊塗。
MIME類型:編寫代碼使用的腳本語言的內容類型 能夠是text/html 也能夠是text/javascript數據結構
總結梳理
如何在瀏覽器中使用JavaScript呢?須要用到HTML。因此就引出了幾個問題app
按照這個內容本身想一下,在書中均可以找到答案。ide
和c java語言有不少類似之處,因此在這裏就重點說一下不一樣之處。
1. 鬆散類型
var message;
var message = 16;
message = "hello";
也就是一個變量可以存全部的類型。甚至咱們均可以不用加var
像這樣定義就會直接建立全局變量message = 16
(由於有了window對象,因此實際是window.message = 16')。
2. 沒有塊級做用域
不像其餘語言{}
內容裏面的都是塊級做用域,而在JavaScript中是沒有這一說的。它的做用域法則是不同的。
在JavaScript中,把這個東西叫作,執行環境。注意,執行環境只分爲兩種全局執行環境(除函數以外的環境)和局部執行環境(只有函數內部的區域是局部的。)每一個執行環境都有一個與之相關聯的變量對象(全部的變量與函數保存在裏面)
對於全局執行環境來講,對象就是window對象,而對於局部(函數)環境來講,稱爲活動對象(最開始至包含arguments對象)
環境結束就會銷燬,其裏面的變量,函數。全局環境的關閉是頁面關閉或者瀏覽器關閉,而局部環境的關閉是指函數結束。
由於這個道理就能夠在函數內部創建相同的變量。(兩個對象不一樣)
其查詢標識符是從下道上的一個過程,例以下面的代碼:
var color = "blue"; function getColor() { var color = "red"; return color; } alert(getColor()); //"red"
搜索的過程就是先搜索getColor()的變量對象,是否包含color,是就結束,否就找下一個變量對象(此例子中是全局對象即window對象),都找不到的話就返回undefined
3.[]表示法
和其餘語言不一樣,在javaScript中[]不止用在數組中,它還能夠用在對象上面。如咱們如今創建一個名爲dog的對象,若是咱們想要訪問name屬性,那麼能夠這麼寫:dog["name"],【注意】屬性是以字符串的形式的。
看完了不一樣之處,最難理解的東西就已經掌握了,其餘的就是一些細小的東西了,只須要按照必定的邏輯背一下熟悉熟悉,多練多實踐,我就以爲夠了,這也是筆者的見解。
學習的脈絡就是根據不一樣的類型開始逐一熟悉。
1.數據類型
注意數據類型指的是數據的類型。
分爲五種基本類型,和一種複雜類型。
五種基本類型:Undefined,Null,Boolean,Number,String
一種複雜類型:Object.
提到這個就很天然的想到,既然是鬆散類型的,該怎麼檢測給定變量的數據類型呢?
答案是typeof操做符,注意是操做符。
他返回的是:"undefined" "string""number" "boolean" "object" "function"
用法:typeof 變量
或typeof(變量)
2.Undefined類型
Undefined類型我把它理解爲未被定義過的類型,是一個undefined值,
這有兩種狀況:
體會一下兩個的區別:
alert(message);//會顯示錯誤信息 alert(typeof message);//"undefined"值
3.Null
Null類型只有一個null值的類型。null值是一個空對象指針,因此typeof null
返回的是"object"
而undefined就是由null值派生出來的。
因此undefined == null
返回的是true
4.Number類型
轉換問題:
這是一個很清晰的脈絡,對於不一樣類型的值怎麼轉換是一個很大的問題。
因此方法有Number()、parseInt()、parseFloat().
不一樣方法的規則是什麼?
整數類型:
十進制的表示,八進制的表示,以及16進制的表示。
浮點數類型:
自動轉換整數的特色,e表示法。
數值範圍:
最大和最小的範圍是?超出範圍的數字如何表示?
NaN:
NaN是一個特殊的值。有兩個特色
5.String類型:
Unicode字符組成的字符串。
轉換問題
一樣是轉換問題,這一個脈絡仍是很清晰。
String(),toString()方法。它們分別轉換的規則是什麼?對於數值型的轉換有沒有什麼不同的地方?對於null和undifined呢?
6.引用類型
爲何會多出一個引用類型呢?所謂引用類型實際是一個數據結構,是描述一類對象的屬性和方法。和「類」類似。它與對象是什麼關係呢?對象是某一個引用類型的實例。
在上面說的一種複雜數據類型Object就是指的是引用類型,是一種大的概念。
如何學習這裏面的內容呢?因爲對象就是一系列的屬性和方法,因此重點是經常使用的屬性和方法,而這一點也沒有什麼難度,無非就是熟練的過程。仍是多練。
引用類型的建立
new標識符。如 var message = new Object();
var item = new Array();
如下列出幾種重要的引用類型,對於方法和屬性的細節,暫時拋棄。
1) Object類型
對於Object的建立除了new 還有 字面量,即:
var message = { name : helo, color : red, ... }
【注意】在使用字面量的時候,是不調用構造方法的。
2)Array類型
一樣的建立一個Array的對象也有不一樣的方法:
例如:var colors = new Array(2);//數組的長度爲2.
var colors = ["red","blue","green"];//用[]來建立一個特定的數組
固然JavaScript中的數組更加神童廣大,最大的區別就是:數組長度可變。
相關的方法,請具體查閱書籍。
3)Date類型
4)RegExp類型
5)Function類型
這裏要提一下了,在Javascript中,每一個函數都是Function類型的實例,也能夠說是對象。
因此能夠這麼寫代碼:var sum = new Function("num1","num2","return num1 + num2");
可是不建議。
另外兩種定義一個函數的方法是:function sum (num1,num2) {...}//函數聲明
var sum = function(num1,num2){...}//函數初始化
這兩種定義的方式是有區別的,
【函數聲明】:在代碼執行以前,解析器讀取並將函數聲明添加到執行環境中去。因此如下代碼是沒有問題的。
alert(sum(10,10)); function sum(num1,num2){ return num1 + num2; }
【函數自定義】:則是在執行到函數以前,是不會保存的。因此如下代碼會出現「unexpected identifier」錯誤
alert(sum(10,10)); var sum = function(num1,mum2) { return num1 + num2; };
另外一個方面既然函數是對象的話,函數名是指針變量,那麼就能夠把這個函數變量,看成參數,傳遞給另外一個函數。
同時它還應該有屬性和方法。具體有哪些屬性本身回憶或查閱。
在這裏重點提一下 prototype屬性,對於引用類型而言,prototype是保存他們全部實例方法的真正所在。(後面會更加詳細的講解。)
6)基本包裝類型
爲了便於操做基本類型,又建立出了特殊的引用類型,Boolean、Number、String。
實際上讀取一個基本類型,他就會自動的建立各自的實例,執行相關操做,而後就會銷燬
如:
var s1 = "some text"; var s2 = s1.substring(2);
下面的代碼就體現了銷燬過程
var s1 = "some text";//在內部的過程 s1.color = "red"; alert(s1.color);
在第一行代碼中,建立了一個實例,建立了字符串,隨之銷燬,第二行又從新建立了一個實例,附上red後,銷燬,在第三行中在執行中,又建立了一個實例,此時實例的屬性是undefined。
同時Object構造函數也具備這個功能。
如:
var obj = new Object("some text");//自動返回基本包裝類型的實例 alert(obj instanceof String);//true
三種各自的包裝類型詳細方法本身回憶。
7)單體內置對象
這些書有一大特色,就是裏面的名詞真的讓你心驚膽戰,明明很簡單的事情,非要弄個你不熟悉的名字嚇唬你。
單體內置對象,就是不依賴宿主環境的對象,在程序執行以前就已經存在。有兩個 Global和Math
Global對象
書中寫的頗有意思,叫作「終極兜底兒對象」,全部不屬於其餘對象的屬性和方法,最終都是他的屬性和方法
你必定想知道以前不是有window對象嗎?他們兩個是一個什麼關係,如今先保留這個問題。
Global是一個虛擬的東西,他不能new出來,可是倒是真實存在的。全部在全局做用域中定義的屬性和函數,最終都是它的屬性和方法。其裏面還有一些內置的函數,諸如咱們以前瞭解過的isNaN(),isFinite(),parseInt(),parseFloat()等等,都是Global的方法。
如今咱們就來講一下window是一個什麼東西,以前說過在全局做用域中定義的屬性和方法,其實均可以用window.XX來訪問獲得,由於不能直接訪問Global對象,因此window對象實現了Global對象的一部分,全局做用域中屬性和函數,就都成爲了window對象的屬性和方法。
接下來Global對象的屬性和方法請自行回憶腦補。
Math對象
對於Math對象沒有什麼難理解的,一樣沿着他的屬性和方法回憶就好。。
首先這一思想是最重要的,也是之後的基礎,因此脈絡清楚對於有好處。
到目前爲止,咱們怎麼兩種方法建立對象:
function createPerson(name,age,job) { var o = new Object(); o.name = name; o.age = age; o.job = job; o.sayName = function() { alert(this.name); }; return o; } var person1 = createPerson("Nicholas",29,"Software Engineer"); var person2 = createPerson("Greg",27,"Doctor");
function Person(name,age,job) { this.name = name; this.age = age; this.job = job; this.sayName = function() { alert(this.name); }; } var person1 = new Person("Nicholas",29,"Software Engineer"); var person2 = new Person("Greg",27,"Doctor");
用構造方法來建立的實例中,這兩個對象都有一個constructor(構造函數)屬性,該屬性指向Person。
可是目前的這個構造方法建立對象是有問題的,回想一下每一個函數其實都是Function的一個實例,在以上建立person1和person2的時候,雖然兩個函數是同樣的,可是須要在裏面建立兩個不一樣的Function實例,因此能夠改進一下:
function Person(name,age,job) { this.name = name; this.age = age; this.job = job; this.sayName = sayName; } function sayName() { alert(this.name); } var person1 = new Person("Nicholas",29,"Software Engineer"); var person2 = new Person("Greg",27,"Doctor");
這樣一來雖然能夠解決問題,可是若是有不少函數的話,就須要在外面定義好多函數,就體現不了封裝的思想了。爲了解決這一問題,就出現了原型。(prototype)
關於原型
每一個對象都有一個私有屬性(稱之爲 [[Prototype]]),它持有一個鏈接到另外一個稱爲其 prototype 對象(原型對象)的連接。該 prototype 對象又具備一個本身的原型,層層向上直到一個對象的原型爲 null。根據定義,null 沒有原型,並做爲這個原型鏈中的最後一個環節
再看一下書中的那個示意圖,會很明白。
關於幾個方法:isPrototypeOf()
是否爲某個對象的原型Person.prototype.isPrototypeOf(person1)//true
Object.getPrototypeOf()
獲得某個對象的原型。alert(Object.getPrototypeOf(person1).name;//"Nicholas"
hasOwnProperty()
方法能夠檢測一個屬性是否存在實例中。alert(person1.hasOwnProperty("name"));//true
function Person() {} Person.prototype = { constructor:Person; name:"nigulasi", age:29, job:"Software Engineer", sayName:function() { alert(this.name); } };
以上兩種方式都有各自的缺點,取他們的長處組合,是一個很好的方法。
function Person(name,age,job) { this.name=name; this.age=age; this.job=job; this.friends=["Shelby","Court"]; } Person.prototype = { constructor:Person; sayName:function(){ alert(this.name); } };
實例屬性都是在構造函數中定義的,而全部實例共享的屬性constructor和方法sayName()則是在原型中定義的。
原型鏈繼承
//組合方法建立父級對象 function Animal(name,age) { this.name=name; this.age = age; } Dog.prototype.getName() { alert(this.name); } //組合方法建立對象,利用原型繼承 function Dog(name,age) { this.name = name; this.age = age; } //實現繼承 Dog.prototype = new Animal();
構造函數實現繼承
function Super() { this.colors = ["red","blue","green"]; } function Sub() { //繼承自Super Super.call(this);//使用apply()和call()方法能夠在新建立的對象上執行構造函數。 }
組合繼承
一樣集兩種之所長。
function Super(name) { this.name = name; this.colors = ["red","blue","green"]; } Super.prototype.sayName = function(){ alert(this.name); }; function Sub(name,age) { //繼承屬性 Super.call(this.name); this.age = age; } //繼承方法 Sub.prototype = new Super(); sub.prototype.contructor =sub Sub.prototype.sayAge = function() { alert(this.age); };