在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呼叫函式
看到一個new Function用法
function callAnotherFunc(fnFunction, vArgument) { fnFunction(vArgument); } var doAdd = new Function("iNum", "alert(iNum + 10)"); callAnotherFunc(doAdd, 10); //輸出 "20"