ES6學(xué)習(xí)筆記之函數(shù)擴(kuò)展

一. 函數(shù)參數(shù)的默認(rèn)值

ES6 允許為函數(shù)的參數(shù)設(shè)置默認(rèn)值驳概,即直接寫(xiě)在參數(shù)定義的后面。

function log(x , y = 'world'){
   console.log(x, y);
}

log('hello'); //  Hello World
log('Hello', 'China') // Hello China
log('Hello', '') // Hello World

function Point(x = 0, y = 0){
    this.x = x;
    this.y = y;
}
var p = new Point();
p // {x : 0, y: 0}

Tips:參數(shù)變量是默認(rèn)聲明的,所以不能用let或const再次聲明。

//下面代碼中麻捻,參數(shù)變量x是默認(rèn)聲明的,在函數(shù)體中,不能用let或const再次聲明,否則會(huì)報(bào)錯(cuò)赦抖。
function foo(x = 5){
    let x = 1;  //error
    const x =2; //error
 }

參數(shù)默認(rèn)值不是傳值的,而是每次都重新計(jì)算默認(rèn)值表達(dá)式的值。也就是說(shuō)锻拘,參數(shù)默認(rèn)值是惰性求值的油吭。

let x = 99;
function foo(p = x+1){
    console.log(p);
}

foo(); // 100
x = 100;
foo(); // 101

Tips:參數(shù)p的默認(rèn)值是x + 1,每次調(diào)用函數(shù)foo,都會(huì)重新計(jì)算x + 1署拟,而不是默認(rèn)p等于 100婉宰。

二 .與解構(gòu)賦值默認(rèn)值結(jié)合使用

function foo({x , y = 5}){
    console.log(x, y);
}

foo({}); // undefined 5
foo({x : 1}); //1, 5
foo({x : 1, y : 2}); // 1 2
foo() // TypeError: Cannot read property 'x' of undefined

Tips:上面代碼只使用了對(duì)象的解構(gòu)賦值默認(rèn)值,沒(méi)有使用函數(shù)參數(shù)的默認(rèn)值推穷。只有當(dāng)函數(shù)foo的參數(shù)是一個(gè)對(duì)象時(shí)心包,變量x和y才會(huì)通過(guò)解構(gòu)賦值生成。如果函數(shù)foo調(diào)用時(shí)沒(méi)提供參數(shù)馒铃,變量x和y就不會(huì)生成蟹腾,從而報(bào)錯(cuò)。通過(guò)提供函數(shù)參數(shù)的默認(rèn)值区宇,就可以避免這種情況娃殖。

//下面代碼指定,如果沒(méi)有提供參數(shù)议谷,函數(shù)foo的參數(shù)默認(rèn)為一個(gè)空對(duì)象炉爆。
function foo({x, y = 5} = {}){
    console.log(x, y);
}

foo(); //undefined 5

  function fetch(url, { body = '', method = 'Get', headers = {}}){
  console.log(method);
}

fetch('http://example.com', {});
//'GET'

fetch('http://example.com');
//報(bào)錯(cuò)

Tips: 上面代碼中,如果函數(shù)fetch的第二個(gè)參數(shù)是一個(gè)對(duì)象卧晓,就可以為它的三個(gè)屬性設(shè)置默認(rèn)值芬首。這種寫(xiě)法不能省略第二個(gè)參數(shù),如果結(jié)合函數(shù)參數(shù)的默認(rèn)值逼裆,就可以省略第二個(gè)參數(shù)郁稍。這時(shí),就出現(xiàn)了雙重默認(rèn)值胜宇。

function fetch(url, {method = 'GET'} = {}){
  console.log(method);
}

fetch('http://example.com');
//'GET'

//寫(xiě)法一
function m1({x = 0, y = 0} = {}){
    return [x, y];
 }

 //寫(xiě)法二
 function m2({x , y} = { x : 0, y : 0}){
       return [x, y]
  }

