函数的扩展
函数的默认值
function log(x, y = 'World') {
console.log(x, y);
}
//惰性求值
let x = 99;
function foo(p = x + 1) {
console.log(p);
}
foo() // 100
x = 100;
foo() // 101
//配合解构赋值默认值
function foo({x, y = 5}) {
console.log(x, y);
}
foo({x: 1, y: 2}) // 1 2
//使用双重默认值
function fetch(url, { body = '', method = 'GET', headers = {} } = {}) {
console.log(method);
}
fetch('http://example.com')
// "GET"
两种默认值的写法:
// 写法一
function m1({x = 0, y = 0} = {}) {
return [x, y];
}
// 写法二
function m2({x, y} = { x: 0, y: 0 }) {
return [x, y];
}
//第一种是解构赋值之后的默认值,第二种则是对于整个对象的默认值
对于参数默认值的位置应该使用undefined
来代替位置,会被默认值替换,而Null不行。
- 指定了默认值之后函数的length属性,返回没有指定默认值的参数个数.
(function (a) {}).length // 1
(function (a = 5) {}).length // 0
参数作用域:
var x = 1;
function f(x, y = x) {
console.log(y);
}
f(2) // 2
let foo = 'outer';
//参数找不到时往外面找
function bar(func = () => foo) {
let foo = 'inner';
console.log(func());
}
bar(); // outer
//理解作用域的小案例
var x = 1;
function foo(x, y = function() { x = 2; }) {
var x = 3;
y();
console.log(x);
}
foo() // 3
x // 1
rest参数:
function add(...values){}
使用arguments变量的写法:
const sortNumbers = (...numbers) => numbers.sort();
- 严格模式只能在全局或者没有参数的函数体内使用。
- 使用name属性访问函数名
var f = function () {};
// ES5
f.name // ""
// ES6
f.name // "f"
使用Function构造函数返回的函数实例,name为anonymous
(new Function).name // "anonymous"
bind返回的函数,name属性会加上bound前缀.
function foo() {};
foo.bind({}).name // "bound foo"
(function(){}).bind({}).name // "bound "
箭头函数
//箭头函数的错误用法
let foo = () => { a: 1 };
foo() // undefined
//箭头函数不需要返回值的用法
let fn = () => void doesNotReturn();
//箭头函数与变量解构配合使用
const full = ({ first, last }) => first + ' ' + last;
//箭头函数和rest参数结合使用
const numbers = (...nums) => nums;
const headAndTail = (head, ...tail) => [head, tail];
箭头函数的注意点:
1.this对象是定义时所在的对象,如:
function foo() {
setTimeout(() => {
console.log('id:', this.id);
}, 100);
}
var id = 21;
foo.call({ id: 42 });
// id: 42
2.不可作为构造函数,原因正是箭头函数没有自己的this,此外还有super,new.target都不存在,需要指向外层函数的对应变量,也就不能使用call(),apply(),bind()去改变this的指向.
ps:obj.call(db,parms)是更改绑定的this对象,并传入参数,使用,隔开;
而apply(db,[])使用数组装参数,
而bind参数和call一样,不过返回的是函数,因此还需要再进行调用.
3.不存在arguments对象,使用rest参数代替
4.不可使用yield命令,箭头函数不能用作Generator函数.
对于绑定时对应的作用域,普通函数是对应全局的作用域:
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);
setTimeout(() => console.log('s2: ', timer.s2), 3100);
// s1: 3
// s2: 0
不适合使用箭头函数的场景:
1.对象中有箭头函数且使用this,因为对象不是作用域,this为全局this
2.需要动态this的时候:
var button = document.getElementById('press');
button.addEventListener('click', () => {
this.classList.toggle('on');
});
箭头函数嵌套使用:
部署管道机制的作用,前一个输出为后一个输入:
const pipeline = (...funcs) =>
val => funcs.reduce((a, b) => b(a), val);
const plus1 = a => a + 1;
const mult2 = a => a * 2;
const addThenMult = pipeline(plus1, mult2);
addThenMult(5)
尾调用优化
某个函数的最后调用另一个函数,如:
function f(x){
return g(x);
}
//这种情况不对
// 情况三
function f(x){
g(x);
}
相当于
function f(x){
g(x);
return undefined;
}
尾调用优化:就是执行到尾调用函数时,可以直接将外部函数的调用帧直接替换即可,可以节省内存,但是该函数内部不能使用到外部函数的变量.
尾递归:
//返回的不是自身因此不是尾递归
function factorial(n) {
if (n === 1) return 1;
return n * factorial(n - 1);
}
factorial(5) // 120
//改成返回自身的递归就是尾递归
function factorial(n, total) {
if (n === 1) return total;
return factorial(n - 1, n * total);
}
factorial(5, 1) // 120
允许函数参数的尾逗号
Function.prototype.toString()返回函数代码本身。
允许catch代码块省略参数。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!