ES6基础:函数(上)

572 阅读6分钟

写在前面

函数(下)链接:juejin.cn/post/684490…

函数是所有编程语言的重要组成部分,es6出现之前,JavaScript的函数语法一直没有太大的变化,遗留了很多的问题,导致实现一些基本功能要编写较多的代码。今天学完了函数部分的语法,由于内容较多分成两个部分来总结,对比es6和es6之前的语法来总结。

文章稍稍长,既然点进来了就耐心看完再出去呗

函数(上)

1.函数形参的默认值

1.1 es5中设置默认参数

function makeRequest(url, timeout, calback) {
    timeout = (typeof timeout !== "undefined") ? timeout : 2000;
    calback = (typeof timeout !=="oundefined") ? calback : function() {};
}

1.2 es6中设置默认参数

es6简化了为形参提供默认值的代码,如果没有实参传入时提供一个初始值

function makeRequest(url, timeout = 2000,calback = function() {}) {
    
}

在es6的语法中,url是必须参数,其余两个是可选参数,不为可选参数传递值或者传递undefined才会使用其默认值,还是会优先使用实参。实参值为null也是合法的。

1.3 默认参数值对argument对象的影响

argument的length值是实参的个数。

在es5的非严格模式下,函数命名参数的改变会体现在同步更新到argumemt对象中,在es5的严格模式中,无论参数如何变化,argument对象将不再随之改变。

在es6中,如果使用了默认参数值,无论在什么模式,argument对象的行为与es5严格模式下的行为一致。

1.4默认参数的表达式和默认参数的临死区

默认参数表达式就是参数以表达式的形式体现出来,下面代码中first = second就是表达式。

默认参数表达式要注意的地方,当使用函数调用结果作为默认参数值时,不要忘记写小括号(),否则是对函数的引用而不是结果。

function add(first = second,second) {
    return first + second;
}
console.log(add(1,1));//2
console.log(add(undefined,1));// 抛出错误

这里为神马会爆出错误呢?在这个例子里,两次调用add函数在引擎背后做了哪些事情呢 ?
//add(1,1)

let first = 1;
let second = 2;

//add(undefined,1)

let first = secod;
let second= 1;

在之前学习js的时候发现函数里面的变量都没有像c,java语言那样经过定义再使用,原因就是调用函数时候引擎内部进行定义声明。

在这里,first初始化时候second没有初始化在临死区域中,前面let绑定时说过引用临死区域中绑定的行为都会报错。

2.无命名参数

2.1在es5中的无命名参数

在早期es5中不定义每一个要用到的参数,而是根据argument对象来检查函数的所有参数。举个栗子:

//只有一个参数boo
function pick(boo) {
//创建一个空对象result
    let result = Object.create(null);
    
    //重第二个参数开始
    for(let i = 1;i<arguments.length;i++) {
        result[[arguments[i]] = boo[[arguments[i]];
        //这里若i==1,即result.author = boo.author
    }
    return result;
}
let book = {
    title:'qqqq';
    author:'refef';
    year:"1999";
};
let bookPick = pick(book, "author","year");

console.log(bookPick.author);
console.log(bookPick.year)

上述demo里只定义了一个对象,第一个参数传入是被复制属性的源对象book,其他参数为被复制属性的名称author和year。这里需要从索引1开始遍历来拷贝属性名。

在es6中可以用不定参数来解决这些问题,是问题变得更加简单。

2.2 在es6中的不定参数

在函数的命名参数前面添加三个点...就表示一个不定参数,如...keys就是一个不定参数,keys是一个数组。

用不定参数重现上面pick函数的例子

function pick(object, ...keys) {
    let result = Object.create(null);
    for( let i = 0,len = keys.length; i<len; i++) {
    result[keys[i]]= object[keys[i]];
    }
    return result;
    let book = {
    title:'qqqq';
    author:'refef';
    year:"1999";
};
let bookPick = pick(book, "author","year");

console.log(bookPick.author);
console.log(bookPick.year)
}

这里keys数组包含了book后面传入的所有参数。argument对象包含的是所有传入的参数包括object,函数的length值是函数命名参数的数量,不定参数的加入对其无影响,在本例中pick()函数的length=1,只计算object

2.3 不定参数的使用限制

每个函数只能声明一个不定参数,而且只能放在所有参数的末尾

不定参数不能用于对象字面量setter中,seetter的参数有且只能有一个,不定参数的参数数量可以有无限多个

2.4 不定参数对arguements的影响

不论是否使用了不定参数,arguments始终包含所有传入函数的参数,这一点在前面的2.2中也有提到。

3.增强的Function构造函数

es5中的function

Function构造函数是javascript语法中很少被用到的一部分,通常用它动态创建新函数,这种构造函数接受字符串的形式,分别为函数的参数以及函数体。

var add = new Function("first", "second", "return first + second") ;
console.log(add(1,1)); 

es6中的Function

在es6中可以在创建函数的时候定义默认参数和不定参数

var pickFirst = new Function("...args", "return args[0]");
console.log(pickFirst(1 ,2)); //1

4.展开运算符

在说展开运算符之前,先看一个Math.max的例子,它可以接受任意数量的·1参数但是不能接受数组。在es5及之前,需要手动遍历数组或者使用apply。

let values = [1,45,63];
console.log(Math.max.apply(Math,values));

这个代码很难让人看懂,需要了解this,apply改变this指向 在es6中,可以添加不定参数表示一个数组,因而就不需要apply()方法了。js引擎会将参数数组分割成独立的参数并依次传入。

let values = [1,45,63];
console.log(Math.max(...values));
//==console.log(Math.max(1,45,63));

如果还有其他值想进行比较,可以单独传入。如和0比较:

let values = [1,45,63];
console.log(Math.max(...values,0));

5.name属性

js中的匿名函数表达式的广泛使用加大了调试的难度。es6中name属性使函数都有一个自己合适的名字。

一般非匿名函数name属性值对应声明时的函数名称,匿名函数对应着被赋值为该匿名函数的变量的名称

name属性值得特殊情况

1.函数非匿名函数,又被赋值的情况下name值是函数表达式自己的名字不是被赋值变量的名字,因为这个名字比函数本身被赋值的变量的权重高。

2.对象字面量的name值取对象字面量

var person = {
    get firstName = {
        return "aaa"
    },
    sayName: function() {
        console.log(this.name);
    }
}

console.log(person.sayName.name); //"sayName"
console.name(person.firstName.name); //" get firstName"

3.bind()函数创建的函数,其名称带有bond前缀,通过Function构造函数创建的函数,其名称是“anonymous”。

最后name属性值是协助调试用的额外信息,不能用name属性的值来获取对函数的引用