函数的扩展
函数参数的默认值
ES6 允许给函数参数赋值初始值
基本用法
通过给形参赋初始值,具有默认值的参数, 一般位置要靠后(潜规则),只有当传入的参数的值为undefined时才会使用默认值
function log(x, y = "World") { console.log(x, y) }
log("Hello") // Hello World log("Hello", "China") // Hello China log("Hello", "") // Hello使用参数默认值时,函数不能有同名参数
// 不报错,但是先传入的同名参数会被后面覆盖 function fun(x, x, y) { // ... }
// 报错 function fun(x, x, y = 1) { // ... } // SyntaxError: Duplicate parameter name not allowed in this context与解构赋值默认值结合使用
参数默认值可以与解构赋值的默认值,结合起来使用
function fun({ x, y = 5 }) { console.log(x, y); }
fun({}); // undefined 5 fun({ x: 1 }); // 1 5 fun({ x: 1, y: 2 }); // 1 2 fun(); // TypeError: Cannot read property 'x' of undefined上面代码只使用了对象的解构赋值默认值,没有使用函数参数的默认值
只有当函数fun的参数是一个对象时,变量x和y才会通过解构赋值生成。如果函数fun调用时没提供参数,变量x和y就不会生成,从而报错
function fun({ x, y = 5 } = {}) { console.log(x, y) }
fun() // undefined 5上面代码指定,如果没有提供参数,函数fun的参数默认为一个空对象
例:
function fetch(url, { body = "", method = "GET", headers = {} }) { console.log(method); }
fetch("https://example.com", {}); // "GET"
fetch("https://example.com"); // 报错上面代码中,如果函数fetch的第二个参数是一个对象,就可以为它的三个属性设置默认值。
这种写法不能省略第二个参数,如果结合函数参数的默认值,就可以省略第二个参数。这时,就出现了双重默认值。
function fetch(url, { body = "", method = "GET", headers = {} } = {}) { console.log(method); }
fetch("https://example.com"); // "GET"上面代码中,函数fetch没有第二个参数时,函数参数的默认值就会生效,然后才是解构赋值的默认值生效,变量method才会取到默认值GET
问:以下代码有何区别
// 写法一 function m1({ x = 0, y = 0 } = {}) { return [x, y] }
// 写法二 function m2({ x, y } = { x: 0, y: 0 }) { return [x, y] }上面两种写法都对函数的参数设定了默认值,区别是写法一函数参数的默认值是空对象,但是设置了对象解构赋值的默认值 写法二函数参数的默认值是一个有具体属性的对象,但是没有设置对象解构赋值的默认值
// 函数没有参数的情况 m1() // [0, 0] m2() // [0, 0]
// x 和 y 都有值的情况 m1({ x: 3, y: 8 }) // [3, 8] m2({ x: 3, y: 8 }) // [3, 8]
// x 有值,y 无值的情况 m1({ x: 3 }) // [3, 0] m2({ x: 3 }) // [3, undefined]
// x 和 y 都无值的情况 m1({}) // [0, 0]; m2({}) // [undefined, undefined]函数的 length 属性
指定了默认值以后,函数的length属性,将返回没有指定默认值的参数个数
(function (a) {}).length // 1 (function (a = 5) {}).length // 0 (function (a, b, c = 5) {}).length // 2因为length属性的含义是,该函数预期传入的参数个数。某个参数指定默认值以后,预期传入的参数个数就不包括这个参数了
如果设置了默认值的参数不是尾参数,那么length属性也不再计入后面的参数了
(function (a, b = 1, c) {}).length // 1作用域
一旦设置了参数的默认值,函数进行声明初始化时,参数会形成一个单独的作用域(context)。等到初始化结束,这个作用域就会消失
let x = 1
function fun(x, y = x) { console.log(y) }
fun(2) // 2上面代码中,参数y的默认值等于x,调用fun()时,此时形成了封闭的作用域,默认值x指向第一个参数x,也就是2
let x = 1
function fun(y = x) { let x = 3 console.log(y) }
fun() // 1上面代码中,函数f调用时,参数y = x形成一个单独的作用域。这个作用域里面,变量x本身没有定义,所以指向外层的全局变量x。函数调用时,函数体内部的局部变量x影响不到默认值变量x。
如果此时,全局变量x不存在,就会报错
rest 参数
ES6 引入 rest 参数(形式为…变量名),用于获取函数的多余参数,这样就不需要使用arguments对象了。
rest 参数搭配的变量是一个数组,该变量将多余的参数放入数组中
// ES5 获取实参的方式 function fun(){ console.log(arguments) } fun('a','b','c')
// rest 参数 function fun(x, ...args){ console.log(args);// filter some every map } fun('a','b','c') // b crest 参数必须要放到参数最后,否则会报错
function fun(a, ...args, b) {} // SyntaxError: Rest parameter must be last formal parameter函数的length属性,不包括 rest 参数
(function (...args) {}).length // 0 (function (a, b, ...args) {}).length // 2箭头函数
ES6 允许使用“箭头”(=>)定义函数
基本用法
let fun = function (a) { return a * a }
// 等价于 let fun = (a) => { return a * a }如果箭头函数当形参有且只有一个的时候,可以省略()
当代码体只有一条语句的时候, 可以省略{},但此时 return 必须省略,return 返回该条语句执行结果
let fun = (a) => { return a * a }
//等价于 let fun = a => a * a由于大括号被解释为代码块,所以如果箭头函数直接返回一个对象,必须在对象外面加上括号,否则会报错
// 报错 let getTempItem = id => { id: id, name: "Temp" }
// 不报错 let getTempItem = id => ({ id: id, name: "Temp" })注意事项
-
this是静态的.this始终指向函数声明时所在作用域下的this的值function getName() {console.log(this.name)}let getName2 = () => {console.log(this.name)}window.name = "window"const obj = {name: "obj"}// 直接调用getName() //windowgetName2() //window// call 方法调用getName.call(obj) //objgetName2.call(obj) //window上面代码中都是定义在全局作用域中,而箭头函数
getName2()this始终指向全局作用域,不随call()的调用而改变如在回调函数中使用 let div = document.getElementById(“test-div”) div.onclick = function () { // setTimeout(function () { // console.log(this) // 此时this是window // this.style.background = “red” // },2000)
setTimeout(() => {// 此时this是外部作用域divthis.style.background = "red"}, 2000)} -
不能作为构造实例化对象,也就是说,不可以使用new命令,否则会抛出一个错误
let Person = (name, age) => {this.name = namethis.age = age}let me = new Person('tom',30)//Uncaught TypeError: Person is not a constructorconsole.log(me) -
不能使用
arguments变量,该对象在函数体内不存在。如果要用,可以用rest参数代替let fun = () => {console.log(arguments);}fun(1, 2)// ReferenceError: arguments is not defined
文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!














