今天翻看红宝书看到了一些函数中的属性。
- arguments大家很熟悉,一个类数组对象,包含调用函数时传入的所有参数,这个对象只有以function关键字定义函数才会有。但是arguments里面还有一个callee属性,指向了arguments对象所在函数的指针。书中举了一个例子。
js
// 写法1
function factorialA(num) {
if (num <= 1) {
return 1
} else {
return num * factorial(num - 1)
}
}
以上代码可以改写成:
js
// 写法2
function factorialB(num) {
if (num <= 1) {
return 1
} else {
//改写成如下,这可以让函数逻辑与函数名解耦
return num * arguments.callee(num - 1)
}
}
使用场景: 以下代码trueFactorial被赋值为factorialA,实际将同一个函数的指针保存到另外一个位置,然后factorialA又被重写成一个返回0的函数。此时会发生以下情况:
基于上述写法1:
js
let trueFactorial = factorialA
factorialA = function () {
return 0
}
console.log(trueFactorial(6)) // 0
console.log(factorialA(6)) // 0
基于上述写法2:
js
let trueFactorial = factorialB
factorialB = function () {
return 0
}
console.log(trueFactorial(6)) // 120
console.log(factorialB(6)) // 0
- this,在标准函数中引用的是把函数当成方法调用的上下文对象。 定义在全局上下文中的函数sayColor引用了this对象,这个this对象引用哪个对象必须到函数被调用时才能确定。如下面的代码,全局定义的sayColor函数和o.sayColor是同一个函数,只不过执行上下文不同:
js
window.color = 'red';
let o = {
color: 'blue'
}
function sayColor() {
console.log(this.color)
}
// 全局上下文调用,此时this指向window,this.color === window.color
sayColor() // 'red'
o.sayColor = sayColor()
// this指向o
o.sayColor() // 'blue'
某些情况下就会有问题,如:
js
window.name = 'window'
function King() {
this.name = 'Henry';
setTimeout(function () { console.log(this.name) }, 1000)
}
new King() // 'window'
发现上述代码的定时器没有指向想要的对象,可以通过箭头函数解决此问题,这是因为箭头函数的this会保留定义该函数时的上下文:
js
function King() {
this.name = 'Henry';
setTimeout(() => console.log(this.name), 1000)
}
new King() // 'Henry'
- caller,这个属性指向的是调用当前函数的函数。 以下代码会显示outer函数的源码
js
function outer() {
inner()
}
function inner() {
console.log(inner.caller)
}
console.log(outer()) // ƒ outer() { inner() }
- new.target,ECMAScript中的函数始终可以作为构造函数实例化一个新对象也可以作为普通函数被调用。ES6新增new.target检测函数是否使用new关键字调用。如果普通函数调用new.target的值是undefined,如果是new关键字调用,则new.target将引用被调用的函数。
js
function King() {
if (!new.target) {
throw 'King must be instantiated using "new"'
}
console.log('King instantiated using "new"')
}
new King(); // 'King instantiated using "new"'
King(); // 'King must be instantiated using "new"'
这个有啥用呢?我们可以使用new.target定义一个不能被实例化的抽象基类,我们不希望Vehicle被实例化,如下:
js
class Vehicle {
constructor() {
if (new.target === Vehicle) {
throw new Error('Vehicle cannot be directly instantiated')
}
}
}
class Bus extends Vehicle { }
new Bus() // 正常
new Vehicle() // Error:Vehicle cannot be directly instantiated
-
length和name,length属性保存函数定义的命名参数的个数。如:
jsfunction sayName(name) { console.log(name) } function sum(num1, num2) { return num1 + num2 } function sayHi() { console.log("hi") } console.log(sayName.length) // 1 console.log(sum.length) // 2 console.log(sayHi.length) // 0
name 属性保存的是 Function 实例的
name
数据属性表示函数在创建时指定的名称,或者如果函数是匿名函数,则名称可以是anonymous
或''
,如:jsconst func1 = function () {}; const object = { func2: function () {}, }; console.log(func1.name); // "func1" console.log(object.func2.name); // "func2" //并且函数的name属性是只读的,不能用赋值运算符修改,但可以使用Object.defineProperty()改变。 function someFunction() {} someFunction.name = "otherFunction"; console.log(someFunction.name); // someFunction