js函数


Function.prototype.toString()
1
2
let fn = function(){}
fn.toString() // 'function(){}'
函数与解构赋值结合使用
1
2
3
4
5
6
7
8
9
function foo({x, y = 5}) {
console.log(x, y);
}

foo({}) // undefined 5
foo({x: 1}) // 1 5
foo({x: 1, y: 2}) // 1 2
foo() // TypeError: Cannot read property 'x' of undefined
// 上面代码只使用了对象的解构赋值默认值,没有使用函数参数的默认值。只有当函数foo的参数是一个对象时,变量x和y才会通过解构赋值生成。如果函数foo调用时没提供参数,变量x和y就不会生成,从而报错。通过提供函数参数的默认值,就可以避免这种情况。
1
2
3
4
5
function foo({x, y = 5} = {}) {
console.log(x, y);
}

foo() // undefined 5
函数参数默认值的位置

函数参数默认值应该放最后,这样就可以看出到底省略了哪些参数,不放最后就没意义了

1
2
3
4
5
6
function f(x = 1, y) {
return [x, y];
}
f() // [1, undefined]
f(2) // [2, undefined])
f(, 1) // 报错

函数的length属性

函数的length属性,将返回没有指定默认值的参数个数。也就是说,指定了默认值后,length属性将失真。

1
2
3
(function (a) {}).length // 1
(function (a = 5) {}).length // 0
(function (a, b, c = 5) {}).length // 2

函数参数的作用域

一旦设置了参数的默认值,函数进行声明初始化时,参数会形成一个单独的作用域(context)。等到初始化结束,这个作用域就会消失。

1
2
3
4
5
var x = 1;
function f(x, y = x) {
console.log(y);
}
f(2) // 2

rest参数

ES6 引入 rest 参数(形式为…变量名),用于获取函数的多余参数,这样就不需要使用arguments对象了。rest 参数搭配的变量是一个数组,该变量将多余的参数放入数组中。
注意,rest 参数之后不能再有其他参数(即只能是最后一个参数),否则会报错。

1
2
3
4
5
6
7
8
// arguments变量的写法
function sortNumbers() {
return Array.prototype.slice.call(arguments).sort();
}

// rest参数的写法
const sortNumbers = (...numbers) => numbers.sort();
//arguments对象不是数组,而是一个类似数组的对象。所以为了使用数组的方法,必须使用Array.prototype.slice.call先将其转为数组。rest 参数就不存在这个问题,它就是一个真正的数组,数组特有的方法都可以使用。

name属性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
function foo() {}
foo.name // "foo"

var f = function () {}; // 匿名函数
// ES5
f.name // ""
// ES6
f.name // "f"

const bar = function baz() {};
// ES5
bar.name // "baz"
// ES6
bar.name // "baz"
箭头函数

JavaScript 语言的this对象一直是一个令人头痛的问题,在对象方法中使用this,必须非常小心。

1
2
3
4
5
6
7
8
9
10
11
12
13
const team = {
members:["Henry","Elyse"],
teamName:"es6",
teamSummary:function(){
return this.members.map(function(member){
return `${member}隶属于${this.teamName}小组`; // this指向的是window
})
}
}
console.log(team.teamSummary());//["Henry隶属于undefined小组", "Elyse隶属于undefined小组"]

// 箭头函数
var sum = (num1, num2) => { return num1 + num2; }

由于大括号被解释为代码块,所以如果箭头函数直接返回一个对象,必须在对象外面加上括号,否则会报错。

1
2
3
4
5
// 报错
let getTempItem = id => { id: id, name: "Temp" };

// 不报错
let getTempItem = id => ({ id: id, name: "Temp" });

箭头函数注意

(1)函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。
(2)不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。
(3)不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。

不适合场合
1
2
3
4
5
6
7
const cat = {
lives: 9,
jumps: () => {
this.lives--;
}
}
// cat.jumps()方法是一个箭头函数,这是错误的。调用cat.jumps()时,如果是普通函数,该方法内部的this指向cat,如果写成上面那样的箭头函数,使得this指向全局对象
1
2
3
4
5
var button = document.getElementById('press');
button.addEventListener('click', () => {
this.classList.toggle('on');
});
// 上面代码运行时,点击按钮会报错,因为button的监听函数是一个箭头函数,导致里面的this就是全局对象。如果改成普通函数,this就会动态指向被点击的按钮对象。