在ES6以前,咱們是這樣來作的javascript
function log( x, y){
y = y || 'world'
console.log(x, y)
}
log('hello') //hello world
log('hello', 'china') // hello china
log('hello','') // hello world
複製代碼
以上寫法會有一個問題,就是當咱們傳進去一個y值,可是其對應的布爾值爲false,例如 log('hello','')
,結果被修改成了默認值! 因此,爲了不這個問題,咱們替換以下語句java
if(typeof y === 'undefined'){
y = 'world'
}
複製代碼
在ES6裏面就簡單多了,能夠直接在參數設置默認值es6
function log(x, y = 'world') {
console.log(x ,y)
}
log('hello') //hello world
log('hello', 'china') //hello china
log('hello','') // hello
複製代碼
有一點須要注意 參數默認值不是傳值的,而是每次從新計算默認值表達式的值,參數默認值是「惰性求值的」ajax
let x = 99
function foo(p = x + 1){
console.log(p)
}
foo() //100
x = 100
foo() //101
//參數 p 的默認值是 x+1 每次調用函數 foo 都會從新計算 x+1 ,而不是默認 p 等於 100
複製代碼
注意:參數變量是默認聲明的,在函數體中,不能再用 let const 進行聲明,也 不容許有同名參數。數組
function foo({x, y = 5}){
console.log(x, y)
}
foo({}) // undefined 5
foo({x:1}) // 1, 5
foo({x: 1, y: 3}) // 1, 3
foo() //報錯
複製代碼
只有函數的參數是一個對象時,變量x y 纔會經過解構賦值生成。若是函數調用時,參數不是對象,變量x y 就不會生成,會報錯。ide
在前面文章 重學ES6 解構咱們他提到過函數參數的默認值,jQuery ajax的解構函數
這裏再用一個新的API寫一遍post
function fetch(url,{body = '', metthod = 'GET', headers = {}}){
console.log( method )
}
fetch('http://example.com', {}) // GET
fetch('http://example.com') // 報錯
複製代碼
這個寫法不能省略第二個參數~那就太很差了。。。因此,咱們要再結合函數的默認值,就能夠省略第二個參數了fetch
function fetch(url,{body = '', metthod = 'GET', headers = {}} = {}){
console.log( method )
}
fetch('http://example.com', {}) // GET
fetch('http://example.com') // GET
複製代碼
注意:在函數傳參解構中,只要傳入實際參數,那麼就拿傳入的實際參數進行解構,若是沒有傳入實際參數,且參數寫了默認值,函數參數獲得值是 undefined 時,被賦予默認值。ui
// demo 1
function m1 ({x = 0,y = 0} = {}){
return [x, y]
}
// demo 2
function m2 ({x, y} = {x: 0, y: 0}){
return [x, y]
}
//x y 都無值
m1({}) //[0, 0]
m2({}) // 沒有寫默認值,對實參進行解構,[undefined, undefined]
m1({z: 3}) // [0, 0]
m2({z: 3}) // [undefined, undefined]
複製代碼
一般,定義了默認值的參數應該是函數的尾參數。這樣能夠看出到底省略了哪些參數。
function f(x, y, z = 1){
return [x, y, z]
}
f() // [undefined, undefined, 1]
複製代碼
指定了默認值之後,函數的 length 屬性將返回沒有指定默認值的參數個數。指定了默認值後,length屬性將失真
(function (a) {}).length //1
(function (a = 5)).length // 0 (function (b ,c ,a = 5)).length // 2 複製代碼
length 屬性 含義是 「函數預期傳入的參 數個數」 ,某個參數指定默認值之後,函數傳入參數個數就不包含這個了,rest參數也不會計入length屬性
設置了參數的默認值後,函數進行初始化時,參數會造成一個單獨的做用域。等到初始化結束,這個做用域就會消失。這種語法行爲在不設置參數時是不會出現的。
var x= 1
function f(x, y = x){ //至關於 let x
console.log(y)
}
f(2)
複製代碼
// 若是此時全局 x 不存在,就報錯了
function f(y = x){ //至關於 let y = x
console.log(y)
}
f() // x is nit defined
複製代碼
var x = 1
function f(x = x){ //至關於 let x = x 暫時性死區
console.log(x)
}
f() // x is nit defined
複製代碼
若是參數是一個函數
let foo = 'ourter'
function bar (func = () => foo){ //在這裏,函數裏面的foo沒有定義,因此foo指向外層的 foo
let foo = 'inner'
console.log(func())
}
bar()
複製代碼
又一個例子
此例子,x共有3個,全局做用域下 foo函數參數做用域 還有 foo函數內部做用域,共三個,互不相同
var x =1
function foo(x, y = function() { x = 2}){
var x = 3
y()
console.log(x)
}
foo() // 3
x // 1
複製代碼
可是,若是去掉 foo 函數 內部的 var x = 3
的 var,那麼就剩下兩個不一樣的x,即:全局下的x 和 函數 foo 參數做用域下的x ,由於函數內部的 x 和 函數參數的x 已是同一個x
var x =1
function foo(x, y = function() { x = 2}){
x = 3
y()
console.log(x)
}
foo() // 2
x // 1
複製代碼
兩個例子都不會影響外部全局變量x的值。
參數默認值,能夠指定某一個參數不能省略,若是省略了,就跑出一個錯誤
function throwIfMissing(){
throw new Error('Missing parameter')
}
function foo(mustBeProvided = throwIfMissing()){
return mustBeProvided
}
foo()
複製代碼
es6 引入了 rest參數,(形式爲 ...變量名),用於獲取函數的多餘參數,也就不須要使用 arguments 參數對象了。 rest參數搭配的變量是一個數組,該變量將多餘的參數放入其中。
function add(...values){
let sum = 0
for(var val of values){
sum += val
}
return sum
}
add(1,2,3) // 6
複製代碼
以前,用arguments的寫法
// Array.prototype.slice.call(arguments) 將參數轉化爲數組
// array.sort
function sortNumbers() {
return Array.prototype.slice.call(arguments).sort()
}
// rest 參數的寫法
//...numbers 將numbers 轉化爲數組
const sortNumbers = (...numbers) => numbers.sort()
複製代碼
rest參數改寫 push
function push(array,...items){
items.forEach(function(item){
array.push(item)
})
}
var a = []
push(a,1,2,3)
複製代碼
rest 參數以後,不能再有其餘參數,因此,rest只能是最後一個參數。並且,函數的length,不包括rest參數。