定義 || 賦值java
1-函數的定義
函數定義的兩種方式:
「定義式」函數:function fn(){ alert("喲,喲!"); }
「賦值式」函數:var fn = function(){ alert("切可鬧!"); }
@頁面加載時,瀏覽器會對JavaScript代碼進行掃描,並將 定義式函數進行預處理(相似C等的編譯)。【函數聲明提高】
處理完再由上至下執行,遇到賦值式函數 則只是將函數賦值給一個變量,不進行預處理,待調用時才進行處理。
@在定義前面調用函數時,定義式函數正常執行,賦值式函數會報錯 (提示:oFn is not a function)。數組
2-變量與函數的定義
變量:①var a; 定義變量a。
②var a = 123; 定義變量a,再給變量a賦值。
函數:①function fn(...){...} 聲明函數fn。
②var oFn = function(...){...} 先定義變量oFn和一個匿名函數,再將匿名函數賦值給變量oFn。
@定義變量和定義函數都會先預處理,變量賦值則是在執行中完成。
@定義變量的做用:只是指明變量做用域。
有定義沒賦值的變量 和 使用沒定義的變量 值都爲undefined。
@定義函數的做用:除了指明函數做用域,同時定義函數體結構——包括函數體內部的變量定義和函數定,此過程遞歸。瀏覽器
alert(a); //function a(){} alert(b); //function b(){} alert(c); //undefined var a = "a"; function a() {} function b() {} var b = "b"; var c = "c"; var c = function() {} alert(a); //a alert(b); //b alert(c); //function(){} ①雖然第一個 alert(a) 在最前面,可是你會發現它輸出的值居然是 function a() {},這說明,函數定義確實在整個程序執行以前就已經完成了。 ②再來看 b,函數 b 定義在變量 b 以前,可是第一個 alert(b) 輸出的仍然是 function b() {},這說明,變量定義確實不對變量作什麼,僅僅是聲明它的做用域而已,它不會覆蓋函數定義。 ③最後看 c,第一個 alert(c) 輸出的是 undefined,這說明 var c = function() {} 不是對函數 c 定義,僅僅是定義一個變量 c 和一個匿名函數。 ④再來看第二個 alert(a),你會發現輸出的居然是 a,這說明賦值語句確實是在執行過程當中完成的,所以,它覆蓋了函數 a 的定義。 ⑤第二個 alert(b) 固然也同樣,輸出的是 b,這說明無論賦值語句寫在函數定義以前仍是函數定義以後,對一個跟函數同名的變量賦值總會覆蓋函數定義。 ⑥第二個 alert(c) 輸出的是 function() {},這說明,賦值語句是順序執行的,後面的賦值覆蓋了前面的賦值,無論賦的值是函數仍是其它對象。
3-變量賦值
對於弱類型的JavaScript,聲明變量不須要聲明其類型。
隨之的問題,在使用 直接量和引用量 卻混亂一片:
①var x = "111"; var y = x; x = "222"; alert(y);
在JavaScript中,此時y值爲111,即字符串的賦值是直接量操做,直接把數據賦值給y的存儲空間。
在java等語言中,y的值爲222,即x在存儲器中將地址(指針)賦給變量y。
②var x = ["111"]; var y = x; x[0] = "222"; alert(y[0]);
在JavaScript中,此時卻與①不一樣,y[0]值爲222,引用量操做,即x把在存儲器中的地址(指針)賦給了y。
③var x = ["111"]; var y = x; x = ["222","333"]; alert(y[0]);
在Javascript中,此時y的值又是111,即此賦值又是直接量操做。
JavaScript解析器 對不一樣類型的差別:
var x = "xxxx"; var y = ["11","22"];
①在字符串中,解析器直接把字符串賦給變量x(直接量)。
②在數組中,解析器把數組的指針賦給變量y(引用量)。
上述問題②中,x[o] = "222"因爲沒有給x新定義值,沒有新開闢存儲空間,只修改了它存儲空間裏的數據,故仍是引用量。
上述問題③中,建立var x = ["111"]時,解析器在內存中爲數組建立存儲空間,x則得到該空間的地址(指針),
再執行x = ["2","3"]給數組新定義值時,解析器會開闢新存儲空間放這個數組,x則爲新存儲空間的指針。ide
由上述可知,JavaScript的變量能存儲直接量 也能存儲引用量。
在大字符串鏈接 和 循環裏賦值等地方,需留意此變量特性對執行效率的影響。函數
var x=""; var big = "這裏是一大坨字符串..."; for (i=0; i<100; i++){ a += big; } x = a; //由於是字符串操做,使用直接量,每次循環都要操做大字符串,很是笨重,效率低下。若是改用引用量操做,即經過數組,效率甚至會提升十幾倍: var s = "這裏又是一大坨字符串..."; var a = []; for (i=0; i<100; i++){ a[i] = s; } s = a.join("");
4-原型的定義和賦值
原型:若是構造器有個原型對象A,由構造器建立的對象實例(Object Instance)都複製於原型對象A。
①每一個對象都有一個原型鏈,由自身向上包含一個或多個對象,自己爲起始對象。
②在JavaScript中,一個對象 或 一個對象實例沒有原型,不存在「持有某個原型」的說法,只存在「構造自某個原型」的說法。
構造器纔有原型,<構造器>.prototype屬性指向原型。spa
function fn() { var name = "大蝦"; var age = 23; function code() { alert("切克鬧!"); }; } var obj = new fn();
上述代碼中:
①obj爲對象實例,fn爲一個構造器。
②obj.prototype; //undefined,對象實例沒有原型。
fn.prototype; //[object Object],原型是一個對象。
③obj.constructor; //輸出fn()的函數代碼。
fn.construtor; //function Function(){[native code]},native code表示JavaScript引擎的內置函數。
obj.construtor == fn; //true,obj構造自fn。
④fn.prototype.construtor == fn; //true,函數原型的構造器 默認爲函數自己。prototype
對象實例 複製構造器的原型對象時,採用的是讀遍歷機制複製的。
讀遍歷機制:指僅當寫某個實例的成員時,將成員信息複製到實例映像中。
即構造的新對象裏面的屬性 指向原型中的屬性。讀取對象實例的屬性時,獲取的是原型對象的屬性值。指針
Object.prototype.value = "abc"; var obj1 = new Object(); var obj2 = new Object(); obj2.value = 10; alert(obj1.value);//輸出abc,讀取的是原型Object中的value alert(obj2.value);//輸出10,讀取的是obj2成員列表中的value delete obj2.value;//刪除obj2中的value,即在obj2的成員列表中將value刪除掉 alert(obj2.value);//輸出abc,讀取的是原型Object中的value
上述說明了讀遍歷機制 如何管理實例對象成員列表 和 原型中的對象成員。
①只有第一次對屬性進行寫操做時,纔會在對象的成員列表中 添加該屬性的記錄。
②當obj1和obj2經過new構造出來,只是一個指向原型的引用,這樣的讀遍歷 避免了建立對象實例可能的大量內存分配。
③obj2.value屬性被賦值10時,obj2的成員表中添加了一個value成員並賦值10。
此成員表記錄了對象發送了修改的成員名、值與類型。遵循2個原則:
a、保證在讀取是首先訪問。
b、對象中午指定屬性時,遍歷對象的整條原型鏈,直到原型爲空或找到該屬性。
④delete obj2.value刪除的是成員表的屬性。code
原型的構造器
函數的原型 是內置的Object()構造器的一個實例。但該對象實例建立後,constructor屬性總會先被賦值爲當前函數。
究其根源在於構造器(構造函數)的原型(prototype)的constructor屬性指向構造器自己。對象
function MyObject() { } alert(MyObject.prototype.constructor == MyObject); //顯示true,代表原型的構造器老是指向函數自身的 delete MyObject.prototype.constructor; //刪除該成員(指向自身的原型構造器) alert(MyObject.prototype.constructor == Object); alert(MyObject.prototype.constructor == new Object().constructor); //刪除操做使該成員指向了父代類原型中的值 //均顯示爲true
上例中,myObject.protptype與new Object()沒有實質區別,只是在建立時將myObject的constructor值賦值爲自身。
函數與構造器並無明顯的界限:
當指定一個函數的prototype時,該函數就會成爲構造器。
此時用new建立實例時,引擎會構造一個新對象,把這個新對象的原型鏈 鏈接向該函數prototype屬性就能夠了。
原型繼承中的「原型複製」
經過設置 不一樣構造器建立出來的實例的constructor屬性,能指向同個構造器。
function MyObject() { } function MyObjectEx() { } MyObjectEx.prototype = new MyObject(); var obj1 = new MyObject(); var obj2 = new MyObjectEx(); alert(obj2.constructor == MyObject); //true alert(MyObjectEx.prototype.constructor == MyObject); //true
obj1和obj2是由不一樣的兩個構造器(MyObject和MyObjectEx)產生的實例。然而,兩個alert都會輸出true,即由兩個不相同的構造器產生的實例,它們的constructor屬性卻指向了相同的構造器。這體現了原型繼承中的「原型複製」。MyObjectEx的原型是由MyObject構造出來的對象實例,即obj1和obj2都是從MyObject原型中複製出來的對象,所以它們的constructor指向的都是MyObject!