Tips:上面兩種寫(xiě)法都對(duì)函數(shù)的參數(shù)設(shè)定了默認(rèn)值艺晴,區(qū)別是寫(xiě)法一函數(shù)參數(shù)的默認(rèn)值是空對(duì)象昼钻,但是設(shè)置了對(duì)象解構(gòu)賦值的默認(rèn)值;寫(xiě)法二函數(shù)參數(shù)的默認(rèn)值是一個(gè)有具體屬性的對(duì)象封寞,但是沒(méi)有設(shè)置對(duì)象解構(gòu)賦值的默認(rèn)值然评。

//函數(shù)沒(méi)有參數(shù)
m1() // [0, 0]
m2() // [0, 0]

//x和y都有值的情況
m1({x : 3, y : 8}) // [3, 8]
m2({x: 3,  y : 8}) // [3, 8]

//x有值,y都無(wú)值的情況
m1({x : 3}) // [3, 0]
m2({x : 3}) // [3, undefined]

//x和y都無(wú)值
m1({}) // [0, 0]
m2({}) //[undefined, undefined]

m1({z : 3}) // [0, 0]
m2({z : 3}) // [undefined, undefined]

三. 參數(shù)默認(rèn)值的位置

如果非尾部的參數(shù)設(shè)置默認(rèn)值,實(shí)際上這個(gè)參數(shù)是沒(méi)法省略的狈究。

//例一
function f(x = 1, y){
  return [x, y];
}

f() // [1, undefined]
f(2) // [2, undefined]
f(, 1)// 報(bào)錯(cuò)
f(undefined, 1)// [1, 1]

//例二
function f(x, y = 5, z){
    return [x, y, z];
}

f() // [undefined, 5, undefined]
f(1) // [1, 5, undefined]
f(1, ,2) // 報(bào)錯(cuò)
f(1, undefined, 2) //[1, 5, 2]

Tips:上面代碼中碗淌,有默認(rèn)值的參數(shù)都不是尾參數(shù)。

//如果傳入undefined抖锥,將觸發(fā)該參數(shù)等于默認(rèn)值亿眠,null則沒(méi)有這個(gè)效果。
 function foo(x = 5, y =6){
    console.log(x, y);
 }

foo(undefined, null)
//5 null

Tips: 上面代碼中磅废,x參數(shù)對(duì)應(yīng)undefined纳像,結(jié)果觸發(fā)了默認(rèn)值,y參數(shù)等于null拯勉,就沒(méi)有觸發(fā)默認(rèn)值竟趾。

四. 函數(shù)的length屬性

指定了默認(rèn)值以后,函數(shù)的length屬性宫峦,將返回沒(méi)有指定默認(rèn)值的參數(shù)個(gè)數(shù)岔帽。也就是說(shuō),指定了默認(rèn)值后导绷,length屬性將失真犀勒。

(function (a) {}).length // 1
(function (a = 5) {}).length // 0
(function (a, b, c = 5) {}).length // 2

五. 作用域

一旦設(shè)置了參數(shù)的默認(rèn)值,函數(shù)進(jìn)行聲明初始化時(shí)妥曲,參數(shù)會(huì)形成一個(gè)單獨(dú)的作用域(context)贾费。等到初始化結(jié)束,這個(gè)作用域就會(huì)消失檐盟。這種語(yǔ)法行為铸本,在不設(shè)置參數(shù)默認(rèn)值時(shí),是不會(huì)出現(xiàn)的遵堵。

var  x = 1;
function f(x, y = x){
    console.log(y);
}
f(2);  // 2

Tips:上面代碼中箱玷,參數(shù)y的默認(rèn)值等于變量x。調(diào)用函數(shù)f時(shí)陌宿,參數(shù)形成一個(gè)單獨(dú)的作用域锡足。在這個(gè)作用域里面,默認(rèn)值變量x指向第一個(gè)參數(shù)x壳坪,而不是全局變量x舶得,所以輸出是2。

let x = 1;
function f(y = x){
  let x = 2;
  console.log(y);
}
f() // 1

