Javascript学习---函数对象

我们已经知道Javascript里的值都有对应的类型,函数始终特殊的值,它的类型是对象


name属性

函数对象包含一些可用的对象,例如name属性

function sayHi() {
  alert("Hi");
}

alert(sayHi.name); // sayHi

显然,name属性返回函数的名字


有趣的是,函数名字的指配是灵活的,例如:

let sayHi = function() {
  alert("Hi");
}

alert(sayHi.name); // sayHi (works!)

当函数名是默认值的时候也起作用,例如:

function f(sayHi = function() {}) {
  alert(sayHi.name); // sayHi (works!)
}

f();

同样,对象的方法也有name属性,例如:

let user = {

  sayHi() {
    // ...
  },

  sayBye: function() {
    // ...
  }

}

alert(user.sayHi.name); // sayHi
alert(user.sayBye.name); // sayBye

length属性

函数的length属性返回函数参数的个数,例如:

function f1(a) {}
function f2(a, b) {}
function many(a, b, ...more) {}

alert(f1.length); // 1
alert(f2.length); // 2
alert(many.length); // 2
在这里我们可以看出,rest参数并不会被计算进去


自定义属性

除了函数的内置属性,我们可以添加自定义属性到函数中,例如添加counter属性来放回函数被调用次数:

function sayHi() {
  alert("Hi");

  // let's count how many times we run
  sayHi.counter++;
}
sayHi.counter = 0; // initial value

sayHi(); // Hi
sayHi(); // Hi

alert( `Called ${sayHi.counter} times` ); // Called 2 times
这里需要注意的是,sayHi.counter=0来指定counter的值并不意味着counter是该函数的本地变量


函数的自定属性特性有时候可以用来当做闭包使用,例如:

function makeCounter() {
  // instead of:
  // let count = 0

  function counter() {
    return counter.count++;
  };

  counter.count = 0;

  return counter;
}

let counter = makeCounter();
alert( counter() ); // 0
alert( counter() ); // 1

相比于闭包,如果count存在于外部变量中,那么外部代码将无法访问count,只有嵌套函数才可以修改它,例如:

function makeCounter() {

  function counter() {
    return counter.count++;
  };

  counter.count = 0;

  return counter;
}

let counter = makeCounter();

counter.count = 10;
alert( counter() ); // 10

命名函数表达式

先看下面两个例子:

let sayHi = function(who) {
  alert(`Hello, ${who}`);
};

现在我们为函数表达式加多一个名字,如下:

let sayHi = function func(who) {
  alert(`Hello, ${who}`);
};

对于添加的函数名字,我们不能够直接在外部调用,否则会报错,例如:

let sayHi = function func(who) {
  alert(`Hello, ${who}`);
};

sayHi("John"); // Hello, John

func("Jonh");  //error

这是因为命名函数表达式的名字(func)有以下两个特性:

(1)它只能在函数内部被引用或调用;

(2)在函数外部函数名是不可见的,如上边的例子;


那么使用命名函数表达式有什么好处呢?常见的作用是用于内部的自身调用,例如下面的例子:

let sayHi = function(who) {
  if (who) {
    alert(`Hello, ${who}`);
  } else {
    sayHi("Guest");
  }
};

这里sayHi()函数在内部调用了自身,显然这没什么问题,但是考虑一下下面这种情况:

let sayHi = function(who) {
  if (who) {
    alert(`Hello, ${who}`);
  } else {
    sayHi("Guest"); // Error: sayHi is not a function
  }
};

let welcome = sayHi;
sayHi = null;

welcome(); // Error, the nested sayHi call doesn't work any more!

很明显,sayHi的值如果发生变化的话,其内部的自身调用也要改变。为了解决这种情况,命名函数表达式的作用就很明显,如下:

let sayHi = function func(who) {
  if (who) {
    alert(`Hello, ${who}`);
  } else {
    func("Guest"); // Now all fine
  }
};

let welcome = sayHi;
sayHi = null;

welcome(); // Hello, Guest (nested call works)

这里要注意一点是,函数“内部名”为命名函数表达式所有,普通的函数声明并不具备这样的语法特性。




猜你喜欢

转载自blog.csdn.net/Blue_Sky2015/article/details/79313375
今日推荐