函数
参数的默认值
参数默认值表达式
function defaultValue() {
return 1;
}
function foo(x = defaultValue()) {
console.log(x);
}
foo(); // 1
foo(undefined) // 1
使用参数作为默认值
- 还可以使用前一个参数的值作为默认值。
function foo(x, y = x) {
console.log(x, y);
}
foo(2); // 2 2
使用参数值作为默认值表达式的参数
function defaultValue(x) {
return x + 3;
}
function foo(x, y = defaultValue(x)) {
console.log(y);
}
foo(1);
剩余参数
ES6
之前通过 arguments 来访问。
function foo(x) {
console.log(arguments[1]);
console.log(arguments[2]);
console.log(arguments);
console.log(arguments.callee);
console.log(arguments.length);
}
foo(1, 2, 3); // 2
/*
ƒ foo(x) {
console.log(arguments[1]);
console.log(arguments[2]);
console.log(arguments);
console.log(arguments.callee);
console.log(arguments.length);
}
*/
在 ES6
中,通过剩余项来获取参数
function foo(x, ...args) {
console.log(args);
}
foo(1,2,3); // [2, 3]
name属性
声明函数
对于声明函数,它的名称就是函数的名称。
function foo() {
console.log(foo.name); // 'foo'
}
foo();
函数表达式
对于函数表达式,函数的名称就是变量的名称
let foo = function() {
console.log(foo.name); // 'foo'
}
foo();
对象的方法
对于对象的方法,会以方法名作为名称,比较特殊的是 getter 和 setter 方法,会为他们加上 get 和 set 来标记和区分方法是 getter 还是 setter 方法。
let obj = {
get color() {},
set color(color) {},
method() {}
};
console.log(Object.getOwnPropertyDescriptor(obj, 'color').get.name); // 'get color'
console.log(Object.getOwnPropertyDescriptor(obj, 'color').set.name); // 'set color'
console.log(obj.method.name); // 'method'
bind 方法创建的函数
对于使用 bind 方法创建的函数,会在方法名前添加 bound 作为名称。
let fn = function() {};
console.log(fn.bind().name); // 'bound fn'
new Function 创建的函数
对于 new Function 方式创建的函数,它的名称是 anonymous(匿名的)
console.log(new Function().name); // 'anonymous'
实例
对于实例,可以使用构造函数来检查名称。
function Foo() {}
let foo = new Foo();
console.log(foo.constructor.name); // "Foo"
如果想通过构造函数的名称来判断是否创建可某个类,一定要注意,经过脚本压缩后,类名 Foo
可能会变成 a,这样构造函数的名称就变成了 a,而不是 Foo
,这样代码可能就会出问题。
new.target 属性
new.target
只能在实例对象中有用。
要检查函数或构造方法是否是通过 new 运算符调用过的,在 ES6
之前,最常用的方式使用 instanceof
运算符来实现,但是该方法有时候会失灵。
function Foo() {
// this = new Foo() 是实例化之后的对象
console.log(this instanceof Foo);
}
let foo = new Foo(); // true
Foo.call(foo); // true 改变 this 的指向
为了解决这个问题,在 ES6
中添加了 new.target
属性:
function Foo() {
console.log(new.target);
}
let foo = new Foo(); // [Function: Foo]
Foo.call(foo); // undefined
console.log([] instanceof Array); // true
console.log([] instanceof Object); // true 这里要注意
console.log({} instanceof Object); // true
从结果看,new.target
属性可以很清楚的区分函数或构造方法是否通过 new 元素夫来调用的。
箭头函数
不绑定 this
不使用箭头函数定义的函数都会有它的自己的 this 值,但是 this 的值稍不注意就会出现错误。
class Counter {
constructor() {
this.counter = 1;
setTimeout(function() { // 匿名函数中的 this 指向的是 window
console.log(this); // window
this.counter++;
console.log(this.counter);
}, 1000)
}
}
let counter = new Counter(); // NaN
要修正以上错误,将 this 对象转换为本地变量就行了,
class Counter {
constructor() {
let me = this;
console.log(this, typeof this); // 实例对象 counter, 'object'
me.counter = 1;
setTimeout(function() {
// console.log(this); // window 匿名函数中的 this 指向 window
me.counter++;
console.log(me.counter);
}, 1000)
}
}
let counter = new Counter(); // 2
还有一种方式就是使用 bind 方法将 this 绑定到函数,如下:
class Counter {
constructor() {
this.counter = 1;
setTimeout(function() {
this.counter++;
console.log(this.counter);
}.bind(this), 1000)
}
}
let counter = new Counter(); // 2
但是将回调函数替换为箭头函数,就不会出现这种问题,因为它会从自己的作用域链的上一层继承 this
class Counter {
constructor() {
this.counter = 1;
setTimeout(() => {
// 箭头函数使用的是外层函数中的 this
this.counter++;
console.log(this.counter);
}, 1000)
}
}
let counter = new Counter(); // 2
由于箭头函数继承了上一层的 this 指针,因此使用 call 或 apply 方法调用箭头函数并传递 this 参数时,是没有效果的。
没有 arguments 对象
在箭头函数内是没有 arguments 对象的,因此不要尝试在箭头函数内使用 arguments 对象来获取参数,如果要获取未知参数,要使用剩余参数来获取。
let fn = (x, ...y) => console.log(y[0], y[1]);
fn(1, 2, 3, 4); // 2 3
不能作为构造函数
由于箭头函数不能作为构造器,因此不能使用 new 操作符来调用,不然会抛出错误。
没有原型
箭头函数是没有原型的,
let fn = () => {};
console.log(fn.prototype); // undefined
let fn = () => {}
console.log(fn.prototype); // undefined
let fn1 = function() {}
console.log(fn1.prototype); // {constructor: ƒ}
不能作为生成器
由于在箭头函数中不能使用 yield 关键字,因而不能将箭头函数作为生成器使用。