*Tips: 上面代碼中爽蝴,函數(shù)f調(diào)用時(shí)沐批,參數(shù)y = x形成一個(gè)單獨(dú)的作用域纫骑。這個(gè)作用域里面,變量x本身沒(méi)有定義九孩,所以指向外層的全局變量x先馆。函數(shù)調(diào)用時(shí),函數(shù)體內(nèi)部的局部變量x影響不到默認(rèn)值變量x躺彬。*

//如果此時(shí)煤墙,全局變量x不存在,就會(huì)報(bào)錯(cuò)宪拥。
function f(y = x){
  let x = 2;
  console.log(y);
 }

 f() // ReferenceError: x is not defined

//這樣寫(xiě)仿野,也會(huì)報(bào)錯(cuò)。
function foo(x = x){
    // ...
}
foo() // ReferenceError: x is not defined

*Tips:上面代碼中她君,參數(shù)x = x形成一個(gè)單獨(dú)作用域脚作。實(shí)際執(zhí)行的是let x = x,由于暫時(shí)性死區(qū)的原因缔刹,這行代碼會(huì)報(bào)錯(cuò)”x 未定義“球涛。*

如果參數(shù)的默認(rèn)值是一個(gè)函數(shù),該函數(shù)的作用域也遵守這個(gè)規(guī)則桨螺。

let foo = 'outer';
function bar(func = () => foo){
    let foo =  'inner';
    console.log(func());
}
bar(); // outer

 function bar(func = () => foo){
      let foo = 'inner';
      console.log(func());
 }
 bar() //ReferenceError: foo is not defined

六. rest參數(shù)

ES6 引入 rest 參數(shù)(形式為...變量名)宾符,用于獲取函數(shù)的多余參數(shù)酿秸,這樣就不需要使用arguments對(duì)象了灭翔。rest 參數(shù)搭配的變量是一個(gè)數(shù)組,該變量將多余的參數(shù)放入數(shù)組中辣苏。

function add(...values){
let sum = 0;
for(var val of values){
sum += val
}
return sum;
}

add(2, 5, 3);

rest 參數(shù)就是一個(gè)真正的數(shù)組肝箱,數(shù)組特有的方法都可以使用。

function push(array, ...items){
    items.forEach(function(item){
        array.push(item);
        console.log(item);
  });
}

var a =[];
push(a, 1, 2, 3);

注意稀蟋,rest 參數(shù)之后不能再有其他參數(shù)(即只能是最后一個(gè)參數(shù))煌张,否則會(huì)報(bào)錯(cuò)。

//報(bào)錯(cuò)
function(a, ...b, c){
    //...
}

函數(shù)的length屬性退客,不包括 rest 參數(shù)骏融。

(function(a) {}).length  // 1
(function(...a) {}).length  // 0
(function(a, ...b) {}).length  // 1

七. name屬性

函數(shù)的name屬性,返回該函數(shù)的函數(shù)名萌狂。

*Tips:如果將一個(gè)匿名函數(shù)賦值給一個(gè)變量档玻,ES5 的name屬性,會(huì)返回空字符串茫藏,而 ES6 的name屬性會(huì)返回實(shí)際的函數(shù)名误趴。 *

var f = function() {};

//ES5
f.name // ''''

//ES6
f.name // "f"

八 .箭頭函數(shù)

ES6 允許使用“箭頭”(=>)定義函數(shù)。

var f = v => v;

等同于

var f = function(v){
     return v;
  }

如果箭頭函數(shù)不需要參數(shù)或需要多個(gè)參數(shù)务傲,就使用一個(gè)圓括號(hào)代表參數(shù)部分凉当。

 var f = () => 5;
 var f = function(){return 5};
 var sum = (num1, num2) => num1 + num2;
  var sum = function(num1, num2){
      return num1 + num2;
  };

如果箭頭函數(shù)的代碼塊部分多于一條語(yǔ)句枣申,就要使用大括號(hào)將它們括起來(lái),并且使用return語(yǔ)句返回看杭。

var sum = (num1, num2) => { return num1 + num2}

由于大括號(hào)被解釋為代碼塊忠藤,所以如果箭頭函數(shù)直接返回一個(gè)對(duì)象,必須在對(duì)象外面加上括號(hào)泊窘,否則會(huì)報(bào)錯(cuò)熄驼。

