@15152278073
2018-03-28T06:37:45.000000Z
字数 1899
阅读 499
JS
说起来ECMAScript中什么最有意思,莫过于函数了----而有意思的根源,在于函数实际上是对象.每个函数都是Function的实例,而且与其他引用类型一样具有属性和方法.由于函数是对象,所以函数名实际上是一个指向函数的指针,不会与某个函数绑定.
//函数的声明function sum(num1 , num2){return num1 + num2;}//与上面类似的声明var sum = function(num1 , num2){return num1 + num2;};//使用Function构造函数//不推荐var sum = new Function("num1","num2","return num1 + num2;")
将函数名想象成指针,有助于理解JS为什么没有重载的概念.同名的函数,后面声明的会覆盖前面声明的函数.
因为函数名本身就是变量,所以函数可以作为值来使用.函数不仅可以作为传递参数也可以作为函数的结果返回.
在函数内部,有两个特殊对象:arguments和this.
arguments是一个类数组对象,包含着传入的所有参数.虽然arguments的主要用途是保存函数参数,但这个对象还有一个名叫callee的属性,该属性是一个指针,指向arguments对象的函数.
function factorial(num){if(num <= 1) return 1;else return num * factorial(num-1);}
以上方法如果函数名factorial,则无法得到正确的结果,所以可以这样修改:
//消除函数名的耦合function factorial(num){if(num <= 1) return 1;else return num * arguments.callee(num -1)}//测试var trueFunc = factorial;factorial = function(){ return 0; };console.log(trueFunc(5)) //120console.log(factorial(5)) //0
函数内部另一个特殊对象是this.this引用的是函数据以执行的环境对象----或者说是this的值.(全局作用域是window对象).
//thiswindow.color = 'red';var o = {color:'blue'};function sayColor(){return console.log(this.color);}sayColor() //redo.sayColor = sayColor;o.sayColor() //blue
注意:函数的名字只是一个包含指针的变量而已.因此,即使在不同的执行环境中,全局的
sayColor()函数与o.sayColor指向的仍是同一个函数.
JS中的函数是对象,所以函数也有属性和方法.每个函数包含两个属性:length和prototype.
length属性表示函数希望接收的命名参数个数.
prototype是保存他们所有的实例方法的真正所在.在JS中,prototype是不可枚举的,所以for-in无法发现.
每个函数包含两个非继承而来的方法apply()和call().这两个方法都是在特定的作用域中调用函数,实际上是设置this的对象的值.不同的地方在于,apply()接收两个参数,一个是作用域对象,另一个是参数数组(可以是Array也可以是arguments).call()第一个参数是作用域对象,之后的参数直接传递给函数.
//call//function.call(thisArg, arg1, arg2, ...)sayColor.call(null) //redsayColor.call(window) //redsayColor.call(o) //blue//apply//function.apply(thisArg, [argsArray])sayColor.apply(null) //redsayColor.apply(window) //redsayColor.apply(o) //blue
还有一个方法:bind().这个方法会创建一个函数实例.其this值会绑定到传给函数的值.
//bindvar objSayColor = sayColor.bind(o);//do some thingconsole.log("======")objSayColor() //blue
注意:
bind()返回的是函数,所以可以延迟调用,而call()和apply()是立即执行的.
参考: