Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

深入了解ES6函数篇 #2

Open
laihuamin opened this issue Aug 17, 2017 · 0 comments
Open

深入了解ES6函数篇 #2

laihuamin opened this issue Aug 17, 2017 · 0 comments

Comments

@laihuamin
Copy link
Owner

laihuamin commented Aug 17, 2017

带参数默认值的函数

1. 什么是带默认值的函数

function example(url, timeout=2000, callback = function(){}) {}

此函数只要求第一个参数始终要被传递,其他两个都带有默认值,这样使得函数更加小巧,不需要添加很多条件来判断参数是否缺失

2. 带默认值的函数的性质

  • 在传入的参数中,null是被判定为有效的
  • 参数默认值对arguments对象的影响

(1)首先讲讲在ES5中非严格模式下,arguments对象反应出具名参数的变化,在ES5的非严格模式下,arg总是会被更新的以反映出具名的变化,举个例子

function mixArgs(first, second){
    console.log(first === arguments[0]);
    console.log(second === arguments[1]);
    first = 'c';
    second = 'd';
    console.log(first === arguments[0]);
    console.log(second === arguments[1]);
}
mixArgs('a', 'b');
//true
//true
//true
//true

(2)在ES6中与ES5的严格模式一致,arguments对象只能反映最初值

function mixArgs(first, second){
    console.log(first === arguments[0]);
    console.log(second === arguments[1]);
    first = 'c';
    second = 'd';
    console.log(first === arguments[0]);
    console.log(second === arguments[1]);
}
mixArgs('a', 'b');
//true
//true
//false
//false

(3)参数默认值的存在会触发arguments对象与具名函数的分离.其实下面这个例子也不难理解,因为只传了一个参数,所以arg的长度是1,second的值为默认值'b',arguments[1]的值为undefined。

function mixArgs(first, second = 'b'){
    console.log(arguments.length);
    console.log(first === arguments[0]);
    console.log(second === arguments[1]);
    first = 'c';
    second = 'd';
    console.log(first === arguments[0]);
    console.log(second === arguments[1]);
}
mixArgs('a');
//1
//true
//false
//false
//false
  • 参数默认值表达式

默认参数不一定要求的最基本类型,例如你可以执行一个函数来产生参数的默认值

function getValue() {
    return 5;
}
function add(first, second=getValue()){
    return first + second;
}
add(1, 1); //2
add(1); //2

将函数调用作为参数的默认值时,一定要小心,如果遗漏了括号,second = getValue,那么你就是按引用传递的,而不是按函数返回的结果传递的.

将前面一个的参数当作默认值传递给后面一个

function add(first, second = first){
    return first + second;
}
console.log(add(1,1)); //2
console.log(add(1)); //

但是这样会如果前面的用后面的值,就会造成暂时性死区

function add(first=second, first){
    return first + second;
}
console.log(add(1,1)); // 2
console.log(add(undefined,1)) //error
  • 剩余参数

(1)剩余参数由三个点(···)和一个紧跟的具名参数指定,它是包含传递给函数的其余参数的一个数组,如同understore.js中的pick函数一样

function pick(object, ...keys){
    let result = Object.create(null);
    for(let i = 0; i < keys.length; i++){
        result[keys[i]] = object[keys[i]];
    }
return result;
}

剩余参数会连同第一个参数都包含在内。这意味着你可以对keys从头到尾进行迭代,不需要有所顾虑。作为一个额外的收益,通过观察该函数便能判断它具有处理任意参数的能力

(2)剩余参数的限制条件,主要受限于两点,一是函数只能有一个剩余参数,二是剩余参数不能对对象字面量的setter

//报错,不能再剩余参数后使用具名函数
function pick(object, ...keys, last){
    let result = Object.create(null);
    for(let i = 0; i < keys.length; i++){
        result[keys[i]] = object[keys[i]];
    }
return result;
let object = {
//语法错误:不能在setter中使用剩余参数
    set name(...value){
    // 一些操作
    }
}
  • 函数构造器能力的增强

允许使用默认参数以及剩余参数

  • 扩展运算符

扩展运算符经常和剩余函数联系到一起,因为剩余函数允许你将多个独立的参数合并到一个数组,而扩展运算符则允许将一个数组分割,并将各个项作为分离的参数,传递给函数使用。

扩展运算符的使用就像剩余函数那样在数组前加...,并直接将其传递给函数,JS引擎就会将数组分割为独立的参数传入。

let values = [1, 2, 3, 4, 5, 6];
console.log(Math.max(...values));
=>等价于 console.log(Math.max(1,2,3,4,5,6));

扩展运算符后面还可以添加参数

let values = [1, 2, 3, 4, 5, 6];
console.log(Math.max(...values, 7)); //7
  • 函数名称

ES6中给所有函数都添加了函数名称

function someName() {
    ....//写代码
}
const anotherName = function () {...}
console.log(someName.name); //someName
console.log(anotherName.name); //anotherNam

看下面的例子中,可以看到自己拥有一个名称的优先级高于赋值名称

var doSome = function someName() {
    ...//代码
}
console.log(doSome.name); // someName
  • 明确函数的双重用途

在ES5版本及以前,函数根据的是否使用new来调用而有双重用途。当使用new时,函数内部的this是一个新的对象,并作为函数的返回值,如

function Person(name) {
    this.name = name;
};
var person = new Person('lai');
var notPerson = Person('hua');
console.log(person); // [Object object]
console.log(notPerson); //"undefined"

上述方法中,在没有new的情况下,且在非严格模式下,还会给全局对象添加一个name属性

在ES6中,这些情况得以改善,ES6提供了两种不同的内部方法,[[call]]和[[Construct]]。当函数不使用new时,[[call]]会被执行,执行的是代码中显示的函数体,当new被调用时,[[Construct]]会被执行,负责创建一个被称为新目标的新对象,并且会用让this去指向它。

  • 在ES5中判断函数是否被调用

函数如果被调用,那么可以用instaceOf的方法去查看他的构造器

在ES5判断函数是否使用new来调用的流行方法

function Person(name) {
    if(this instanceOf Person){
        this.name = name;
    }else{
        throw new error('You must use new with Person')
    }
}
var person = new Person('lai');
var notPerson = new Person('hua'); //P

块级函数

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant