ES6 -- 函数

参数默认值

function sum(a, b, c) {
    // b = b || 1;
    // c = c || 1;

    b = b === undefined && 1;
    c = c === undefined && 1;

    return a + b + c;
}

console.log(sum(10, 11, 12)); // 33

使用

在书写形参时,直接给形参赋值,赋的值即为默认值。

这样一来,当调用函数时,如果没有给对应的参数赋值(给它的值是undefined),则会自动使用默认值。

function sum(a, b = 1, c = 1) {

    return a + b + c;
}

console.log(sum(10)); // 12
<div id="container"></div>

<script>
    const parent = document.getElementById("container");

    function craeteElement(name = "div", container = parent, content = "") {
        const ele = document.createElement(name);

        if(content) {
            ele.innerHTML = content;
        }
        container.appendChild(ele);
    }

    // craeteElement("div", parent, "123");

    craeteElement(undefined, undefined, "123");
</script>

对 arguments 的影响

function test(a, b) {
    console.log("a:", a, "b:", b); // a: 1 b: 2
    console.log(arguments); // [1, 2]

    a = 3;
    console.log("a:", a, "b:", b); // a: 3 b: 2
    console.log(arguments); // [3, 2]
}
test(1, 2);

严格模式下:

"use strict"
function test(a, b) {
    console.log("a:", a, "b:", b); // a: 1 b: 2
    console.log(arguments); // [1, 2]

    a = 3;
    console.log("a:", a, "b:", b); // a: 3 b: 2
    console.log(arguments); // [1, 2]
}
test(1, 2);

只要给函数加上参数默认值,该函数会自动变成严格模式下的规则:argument 和 形参脱离。

function test(a = 1, b = 3) {
    console.log("a:", a, "b:", b); // a: 2 b: 3
    console.log(arguments); // [2]

    a = 3;
    console.log("a:", a, "b:", b); // a: 3 b: 3
    console.log(arguments); // [2]
}
test(2);

留意暂时性死区

形参和ES6中的let和const声明一样,具有作用域,并且根据参数的声明顺序,存在暂时性死区。

function test(a = b, b) {
    console.log(a, b); // Cannot access 'b' before initialization
}
test(undefined, 1);

剩余参数

function sum(arg) {
    let sum = 0;
    for(let i = 0; i < arg.length; i ++) {
        sum += arg[i];
    }
    return sum;
}

console.log(sum([1])); // 1
console.log(sum([1, 2, 3, 4])); // 10

arguments的缺陷:

  1. 如果和形参配合使用,容易导致混乱。
  2. 从语义上,使用arguments获取参数,由于形参缺失,无法从语义上理解函数的真实意图。
function sum() {
    let sum = 0;
    for(let i = 0; i < arguments.length; i ++) {
        sum += arguments[i];
    }
    return sum;
}

console.log(sum(1)); // 1
console.log(sum(1, 2, 3, 4)); // 10

ES6的剩余参数专门用于收集末尾的所有参数,将其放置到形参数组中。

语法:

function (...形参名) {

}
function sum(...args) {
    // args 收集了所有的参数,形成一个数组
    // console.log(args);
    
    let sum = 0;
    for(let i = 0; i < args.length; i ++) {
        sum += args[i];
    }
    return sum;
}

console.log(sum(1)); // 1
console.log(sum(1, 2, 3, 4)); // 10

细节:
1. 一个函数,只能出现一个剩余参数。
2. 一个函数,如果有剩余参数,剩余参数必须是最后一个参数。

展开运算符

使用方式: ...要展开的东西

对 数组展开 ES6

// 对所有数组求和
function sum(...args) {
    let sum = 0;
    for(let i = 0; i < args.length; i ++) {
        sum += args[i];
    }
    return sum;
}

// 获取一个指定长度的随机数组成的数组
function getRandomNumbers(length) {
    const arr = [];
    for(let i = 0; i < length; i ++) {
        arr.push(Math.random());
    }
    return arr;
}

const numbers = getRandomNumbers(10);
console.log(numbers);

// 将数组的每一项展开,依次作为参数传递,而不是把整个数组作为一个参数传递
console.log(sum(...numbers)); // 相当于传递了10个参数 

深度克隆:

const arr1 = [1, 2, 3];
const arr2 = [...arr1];

console.log(arr2, arr2 === arr1); //  [1, 2, 3]    false

对 对象展开 ES7

