1.函數(shù)的默認(rèn)值
- 以前給函數(shù)的參數(shù)設(shè)置默認(rèn)值
function fn(x,y){
y=y||'world'
}
fn('Hello') // Hello World
fn('Hello', 'China') // Hello China
fn('Hello', '') // Hello World
- Es6的寫法
function fn(x=0,y=10){
return x+y
}
fn() // 0
fn(10) // 20
fn(10,20) // 30
- 不可以使用let或者const重新聲明參數(shù)
function fn(x){
let x=10;
}
//error
上面代碼中俘侠,參數(shù)變量x是默認(rèn)聲明的囚灼,在函數(shù)體中坷澡,不能用let或const再次聲明,否則會報錯差牛。
- 使用函數(shù)參數(shù)默認(rèn)值不可以有相同的參數(shù)
function fn(x,x,y){
}
上邊的代碼不會報錯,因為并沒有設(shè)置默認(rèn)值,但是第二個的x的值會覆蓋第一個x
function fn(x=5,x,y=10){
//error
}
-
函數(shù)參數(shù)默認(rèn)值與解構(gòu)賦值結(jié)合使用
- 參數(shù)默認(rèn)值可以與解構(gòu)賦值的默認(rèn)值爬立,結(jié)合起來使用。
function fn({a,y:5}){ console.log(a,y) } fn() //error fn({}) // undefined,5 fn({x:1}) // 1,5 fn({x:1,y:5}) // 1,6
為啦防止上邊的第一種錯誤的情況,可以這么寫:
function fn({x=1,y}={}){ console.log(x,y) } fn() //x:1,y:undefined
仔細(xì)比較這個代碼和上邊的代碼有什么不同,這里的fn執(zhí)行的時候沒有傳入?yún)?shù),而上邊的也沒有傳入?yún)?shù),為什么這里的能正常執(zhí)行呢,是應(yīng)為,上邊的代碼沒有在fn()執(zhí)行的時候添加和參數(shù)默認(rèn)值解構(gòu)的對象,而這里的是在參數(shù)里邊已經(jīng)做啦解構(gòu)賦值,只不過是一個空對象而已.
-
函數(shù)的length
- 函數(shù)的length屬性万哪,將返回沒有指定默認(rèn)值的參數(shù)個數(shù)侠驯。也就是說,指定了默認(rèn)值后奕巍,length屬性將失真
function fn(x){ } console.log(fn.length) // 1 function fn1(x=1){ } console.log(fn.length) //0
- 函數(shù)的length屬性万哪,將返回沒有指定默認(rèn)值的參數(shù)個數(shù)侠驯。也就是說,指定了默認(rèn)值后奕巍,length屬性將失真
-
作用域
- 一旦參數(shù)設(shè)置啦默認(rèn)值,函數(shù)在聲明初始化時會形成一個單獨的域,等到初始化結(jié)束,域消失,參數(shù)沒有設(shè)置默認(rèn)值時,是不會形成這個域的
let x= 10;
function fn (x,y=x){
console.log(y)
}
fn(1) // 1
上面代碼中吟策,參數(shù)y的默認(rèn)值等于變量x。調(diào)用函數(shù)f時的止,參數(shù)形成一個單獨的作用域檩坚。在這個作用域里面,默認(rèn)值變量x指向第一個參數(shù)x,而不是全局變量x匾委,所以輸出是2拖叙。
let x = 1;
function fn(y = x) {
let x = 2;
console.log(y);
}
fn() // 1
在上邊的代碼中,雖然函數(shù)里有變量x,但是這個作用域是在函數(shù)聲明初始化的時候形成的,所以里邊里邊的x指向全局的x.
function f(y = x) {
let x = 2;
console.log(y);
}
f() // ReferenceError: x is not defined
報錯是因為在全局中沒有找到全局變量x
var x = 1;
function foo(x = x) {
// ...
}
foo() // ReferenceError: x is not defined
上面代碼中,參數(shù)x = x形成一個單獨作用域赂乐。實際執(zhí)行的是let x = x薯鳍,由于暫時性死區(qū)的原因,這行代碼會報錯”x 未定義“挨措。
2.rest參數(shù)
ES6 引入 rest 參數(shù)(形式為...變量名)挖滤,用于獲取函數(shù)的多余參數(shù),這樣就不需要使用arguments對象了浅役。rest 參數(shù)搭配的變量是一個數(shù)組斩松,該變量將多余的參數(shù)放入數(shù)組中。
function add(...values) {
let sum = 0;
for(var i = 0;i < values.length;i++){
num+=values[i]
}
return sum;
}
add(2, 5, 3) // 10
- rest必須是最后一個參數(shù),否則會報錯
function fn(x,...values,y){
}
//error
- 函數(shù)的length屬性觉既,不包括 rest 參數(shù)惧盹。
function fn(x,y=2,...values){
}
console.log(fn.length)
3.嚴(yán)格模式
從 ES5 開始,函數(shù)內(nèi)部可以設(shè)定為嚴(yán)格模式 , ES2016 做了一點修改奋救,規(guī)定只要函數(shù)參數(shù)使用了默認(rèn)值岭参、解構(gòu)賦值、或者擴(kuò)展運算符尝艘,那么函數(shù)內(nèi)部就不能顯式設(shè)定為嚴(yán)格模式演侯,否則會報錯。
下邊是報錯的一些例子:
function a(a, b = a) {
'use strict';
// code
}
// 使用啦參數(shù)設(shè)置默認(rèn)值報錯
const a= function ({a, b}) {
'use strict';
// code
};
// 使用啦解構(gòu)賦值報錯
const a= (...a) => {
'use strict';
// code
};
// 報錯
function doSomething(value = 070) {
'use strict';
return value;
}
上面代碼中背亥,參數(shù)value的默認(rèn)值是八進(jìn)制數(shù)070秒际,但是嚴(yán)格模式下不能用前綴0表示八進(jìn)制,所以應(yīng)該報錯狡汉。但是實際上娄徊,JavaScript 引擎會先成功執(zhí)行value = 070,然后進(jìn)入函數(shù)體內(nèi)部盾戴,發(fā)現(xiàn)需要用嚴(yán)格模式執(zhí)行寄锐,這時才會報錯。
解決辦法
1.設(shè)置全局的嚴(yán)格模式
'use strict';
function a(a, b = a) {
// code
}
2.套在一個無參數(shù)的自執(zhí)行函數(shù)里
let a =(function(){
'use strict';
retuen function (x=2,y){
console.log(x,y)
}
}())
4.name 屬性
- 函數(shù)的name屬性尖啡,返回該函數(shù)的函數(shù)名橄仆。
function foo() {}
foo.name // "foo"
- ES6 對這個屬性的行為做出了一些修改。如果將一個匿名函數(shù)賦值給一個變量衅斩,ES5 的name屬性盆顾,會返回空字符串,而 ES6 的name屬性會返回實際的函數(shù)名畏梆。
var f = function () {};
// ES5
f.name // ""
// ES6
f.name // "f"
- 如果將一個具名函數(shù)賦值給一個變量您宪,則 ES5 和 ES6 的name屬性都返回這個具名函數(shù)原本的名字奈懒。
var a = function fn(){
};
//Es5
console.log(a.name) // fn
//Es6
console.log(a.name) // fn
- Function構(gòu)造函數(shù)返回的函數(shù)實例,name屬性的值為anonymous宪巨。
(new Function).name // "anonymous"
5.Es6允許使用“箭頭”(=>)定義函數(shù)磷杏。
- 基本用法
var f = v => 1;
f() //1
// v 函數(shù)的形參, 1 函數(shù)的實參和返回值
- 如果有多個參數(shù),使用一個圓括號代表參數(shù)部分
var f = () => 5;
// 等同于
var f = function () { return 5 };
var sum = (num1, num2) => num1 + num2;
// 等同于
var sum = function(num1, num2) {
return num1 + num2;
};
- 如果要返回一個對象必須在對象外邊加圓括號
//報錯
let obj= id => { id: id, name: "Temp" };
//不報錯
let obj= id => ({ id: id, name: "Temp" });
- 與解構(gòu)賦值的結(jié)合使用
var f = ({name,age}) => name+' '+age
f({name:'suo',age:28}) //"suo 20"
箭頭函數(shù)使用注意事項
(1)函數(shù)體內(nèi)的this對象,就是定義時所在的對象揖铜,而不是使用時所在的對象茴丰。
(2)不可以當(dāng)作構(gòu)造函數(shù),也就是說天吓,不可以使用new命令贿肩,否則會拋出一個錯誤。
(3)不可以使用arguments對象龄寞,該對象在函數(shù)體內(nèi)不存在汰规。如果要用,可以用 rest 參數(shù)代替物邑。
(4)不可以使用yield命令溜哮,因此箭頭函數(shù)不能用作 Generator 函數(shù)。
function foo() {
setTimeout(() => {
console.log('id:', this.id);
}, 100);
}
var id = 21;
foo.call({ id: 42 });
// id: 42
上面代碼中色解,setTimeout的參數(shù)是一個箭頭函數(shù)茂嗓,這個箭頭函數(shù)的定義生效是在foo函數(shù)生成時,而它的真正執(zhí)行要等到 100 毫秒后科阎。如果是普通函數(shù)述吸,執(zhí)行時this應(yīng)該指向全局對象window,這時應(yīng)該輸出21锣笨。但是蝌矛,箭頭函數(shù)導(dǎo)致this總是指向函數(shù)定義生效時所在的對象(本例是{id: 42}),所以輸出的是42错英。
箭頭函數(shù)可以讓setTimeout里面的this入撒,綁定定義時所在的作用域,而不是指向運行時所在的作用域椭岩。下面是另一個例子茅逮。
6.雙冒號運算符
- 函數(shù)綁定運算符是并排的兩個冒號(::),雙冒號左邊是一個對象判哥,右邊是一個函數(shù)氮唯。該運算符會自動將左邊的對象,作為上下文環(huán)境(即this對象)姨伟,綁定到右邊的函數(shù)上面。
foo::bar;
// 等同于
bar.bind(foo);
foo::bar(...arguments);
// 等同于
bar.apply(foo, arguments);
- 如果雙冒號左邊為空豆励,右邊是一個對象的方法夺荒,則等于將該方法綁定在該對象上面瞒渠。
var method = obj::obj.foo;
// 等同于
var method = ::obj.foo;
let log = ::console.log;
// 等同于
var log = console.log.bind(console);
7尾調(diào)用
-
什么是尾調(diào)用
尾調(diào)用是函數(shù)式編程的一個重要概念,本身非常簡單技扼,一句話就能說清楚伍玖,就是指某個函數(shù)的最后一步是調(diào)用另一個函數(shù)。
調(diào)用之后再操作的都不算尾調(diào)用
尾調(diào)用不一定出現(xiàn)在函數(shù)尾部,只要是最后一步操作就好
// 情況一 function f(x){ let y = g(x); return y; } // 情況二 function f(x){ return g(x) + 1; } // 情況三 function f(x){ g(x); }
情況一 : 調(diào)用之后有操作;
情況二 : 調(diào)用之后有操作;
情況三 : function(){g(x) return undefined;};