//報(bào)錯(cuò)
let getTempItem = id => {id : id, name : "Temp"}

//不報(bào)錯(cuò)
let getTempItem = id => ({id : id, name : "Temp"})

箭頭函數(shù)可以與變量解構(gòu)結(jié)合使用。

const full = ({first, last}) => first + ' ' + last;

等同于

function full(person){
    return person.first + ' '+person.last;
}

rest 參數(shù)與箭頭函數(shù)結(jié)合

const numbers = (...nums) => nums;
numbers(1,2,3,4,5);
//[1, 2, 3, 4, 5]
const headAndTail = (head, ...tail) => [head, tail];

headAndTail(1, 2, 3, 4, 5)
[1, [2, 3, 4, 5]]

注意:
1.函數(shù)體內(nèi)的this對(duì)象,就是定義時(shí)所在的對(duì)象,而不是使用時(shí)所在對(duì)象
2.不可以當(dāng)做構(gòu)造函數(shù),不能使用new命令,否則拋出錯(cuò)誤
3.不可以使用arguments對(duì)象,用 rest參數(shù)代替
4.不能用yield命令

//在箭頭函數(shù)中,this對(duì)象的指向是可變的
function foo(){
    setTimeout(() => {
    console.log('id', this.id);
    }, 100);
}

var id = 21;
foo.call({id : 42});
//id :42

Tips:上面代碼中烘豹,setTimeout的參數(shù)是一個(gè)箭頭函數(shù)瓜贾,這個(gè)箭頭函數(shù)的定義生效是在foo函數(shù)生成時(shí),而它的真正執(zhí)行要等到100毫秒后携悯。如果是普通函數(shù)祭芦,執(zhí)行時(shí)this應(yīng)該指向全局對(duì)象window,這時(shí)應(yīng)該輸出21憔鬼。但是龟劲,箭頭函數(shù)導(dǎo)致this總是指向函數(shù)定義生效時(shí)所在的對(duì)象(本例是{id: 42}),所以輸出的是42轴或。