const obj1 = {
    name: "刘",
    age: 20
}

const obj2 = {
    ...obj1
}

console.log(obj2, obj2 === obj1); //  {name: "刘", age: 20}   false

明确函数的双重用途

使用构造函数,或使用普通函数。

function Person(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.fullName = `${firstName} ${lastName}`;
}

const p1 = new Person("p1", "p");
console.log(p1); // {firstName: "p1", lastName: "p", fullName: "p1 p"}

const p2 = Person("p2", "p");
console.log(p2); // undefined
function Person(firstName, lastName) {
    // 判断是否是使用new的方式来调用函数

    // 过去的判断方式
    if(!(this instanceof Person)) {
        throw new Error("该函数没有使用new来调用");
    }

    this.firstName = firstName;
    this.lastName = lastName;
    this.fullName = `${firstName} ${lastName}`;
}

const p1 = new Person("p1", "p");
console.log(p1); // {firstName: "p1", lastName: "p", fullName: "p1 p"}

// 可避开判断
const p3 = Person.call(p1, "p3", "p");
console.log(p3); // undefined

const p2 = Person("p2", "p");
console.log(p2); // Uncaught Error: 该函数没有使用new来调用

ES6提供了一个特殊的API,可以使用该API在函数内部,判断该函数是否使用了new来调用。

new.target
// 该表达式,得到的是:如果没有使用new来调用函数,则返回undefined;如果使用new调用函数,则得到的是new关键字后面的函数本身
function Person(firstName, lastName) {
    // 判断是否是使用new的方式来调用函数

    // ES6 判断方法
    // console.log(new.target);
    if(new.target === undefined) {
        throw new Error("该函数没有使用new来调用");
    }

    this.firstName = firstName;
    this.lastName = lastName;
    this.fullName = `${firstName} ${lastName}`;
}

const p1 = new Person("p1", "p");
console.log(p1); // Person {firstName: "p1", lastName: "p", fullName: "p1 p"}

const p3 = Person.call(p1, "p3", "p");
console.log(p3); // Uncaught Error: 该函数没有使用new来调用

const p2 = Person("p2", "p");
console.log(p2);

箭头函数

回顾:this指向

  • 1.通过对象调用函数,this指向对象
  • 2.直接调用函数,this指向全局对象
  • 3.如果通过new调用函数,this指向新创建的对象
  • 4.如果通过apply、call、bind调用函数,this指向指定的数据
  • 5.如果是DOM事件函数,this指向事件源
const obj = {
    count: 0,
    start: function() {
        console.log(this); //  this --> obj
        setInterval(function() {
            console.log(this); // this --> window
            this.count ++;
            console.log(this.count); // NaN
        },1000)
    }
}

obj.start();
const obj = {
    count: 0,
    start: function() {
        // console.log(this); //  this --> obj
        var self = this;
        setInterval(function() {
            console.log(self); // this --> obj
            self.count ++;
            console.log(self.count);
        },1000)
    }
}

obj.start();

使用语法

箭头函数是一个函数表达式,理论上,任何使用函数表达式的场景都可以使用箭头函数。

完整写法:

(参数1, 参数2) => {
    // 函数体
}
const obj = {
    count: 0,
    start: function() {
        console.log(this); //  this --> obj
        
        setInterval(() => {
            console.log(this); // this --> obj
            this.count ++;
            console.log(this.count);
        },1000)
    }
}

obj.start();

如果参数只有一个,可以省略小括号:

参数 => {
    // 函数体
}

如果箭头函数只有一条返回语句,可以省略大括号,和return关键字:

参数 => 返回值

注意细节

  • 箭头函数的函数体中的this,取决于箭头函数定义的位置的this指向,而与如何调用无关。

1. 箭头函数中,不存在 this、arguments、new.target ,如果使用了,则使用的是函数外层的对应的 this、arguments、new.target 。

2. 箭头函数没有原型。

3. 箭头函数不能作为构造函数使用。

应用场景

1. 临时性使用的函数,并不会刻意调用它。比如:事件处理函数、异步处理函数、其他临时性的函数。

2. 为了绑定外层this的函数。

3. 在不影响其他代码的情况下,保持代码的简洁。最常见的是数组方法中的回调函数。

const num = [3, 5, 5, 3, 2];

const result = num.filter(num => num % 2 === 0).map(num => num * 2);

console.log(result); // [4]
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容