js的中的函數(三)
方法
什么是js的方法?簡單講,綁定到對象的函數就是方法。
this
在對象的方法中,我們常常使用this關鍵字。this關鍵字代表方法所綁定的對象。
var wangqiang = { name : "wangqiang", age : 18, city : "guangzhou", address : "tianhe", //綁定到對象的函數叫方法 getBirth:function(){ let now = new Date(); return now.getFullYear() - this.age; } } wangqiang.getBirth(); //2005 var birth = wangqiang.getBirth; birth(); //NaN,脫離了綁定的對象。上述代碼所示,在方法getBirth()內部,我們用到了一個this關鍵字。這個關鍵字指向了綁定的對象,要正確執行方法,需要按照 obj.xxx()的方式才能正確地調用方法,保證方法綁定的對象,this的指向才能正確。
【資料圖】
再看如下代碼:
var lili = { name : "lili", age : 12, city : "beijing", address : "chaoyang", getBirth : function(){ let diff = function(year){ //超出了this的作用范圍,this為undefined return year-this.age; } let now = new Date(); console.log(diff(2022)); return now.getFullYear() - this.age; } }在getBirth方法中,我們有定義了一個匿名函數。在匿名函數不能再使用this,因為這時的this是undefined。我們可以在匿名函數外部用一個 變量接收this,在匿名函數內部再使用這個變量。也就是this對象不能跨越兩層函數進行使用。
var lili = { name : "lili", age : 12, city : "beijing", address : "chaoyang", //方法的簡寫 getBirth(){ let that = this; let diff = function(year){ return year-that.age; } let now = new Date(); console.log(diff(2022)); return now.getFullYear() - this.age; } }為此,可以在第一次函數里用一個變量that接收this,在第二層函數里再使用that,從而避免this變量不能跨越兩層的障礙。
apply
函數通過apply方法,應用到對象上。
var xiaoli = { name : "xiaoli", age : 12, city : "beijing", address : "chaoyang", birth : getBirth } function getBirth(){ let now = new Date(); return now.getFullYear() - this.age; } xiaoli.birth(); getBirth.apply(xiaoli,[]);//應用到xiaoli對象上,參數數組為[] getBirth(); // Uncaught TypeError另一個與apply()類似的方法是call(),唯一區別是:
- apply()把參數打包成Array再傳入;
- call()把參數按順序傳入。
比如調用Math.max(3, 5, 4),分別用apply()和call()實現如下:
Math.max.apply(null, [3, 5, 4]); // 5 Math.max.call(null, 3, 5, 4); // 5
閉包
在JavaScript中,一個函數可以作為另外一個函數的參數進行傳遞。同樣地,一個函數也可以作為另外一個函數的返回值。例如:
function lazy_sum(...rest){ return function sum(){ let reduce = rest.reduce(function(s,x){ return s += x; },6); return reduce; } } var lazy_sum1 = lazy_sum(1,2,4,6); var lazy_sum2 = lazy_sum(1,2,4,6); lazy_sum1(); //調用sum()函數,返回13 lazy_sum2(); //調用sum()函數,返回13 typeof lazy_sum1(); // 返回function typeof lazy_sum2(); // 返回function lazy_sum1 == lazy_sum2 // false上述代碼所示,調用lazy_sum1和lazy_sum2函數,它們都返回一個sum()函數。雖然返回的名稱相同,但不同于數值的相等比較,它們并不相等。
看起來作用不大,只是可以延遲調用而已。再看下邊的例子:
//閉包可以在函數內部封裝一個變量 function wrap(initial){ initial = initial || 0; return function inc(){ initial += 1; return initial; } } var w = wrap(2); w(); //返回3 w(); //返回4 w(); //返回5上述代碼所示,wrap()是一個函數,它接收一個initial作為參數,這個函數的返回值也是一個函數,它是inc()。我們將inc()函數賦值給變量w, w函數調用一次返回3。接下來再調用一次,其內部的變量initial已經保留了3這個值,所以這時的返回值就是4。接下來的每次調用邏輯都是一致的。 這種在函數中封裝了一個變量的函數形成了閉包。這種在函數中封裝既封裝了變量,又封裝了方法的閉包,是不是有點像Java中的類呢?
閉包
ES6標準新增了一種新的函數:Arrow Function(箭頭函數)。為什么叫Arrow Function?因為它的定義用的就是一個箭頭:
x => x * x
使用規則
上面的箭頭函數相相當于一個匿名函數:
function (x) { return x * x; }箭頭函數簡化了函數定義。箭頭函數有兩種格式,一種像上面的,只包含一個表達式,連{ ... }和return都省略掉了。 還有一種可以包含多條語句,這時候就不能省略{ ... }和return:
x => { if (x>0){ return x; }else{ return -x; } }如果函數有多個參數,需使用括號,參數之間以逗號隔開
// 兩個參數: (x, y) => x * x + y * y // 無參數: () => 3.14 // 可變參數: (x, y, ...rest) => { var i, sum = x + y; for (i=0; i < rest.length; i++) { sum += rest[i]; } return sum; }如果要返回一個對象,就要注意,如果是單表達式,這么寫的話會報錯:
// SyntaxError: x => { foo: x }表達式的對象和函數體的{...}相沖突,需在對象外加上括號:
x => ({foo:x});前面章節指出了對象方法上,this使用的注意事項:
var lili = { name : "lili", age : 12, city : "beijing", address : "chaoyang", getBirth(){ let diff = function(year){ return year-this.age; // this指向window或undefined }; let now = new Date(); return now.getFullYear() - this.age; } }現在,箭頭函數完全修復了this的指向,this總是指向詞法作用域,也就是外層調用者obj:
var lili = { name : "lili", age : 12, city : "beijing", address : "chaoyang", getBirth(){ let diff = (year)=>year-this.age; // this指向lili let now = new Date(); return now.getFullYear() - this.age; } }文章同時發表在:碼農編程網歡迎訪問
本節重點:
- 什么是方法,方法的調用;
- 注意對象方法內部的this指向,避免指向錯誤;
- apply,call的使用和區別;
- 定義一個返回類型為函數的函數;
- 如何形成閉包,閉包的使用;
- 什么是箭頭函數,箭頭函數的使用;
- 箭頭函數修復了對象方法中的this指向。
關鍵詞:
