ES6函数

本文详细介绍了ES6中函数的改进,包括默认参数、arguments对象的行为改变、剩余参数和扩展运算符的使用,以及箭头函数的特性和this的指向。此外,还讨论了new关键字的作用以及new.target的引入,强调了块级函数和函数提升的行为。
摘要由CSDN通过智能技术生成

ES6函数

@(ES6大法) 来自印象笔记的整理
1、在ES5中,要对一个参数赋默认值都要这样:

function makeRequest(url, timeout, callback) {
    timeout = timeout || 2000;
    callback = callback || function() {};
    // 函数的剩余部分
}

当timeout、callback实参为undefined时,|| 后面的值就会成为它门的默认值。ES5的实现办法要写这么多代码,特别麻烦。

ES6对函数进行改造,可以对参数进行默认:

function makeRequest(url, timeout = 2000, callback = function() {}) {
    // 函数的剩余部分
}
// 不使用默认值,传null会被采用,undefined不会
makeRequest("/foo", null, function(body) {
    doSomething(body);
});

2、ES6函数中的arguments对象

ES5中,非严格模式: arguments 对象会反映出具名参数的变化(arguments可以在函数内由于对形参的重新赋值而会被改写),
严格模式,不再反映出具名参数的变化(在函数内对参数的重新赋值不会影响到arguments的值)

ES6函数的arguments对象表现与ES5严格模式一致。
还有一点要注意:ES6参数默认值的存在触发了 arguments 对象与
具名参数的分离,也就是说,虽然你指定了其中一个参数的默认值,但是,arguments对象还是以你调用传进来为准,不会把默认值放进arguments对象里去。

3、ES6函数的默认参数也可以是个表达式

let value = 5;
function getValue() {
    return value++;
}
function add(first, second = getValue()) {
    return first + second;
}
console.log(add(1, 1)); // 2
console.log(add(1)); // 6
console.log(add(1)); // 7

4、ES6函数的默认值可以是前面(后面不行)的参数,或者前面的参数的运算

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

5、ES6的参数默认值的暂时性死区
与let/const 的暂时性死区相同,函数的每个参数都会创建一个新的标识,在初始化之前不允许访问。这体现在第4点,只能对前面的参数进行对后面参数的默认。

6、ES5的不具名参数和ES6的剩余参数
当不确定参数有几个时,ES5可以使用arguments对象来查看所有传进来的参数,并做一些逻辑处理:

function pick(object) {
    let result = Object.create(null); // 传建一个原型为null的对象
    // 从第二个参数开始处理
    // 遍历arguments对象
    // 根据第1个参数之后的参数,从第一个参数中挑出符合组成新对象(result)返回
    for (let i = 1, len = arguments.length; i < len; i++) {
        result[arguments[i]] = object[arguments[i]];
    }
    return result;
}
let book = {
    title: "Understanding ES6",
    author: "Nicholas C. Zakas",
    year: 2015
};
let bookData = pick(book, "author", "year");
console.log(bookData.author); // "Nicholas C. Zakas"
console.log(bookData.year); // 2015

ES6引入了剩余参数解决以上对arguments操作不易于阅读的问题
剩余参数由三个点…与一个紧跟着的具名参数指定

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;
}

…keys 与 arguments不同,它是除了第一个参数的剩下的参数组成的数组。

注意:
1)函数的length属性由具名参数个数决定,不包括剩余参数
上面的函数,pick.length = 1
2)一个函数只能有一个剩余函数
3)剩余参数必须放在最后一个
4)剩余参数不能在对象字面量的setter属性中使用,对象字面量的 setter 被限定只能使用单个参数;而剩余参数按照定义是不限制参数数量的,因此它在此处不被许可

let object = {
    // 语法错误:不能在 setter 中使用剩余参数
    set name(...value) {
        // 一些操作
    }
};

7、剩余参数的出现目的是替代掉之前的arguments

8、扩展运算符
剩余参数是为了把多个独立的参数合并到一个数组去,而扩展运算符用在调用函数时传入函数的参数中:

console.log(Math.max.apply(Math, [1,2,3,4,5]));

以上是ES6之前的写法,由于max函数接受的参数为单个元素,数组求最大值就只能改变max函数的this指向,而现在用ES6你可以这样:

console.log(Math.max(...[1,2,3,4,5])); 

…扩展运算符, JS 引擎将会将该数组分割为独立参数并把它们传递进去

你还可以把扩展运算符和其他参数混合

console.log(Math.max(...[1,2,3,4,5], 10)); 

9、函数的new关键字的双重用途未使用new调用时,返回了undefined,并会在全部window对象添加添加name属性,此时this指向window

