1. 函数的默认参数
1.1 es5处理默认参数
function add(a, b) {
a = typeof a === "undefined" ? 0 : a;
b = typeof b === "undefined" ? 0 : b;
return a + b;
}
1.2 es6形参默认值
function add(a = 0, b = 0) {
return a + b;
}
1.3 es6形参变量默认值
可以使用外层作用域内定义的变量当作默认值,后面的参数也可以用前面的参数当作默认值;
let defaultAge = 0;
function generateId(name, nickname = name, age = defaultAge) {
return name + "_" + nickname + "_" + age;
}
1.4 es6形参函数式默认值
也可以调用函数作为形参的默认值,这个作为默认值的函数只会在主函数被调用且需要默认参数的时候才会被调用;
function getDefaultNum() {
console.log("!");
return 0;
}
function add(a = 0, b = getDefaultNum()) {
return a + b;
}
1.5 默认参数对arguments的影响
在es5的非strict模式下,对参数的修改会映射到arguments对象上,es5的strict模式下,对参数的修改不会映射到arguments对象上;
function add(a, b) {
console.log(arguments); // [1, 2]
a = 100;
b = 200;
console.log(arguments); // [100, 200]
}
function add(a, b) {
"use strict";
console.log(arguments); // [1, 2]
a = 100;
b = 200;
console.log(arguments); // [1, 2]
}
在es6中,如果使用了默认参数,那么相当于es5的strict模式;
function add(a = 0, b) {
console.log(arguments); // [1, 2]
a = 100;
b = 200;
console.log(arguments); // [1, 2]
}
2. 无命名参数
JavaScript函数可以传入任意数量的参数;
2.1 es5获取无命名参数
使用arguments对象,再选取需要的参数;
2.2 es6获取无命名参数
使用 ...获得未被前面参数接受的剩余参数的数组
function add(a, b, ...rest) {
console.log(rest); // [3, 4, 5]
return a + b + rest.reduce((accumulator, currentValue) => accumulator + currentValue, 0)
}
add(1, 2, 3, 4, 5); // 15
2.3 使用无命名参数的注意事项
无命名参数只能放在最后一个参数;
不能用在定义对象字面量的setter中,因为setter只能接受一个参数;
3. 箭头函数
箭头函数与传统的函数相比,有以下不同之处;
3.1 箭头函数没有自己的this
1.普通function函数的this是调用时绑定,即什么对象调用它,它的this就指向什么对象(没有对象直接调用就是window/global);
2. 箭头函数的this取决于函数外部非箭头函数的this,如果外层还是箭头函数,就一直往外找,直到找到全局对象上;如f3,因为f3说非箭头函数,所以在它内部定义的箭头函数的this应该与f3的this相同,而f3由obj调用,所以f3的this是obj,所以内部的箭头函数的this也是obj;而f4也是箭头函数,所以在f4内部定义的箭头函数的this继续向外找,发现找不到,所以this就是全局对象window。
var a = 1;
let obj = {
a: 2,
f1: function () {
console.log(this.a);
},
f2: () => {
console.log(this.a);
},
f3: function () {
return () => {
console.log(this.a);
}
},
f4: () => {
return () => {
console.log(this.a);
}
}
}
obj.f1(); // 2
obj.f2(); // 1
obj.f3()(); // 2
obj.f4()(); // 1
let ff = obj.f3;
ff()(); // 1
2. 箭头函数不能通过bind、call、apply改变this,不会报错,但是是无效的;
var a = 1; // 全局对象window的属性
let obj = {
a: 2
}
let test = () => {
console.log(this.a);
}
test.bind(obj)(); // 1
test.call(obj); // 1
test.apply(obj); // 1
3.2 箭头函数不能使用arguments
箭头函数也没有arguments对象,它会去外层找非箭头函数的arguments,如果外层是非箭头函数,就用它的arguments,如果不是,就中断返回;
// 1.
function f1 (a, b, c) {
let f2 = (b, c) => {
console.log(arguments);
}
f2();
}
f1(1, 2, 3); // [1, 2, 3]
// 2.
let f1 = (a, b, c) => {
let f2 = (b, c) => {
console.log(arguments);
}
f2();
}
f1(1, 2, 3); // Uncaught ReferenceError: arguments is not defined
3.3 箭头函数没有prototype
首先,复习一下原型链:
原型链是一种类的实现,js为了简单的实现类和对象的关系,选择用原型链实现;
函数独有prototype,函数的prototype指向由这个函数创建的对象的原型对象;
对象独有__proto__,由某个函数创建的对象的__proto__指向函数的prototype;
每个函数都有一个原型对象,这个原型对象有一个constructor属性,指向创建对象的函数;
箭头函数没有prototype,但是有__proto__
3.4 箭头函数不能当作构造函数
new操作符干了些什么:
1.在内存中创建一个新对象obj;
2.设置新对象的原型链,obj.__proto__ = Func.prototype;
3.将Func内部的的this指向obj;
4.执行Func内部代码,即为obj添加属性等操作;var result = Func.call(obj)
5.如果Func返回的result是值类型,就返回obj;如果是引用类型,就返回这个引用类型的对象
---------因为箭头函数没有prototype,所以不能用来new对象