function Timer(){
    this.s1 = 0;
    this.s2 = 0;
    setInterval(() => this.s1++, 1000);
    setInterval(function(){
          this.s2++;
    }, 1000);

 var timer = new Timer();
 setTimeout(() => console.log('s1: ', timer.s1), 3100);
  //s1 : 3

 setTimeout(() => console.log('s2: ', timer.s2), 3100);
  //s2 : 0

*Tips:Timer函數(shù)內(nèi)部設(shè)置了兩個(gè)定時(shí)器昌跌,分別使用了箭頭函數(shù)和普通函數(shù)。前者的this綁定定義時(shí)所在的作用域(即Timer函數(shù))照雁,后者的this指向運(yùn)行時(shí)所在的作用域(即全局對(duì)象)蚕愤。所以,3100毫秒之后饺蚊,timer.s1被更新了3次萍诱,而timer.s2一次都沒(méi)更新。 *

九.尾調(diào)用優(yōu)化

尾調(diào)用(Tail Call)是函數(shù)式編程的一個(gè)重要概念污呼,本身非常簡(jiǎn)單裕坊,一句話就能說(shuō)清楚,就是指某個(gè)函數(shù)的最后一步是調(diào)用另一個(gè)函數(shù)燕酷。

function f(x){
    return g(x);
}

//以下三種情況籍凝,都不屬于尾調(diào)用。
//情況一
function f(x){
    let y = g(x);
    return y;
}

//情況二
function f(x){
   return g(x) + 1;
}

情況三
function f(x){
    g(x);
}

Tips:情況一是調(diào)用函數(shù)g之后苗缩,還有賦值操作饵蒂,所以不屬于尾調(diào)用,即使語(yǔ)義完全一樣挤渐。情況二也屬于調(diào)用后還有操作苹享,即使寫(xiě)在一行內(nèi)

尾調(diào)用不一定出現(xiàn)在函數(shù)尾部,只要是最后一步操作即可。

//函數(shù)m和n都屬于尾調(diào)用
function f(x) {
   if(x > 0){
     return m(x);
   }
  return n(x);
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末得问,一起剝皮案震驚了整個(gè)濱河市囤攀,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌宫纬,老刑警劉巖焚挠,帶你破解...
    沈念sama閱讀 211,639評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異漓骚,居然都是意外死亡蝌衔,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)蝌蹂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)噩斟,“玉大人,你說(shuō)我怎么就攤上這事孤个√暝剩” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,221評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵齐鲤,是天一觀的道長(zhǎng)斥废。 經(jīng)常有香客問(wèn)我,道長(zhǎng)给郊,這世上最難降的妖魔是什么牡肉? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,474評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮淆九,結(jié)果婚禮上统锤,老公的妹妹穿的比我還像新娘。我一直安慰自己吩屹,他們只是感情好跪另,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,570評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布拧抖。 她就那樣靜靜地躺著煤搜,像睡著了一般。 火紅的嫁衣襯著肌膚如雪唧席。 梳的紋絲不亂的頭發(fā)上擦盾,一...
    開(kāi)封第一講書(shū)人閱讀 49,816評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音淌哟,去河邊找鬼迹卢。 笑死,一個(gè)胖子當(dāng)著我的面吹牛徒仓,可吹牛的內(nèi)容都是我干的腐碱。 我是一名探鬼主播,決...
    沈念sama閱讀 38,957評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼症见!你這毒婦竟也來(lái)了喂走?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,718評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤谋作,失蹤者是張志新(化名)和其女友劉穎芋肠,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體遵蚜,經(jīng)...
    沈念sama閱讀 44,176評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡帖池,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,511評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了吭净。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片睡汹。...
    茶點(diǎn)故事閱讀 38,646評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖寂殉,靈堂內(nèi)的尸體忽然破棺而出帮孔,到底是詐尸還是另有隱情,我是刑警寧澤不撑,帶...
    沈念sama閱讀 34,322評(píng)論 4 330
  • 正文 年R本政府宣布文兢,位于F島的核電站,受9級(jí)特大地震影響焕檬,放射性物質(zhì)發(fā)生泄漏姆坚。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,934評(píng)論 3 313
  • 文/蒙蒙 一实愚、第九天 我趴在偏房一處隱蔽的房頂上張望兼呵。 院中可真熱鬧,春花似錦腊敲、人聲如沸击喂。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,755評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)懂昂。三九已至,卻和暖如春没宾,著一層夾襖步出監(jiān)牢的瞬間凌彬,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,987評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工循衰, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留铲敛,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,358評(píng)論 2 360
  • 正文 我出身青樓会钝,卻偏偏與公主長(zhǎng)得像伐蒋,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,514評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • 函數(shù)參數(shù)的默認(rèn)值 基本用法 在ES6之前先鱼,不能直接為函數(shù)的參數(shù)指定默認(rèn)值徒蟆,只能采用變通的方法。 上面代碼檢查函數(shù)l...
    呼呼哥閱讀 3,363評(píng)論 0 1
  • 第一章 塊級(jí)作用域綁定 let 和 const 都是不存在提升,聲明的都是塊級(jí)標(biāo)識(shí)符都禁止重聲明 每個(gè)const聲...
    NowhereToRun閱讀 1,578評(píng)論 0 2
  • 1.函數(shù)參數(shù)的默認(rèn)值 (1).基本用法 在ES6之前闹蒜,不能直接為函數(shù)的參數(shù)指定默認(rèn)值寺枉,只能采用變通的方法。
    趙然228閱讀 684評(píng)論 0 0
  • 三绷落,字符串?dāng)U展 3.1 Unicode表示法 ES6 做出了改進(jìn)姥闪,只要將碼點(diǎn)放入大括號(hào),就能正確解讀該字符砌烁。有了這...
    eastbaby閱讀 1,518評(píng)論 0 8
  • 最近很多人都在問(wèn)老師函喉,自己的皮膚變得很嬌氣避归,覺(jué)得緊繃不舒服,是不是過(guò)敏了管呵?為此老師給大家普及一下肌膚敏感的特征梳毙,原...
    王斌老師閱讀 578評(píng)論 0 1