在js中,函數本身屬於對象的一種,因此可以定義、賦值,作為對象的屬性或者成為其他函數的參數。函數名只是函數這個對象類的引用。 函數定義 從技術上講,這是一個函數表達式。但不推薦使用,因為這種語法會導致解析兩次代碼。第一次是解析常規javascript代碼,第二次解析傳入構造函數中的字元串,影響性能。 ...
在js中,函數本身屬於對象的一種,因此可以定義、賦值,作為對象的屬性或者成為其他函數的參數。函數名只是函數這個對象類的引用。
函數定義
1 // 函數的三種創建方法(定義方式) 2 function one(){ // 函數聲明語句,不屬於任何對象,始終預設為全局對象 3 console.log("第一個函數") 4 //預設有一個return this,返回函數中的內容 5 } 6 one(); //必須調用;可以在函數聲明前調用(預處理變異機制) 7 8 var fn=function(){ //函數定義表達式 9 console.log("第二個函數") 10 } 11 fn(); //必須先聲明再調用 12 13 var fun=new Function(console.log("第三個函數")); //Function構造函數 無需調用,會自調
//實際一般應這樣寫:var newFun = new Function("x","return alert(x)");
//[註意]Function構造函數無法指定函數名稱,它創建的是一個匿名函數。
從技術上講,這是一個函數表達式。但不推薦使用,因為這種語法會導致解析兩次代碼。第一次是解析常規javascript代碼,第二次解析傳入構造函數中的字元串,影響性能。
var sum = new Function('num1','num2','return num1 + num2'); //等價於 var sum = function(num1,num2){ return num1+num2; }
[註意]並不是所有的函數都可以成為構造函數
1 var o = new Math.min();//Uncaught TypeError: Math.min is not a constructor
【重覆聲明】變數的重覆聲明是無用的,不會覆蓋之前同一作用域聲明的變數,但函數的重覆聲明會覆蓋前面的聲明的同名函數或同名變數
//變數的重覆聲明無用 var a = 1; var a; console.log(a);//1
1 //覆蓋同名變數 2 var a; 3 function a(){ 4 console.log(1); 5 } 6 a();//1
1 //覆蓋同名函數 2 a();//2 3 function a(){ 4 console.log(1); 5 } 6 function a(){ 7 console.log(2); 8 }
【刪除】函數聲明語句創建的變數無法刪除,這一點和變數聲明一樣。
1 function foo(){ 2 console.log(1); 3 } 4 delete foo;//false 5 console.log(foo());//1
———————————————————
函數調用
javascript一共有4種調用模式:函數調用模式、方法調用模式、構造器調用模式和間接調用模式
【1】函數調用模式
當一個函數並非一個對象的屬性時,那麼它就是被當做一個函數來調用的。對於普通的函數調用來說,函數的返回值就是調用表達式的值。
1 function add(x,y){ 2 return x+y; 3 } 4 var sum = add(3,4); 5 console.log(sum)//7
使用函數調用模式調用函數時,非嚴格模式下,this被綁定到全局對象;在嚴格模式下,this是undefined
function add(x,y){ console.log(this);//window } add();//window
function add(x,y){ 'use strict'; //嚴格模式 console.log(this);//undefined } add();//undefined
因此,’this’可以用來判斷當前是否是嚴格模式
var strict = (function(){return !this;}());
【重寫】因為函數調用模式的函數中的this綁定到全局對象,所以會發生全局屬性被重寫的現象
1 var a = 0; 2 function fn(){ 3 this.a = 1; 4 } 5 fn(); 6 console.log(this,this.a,a);//window 1 1
【2】方法調用模式
當一個函數被保存為對象的一個屬性時,我們稱它為一個方法。當一個方法被調用時,this被綁定到該對象。如果調用表達式包含一個提取屬性的動作,那麼它就是被當做一個方法來調用。
var o = { m: function(){ console.log(1); } }; o.m();//1
方法可以使用this訪問自己所屬的對象,所以它能從對象中取值或對對象進行修改。this到對象的綁定發生在調用的時候。通過this可取得它們所屬對象的上下文的方法稱為公共方法。
var o = { a: 1, m: function(){ return this; }, n: function(){ this.a = 2; } }; console.log(o.m().a);//1 o.n(); console.log(o.m().a);//2
和變數不同,關鍵字this沒有作用域的限制,嵌套的函數不會從調用它的函數中繼承this。如果嵌套函數作為方法調用,其this的值指向調用它的對象。如果嵌套函數作為函數調用,其this值不是全局對象(非嚴格模式下)就是undefined(嚴格模式下)
var o = { m: function(){ function n(){ return this; } return n(); } } console.log(o.m());//window
var o = { m: function(){ function n(){ 'use strict'; return this; } return n(); } } console.log(o.m());//undefined
如果想訪問這個外部函數的this值,需要將this的值保存在一個變數里,這個變數和內部函數都同在一個作用域內。通常使用變數_this、that或self來保存this
var o = { m: function(){ var self = this; console.log(this === o);//true function n(){ console.log(this === o);//false console.log(self === o);//true return self; } return n(); } } console.log(o.m() === o);//true
【3】構造函數調用模式
如果函數或者方法調用之前帶有關鍵字new,它就構成構造函數調用
function fn(){ this.a = 1; }; var obj = new fn(); console.log(obj.a);//1
如果構造函數調用在圓括弧內包含一組實參列表,先計算這些實參表達式,然後傳入函數內
function fn(x){ this.a = x; }; var obj = new fn(2); console.log(obj.a);//2
如果構造函數沒有形參,javascript構造函數調用的語法是允許省略實參列表和圓括弧的。凡是沒有形參的構造函數調用都可以省略圓括弧
var o = new Object(); //等價於 var o = new Object;
[註意]儘管構造函數看起來像一個方法調用,它依然會使用這個新對象作為調用上下文。也就是說,在表達式new o.m()中,調用上下文並不是o
var o = { m: function(){ return this; } } var obj = new o.m(); console.log(obj,obj === o);//{} false console.log(obj.constructor === o.m);//true
構造函數通常不使用return關鍵字,它們通常初始化新對象,當構造函數的函數體執行完畢時,它會顯式返回。在這種情況下,構造函數調用表達式的計算結果就是這個新對象的值
function fn(){ this.a = 2; } var test = new fn(); console.log(test);//{a:2}
如果構造函數使用return語句但沒有指定返回值,或者返回一個原始值,那麼這時將忽略返回值,同時使用這個新對象作為調用結果
function fn(){ this.a = 2; return; } var test = new fn(); console.log(test);//{a:2}
如果構造函數顯式地使用return語句返回一個對象,那麼調用表達式的值就是這個對象
var obj = {a:1}; function fn(){ this.a = 2; return obj; } var test = new fn(); console.log(test);//{a:1}
【4】間接調用模式
javascript中函數也是對象,函數對象也可以包含方法。call()和apply()方法可以用來間接地調用函數。
這兩個方法都允許顯式指定調用所需的this值,也就是說,任何函數可以作為任何對象的方法來調用,哪怕這個函數不是那個對象的方法。兩個方法都可以指定調用的實參。call()方法使用它自有的實參列表作為函數的實參,apply()方法則要求以數組的形式傳入參數。
var obj = {}; function sum(x,y){ return x+y; } console.log(sum.call(obj,1,2));//3 console.log(sum.apply(obj,[1,2]));//3
(函數返回值、函數參數、函數屬性、函數方法)另開篇章
js的運行機制問題:(聲明提升)
1、在js中js引擎會優先解析var變數和function定義!在預解析完成後從上到下逐步進行!
2、解析var變數時,會把值存儲在“執行環境”中,而不會去賦值,值是存儲作用!例如:
alert(a); var a = 2; 這時會輸出undifiend,意思是沒有被初始化沒有被賦值!
這並不是沒有被定義,錯誤了的意思!
3、在解析function時會把函數整體定義,這也就解釋了為什麼在function定義函數時為什麼可以先調用後聲明瞭!其實錶面上看是先調用了,其實在內部機制中第一步實行的是把以function方式定義的函數先聲明瞭(預處理)
//*****************上篇出自:https://blog.csdn.net/luanpeng825485697/article/details/77010261
//*****************下篇出自:https://www.cnblogs.com/hss-blog/articles/9358251.html
//js中只有new Function沒有new function,或者我理解你說的new function是指實例化一個對象 //new Function的作用是從字元串中創建一個匿名方法,如下: var newFun = new Function("alert(1)"); nweFun(); //彈出1 //如果你說的new function是實例化一個對象,那麼代碼如下: function cls(){ this.helloWord = function(){ alert("hello Word!"); } } var clsObj = new cls(); clsObj.helloWord(); //彈出hello Word! //這裡的cls這個你應該要把他看成面向對象裡面的類,而不是js裡面的方法。 //當然本質上他就是一個方法,而且你也可以cls()這樣直接調用。 //更多js面向對象的東西我就不細說了,你可以自行百度。 //直接定義個function,然後調用,代碼如下: function fun(){ alert("hello Word!"); } fun(); //彈出hello Word! //這裡的方法你應該看成面向對象裡面的靜態方法,而不是面向對象裡面的類。 //當然他也確實是一個類,你也可以new fun()來調用。 //但是new fun()得到的對象沒有任何方法。
//其實關於new function 應該是這樣的( 更準確的說應該是new function() )
var clsObj = new function()
{
this.helloWord = function(){
alert("hello Word!");
}
}
clsObj.helloWord(); //彈出hello Word!
//是實例化一個對象(匿名函數),這樣寫的好處是可以防止沒有new調用函數