js之函数

288 阅读3分钟

1、函数参数的默认值

function foo(a, b=1){
    console.log(a, b)//
}
foo(2);
//2 1
foo(2, undefined);
//2 1
foo(2, null);
//2 null

默认值可以是表达式,惰性求值

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

x=100
foo();
//101

2、与解构赋默认值相结合

有两种默认值: (1)对象的解构赋默认值 (2)函数参数的默认值

function fetch(url, {method='GET'} = {}){
    //todo
}
fetch('http://example.com');

注意以下两种写法的区别

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]

m1({x: 1, y: 2});//[1, 2]
m2({x: 1, y: 2});//[1, 2]

m1({x: 1});//[1, 0]
m2({x: 1});//[1, undefined]

m1({y: 2});//[0, 2]
m2({y: 2});//[undefined, 2]

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

m1设置了函数参数的默认值是个空对象,但是对象解构赋值的默认值。 m2设置了函数参数的默认是个具有具体属性的对象,但是没有设置对象解构赋值的默认值

参数默认值的位置,应该是函数的未参数 如果非尾部设置默认值,实际上这个参数是无法省略的。除非显式输入undefined

function foo(a, b=2, c){
    return[a, b, c];
}
foo(1, , 2);//报错
foo(1, undefined, 3)//[1, 2, 3]

3、函数的length属性

fun.length,返回函数参数的个数。指定了默认值以后,函数的length属性将返回没有指定默认值的参数的个数。如果设置默认值的参数不是尾参数,那么length属性也不再计入后面的参数。

rest参数也不会计入length属性。

function foo(a, b=1, c){
}
foo.length;//1

function boo(a, b, ...arg){
}
boo.length;//2

4、作用域

一旦设置了参数的默认值,函数进行声明初始化时,参数会形成一个独立作用域(context),等初始化结束,这个作用域就会消失。

let x= 2;
function foo(y = x){
    let x = 3;
    console.log(y);
}
foo();
//2

函数f调用时,参数y = x形成一个单独的作用域,这个作用域里面,变量x本身没有定义,所以指向外层的全局变量x。函数体内部的局部变量x影响不到默认值变量x。

function foo(y = x){
    let x = 3;
    console.log(y);
}
foo();
//报错

默认值是函数

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

5、rest参数('...变量名')

利用rest向函数传入任意数目的参数。rest参数后不能再有其他参数,否则会报错

规定只要函数参数使用默认值、解构赋值、扩展运算符,那么函数内部就不能显示设定为严格模式,否则会报错。 函数内部的严格模式同时适用于函数体和函数参数,但是函数执行时,先执行函数参数,然后再执行函数体。不合理的地方,只有从函数体之中才能知道函数是否应该以严格模式运行。

6、函数的name属性

返回改函数的函数名。

function boo(){}
boo.name;//'boo'
boo.bind({}).name;"bound boo"

var a = ()=>{}
a.name;//'a'

var b = function(){}
b.name;//'b'

(()=>{}).name;//''
(()=>{}).bind(null).name;//'bound '

7、箭头函数

另外一篇文章

箭头函数有几个使用注意点。

(1)函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象

(2)不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误

(3)不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest参数代替

(4)不可以使用yield命令,因此箭头函数不能用作Generator函数

8、尾调用优化

某个函数的最后一步是调用另外一个函数。只有不再用到外层函数的内部变量,内层函数的调用帧才不会取代外层函数的调用帧,否则不能进行尾部调用优化。

参考链接:es6.ruanyifeng.com/#docs/funct…