function Person(name) {
    this.name = name;
}
// 使用new调用时,函数内部的this是一个新对象,并作为函数的返回值,此时this指向的是调用者person
var person = new Person("Nicholas");
// 未使用new关键字,返回undefined,并在全局window对象下添加name属性
// 指向window
var notAPerson = Person("Nicholas");
console.log(person); // "[Object object]"
console.log(notAPerson); // "undefined"

为啥?
答:
1)JS 为函数提供了两个不同的内部方法: [[Call]] 与 [[Construct]]
2)当函数未使用 new进行调用时, [[call]] 方法会被执行,call运行的是函数的函数体
3)而当函数使用 new进行调用时, [[Construct]] 方法则会被执行,负责创建一个被称为新目标的新的对象,且使用该新目标作为 this 去执行函数体,拥有[[Construct]]的函数被称为构造器

注意:不是所有函数都有[[Construct]] 方法,箭头函数就没有,用instanceof来判断一个函数的构造器是什么

所以,在 ES5 中判断函数是不是使用了 new 来调用(即作为构造器),下面来告诉调用者用Person必须用new关键字:

function Person(name) {
    if (this instanceof Person) {
        this.name = name; // 使用 new
    } else {
        throw new Error("You must use new with Person.")
    }
}
var person = new Person("Nicholas");
var notAPerson = Person("Nicholas"); // 抛出错误

可惜的是,该方法并不绝对可靠,可以这样绕过:

function Person(name) {
    if (this instanceof Person) {
        this.name = name; // 使用 new
    } else {
        throw new Error("You must use new with Person.")
    }
}
var person = new Person("Nicholas");
var notAPerson = Person.call(person, "Michael"); // 奏效了!

用call改变this的指向为person,对于该函数来说,没有任何方法能将这种方式与使用 new 调用区分开来。

10、ES6登场:new.target,使用new的调用后,new.target为构造器,不使用new调用,则new.target 为 undefined

11、ES6的块级函数

ES5严格模式下,不允许在代码块中声明函数:

"use strict";
if (true) {
    // 在 ES5 会抛出语法错误, ES6 则不会
    function doSomething() {
        // ...
    }
}

ES6中则不会,与块级作用域相似,在代码块中声明的函数,只能都在块里被访问,而唯一与let/const的区别是,块级函数存在函数提升到代码块顶部,而let/const不能提升。

另外要注意的是:
在ES6非严格模式下,块级函数的提升不是提升到代码块的顶部,而是提升到函数或者全局环境的顶部(当前作用域顶部)

12、箭头函数 =>
与传统的js函数有何不同?
1)没有 this 、 super 、 arguments ,也没有 new.target 绑定,
2)不能被使用 new 调用
3)没有原型, 既然不能对箭头函数使用 new ,那么它也不需要原型,也就是没有
prototype 属性
4)不能更改 this
5)不允许重复的具名参数

13、箭头函数的语法:
参数只有一个,可以省略()

var reflect = value => value;

函数体只有一句,可以省略{},作为返回值

var sum = (num1, num2) => num1 + num2;

如果没有参数,就要用()

var getName = () => "Nicholas";

如果要创建一个空函数,必须有{}

var doNothing = () => {};

如果函数体不止一句,要加{}
如果函数返回值是对象,即使只有一句,也要加({})

var getTempItem = id => ({ id: id, name: "Temp" });

14、箭头函数没有 this 绑定,意味着箭头函数内部的 this 值只能通过查找作用域链来确定。如果箭头函数被包含在一个非箭头函数内,那么 this 值就会与该函数的相等;否则,this 值就会是全局对象(在浏览器中是 window ,在 nodejs 中是 global )

15、ES5中普通函数的this指向会发生变化:
1). this总是代表它的直接调用者(js的this是执行上下文), 例如 obj.func ,那么func中的this就是obj
2).在默认情况(非严格模式下,未使用 ‘use strict’),没找到直接调用者,则this指的是 window (约定俗成)
3).在严格模式下,没有直接调用者的函数中的this是 undefined
4).使用call,apply,bind(ES5新增)绑定的,this指的是 绑定的对象

16、尾调用优化

总结
A. ES6函数增加了默认参数,默认参数不会计入到arguments对象
B. ES6函数的arguments不允许在函数内改写,与ES5严格模式一致
C. ES6的默认参数可以是表达式
D. ES6函数是块级函数,只能在块级作用域下访问,严格模式下,会提升到代码块顶部,非严格模式下,提升到函数或者全局环境顶部
E. ES6剩余参数和扩展运算符,函数的length属性不包含剩余参数
F. ES6函数的语法
G. ES6函数this

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值