标签:style oms 表示 函数名 对象属性 而不是 对象 表示法 环境
一、函数类型
1.1 在JS中,每个函数都是Function类型的实例。而且都与其他类型一样,具有属性和方法。由于函数是对象,因此函数名实际上也是一个指向函数对象的指针。不会与某个函数绑定,函数通常是使用函数声明语法定义的(函数声明)。
function sum(num1,num2){ return num1 + num2 }
这与下面函数表达式声明的方式相差无几(函数表达式声明)
var sum = function(sum1,sum2){ return num1 + num2 }
在使用函数表达式声明函数时,没有必要使用函数名,如上所示,通过变量sum即可引用函数。
最后一种定义函数的方法是Function构造函数,Function构造函数可以接收任意数量的参数,但最后一个参数始终被看成是函数体,而前面的参数则枚举出了新函数的参数。如下
var sum = new Function("num1","num2","return num1 + num2");//不推荐
从技术上来讲,这的确是一个函数表达式,但是不推荐这样做,因为这种语法会导致解析两次代码。
函数是对象,函数名是指针。由于函数名仅仅是指向函数的指针,因此函数名与包含对象指针的变量没有什么不同。换句话说,一个函数可能会有多个名字。
function sum(num1,num2){ return num1 + num2 ; } alert(sum(10,10))//20 var anthorSum = sum; alert(anthorSum(10,10))//20 sum = null; alert(anthorSum(10,10))//20
以上代码首先定义了一个名为sum()的函数,然后,又声明变量anthorSum,并将其设置为与sum相等,(注意:使用不带圆括号的函数名是访问函数指针,而非调用函数。)此时anthorSum与sum都指向了同一个函数,所以即使将sum设置为null,仍然可以正常调用anthorSum。
1.2 没有重载
将函数名想象成指针,也有助于理解为什么js中没有函数重载这个概念。
function addSum(num1){ return num1 + 100 } function addSum(num1){ return num1 + 200 } var result = addSum(100) //300
这个例子声明了两个同名函数,结果是后面的函数覆盖了前面的函数。以上代码实际上与下面代码没什么区别
var addSum = function (num1){ return num1 + 100 } addSum = function (num1){ return num1 + 200 } var result = addSum(100) //300
由上可以知道,在创建第二个函数的时候,实际上覆盖了引用第一个函数的变量。
1.3 函数声明与函数表达式
实际上,解析器在执行环境中加载数据时,对函数声明和函数表达式并非一视同仁,解析器会率先读取函数声明,并使其在执行任何代码之前可用。至于函数表达式,则必须等到解析器执行到它所在的代码行,才会真正被解析执行。
alert(sum(10,10))//20 function sum(num1,num2){ return num1 + num2; }
以上代码完全可以正常运行,因为在代码开始执行之前,解析器就通过一个名为函数声明提升的过程,读取并将函数声明添加到执行环境中。对代码求值时,js引擎在第一遍会声明函数并将其放在源代码树的顶部。所以即使声明函数的代码在调用它的代码之后,js引擎也能把函数声明提升到顶部。如果将函数声明改成等价的函数表达式时,会在执行期间导致报错
alert(sum(10,10)) var sum = function (num1,num2){ return num1 + num2; }
以上代码会报错的原因在于函数位于一个初始化的语句中,而不是一个函数声明。换句话说,在执行到函数的语句之前,变量sum不会保存有对函数的引用;而且,由于第一行代码会报错,实际上也不会执行到下一行。
也可以同时使用函数声明和函数表达式
var sum = function sum(){}
1.4 作为值的函数
因为js中函数名本身就是变量,所以函数可以直接作为值来使用。也就是说,不仅可以像传递参数一样把一个函数传递给另一个函数,而且可以将函数作为另一个函数的结果返回。
function callSomeFunction(someFunction,someArgument){ return someFunction(someArgument); }
这个函数接收两个参数,第一个参数是一个函数,第二个参数是传递给该函数的一个值,然后就可以像下面的例子一样传递函数了
function add10(num){ return num + 10; } var result1 = callsomeFunction(add10,10); alert(result1) //20 function getGreeting(name){ return ‘hello‘ + name } var result2 = callsomeFunction(getGreeting,‘Toms‘); alert(result2) // hello,Toms
这里的callsomeFunction函数是同用的,即无论第一个参数值传递进来的是什么函数,它都会返回执行第一个参数后的结果,要访问函数的指针而不执行函数的话,就不要带后面的两个圆括号。因此上面函数传递的是add10和getGreeting,而不是他们的函数返回结果。
当然,可以从一个函数中返回另一个函数。例如,假设有一个对象数组,我们想要根据某个对象属性对数组进行排序,而传递给数组sort()方法的比较函数要接收两个参数,即要比较的值。可是,我们需要一种方式来指明按照哪个属性来排序。要解决这个问题,可以定义一个函数。它接收一个属性名,然后根据这个属性名来创建一个比较函数。下面就是这个函数的定义
function cereteComparisonFunction(propertyName){ return function(object1,object2){ var value1 = object1[propertyName]; var value2 = object2[propertyName]; if(value1 < value2){ return -1; } else if (value1 > value2){ return 1; } else{ return 0; } }; }
这个函数看起来有些复杂,但实际上无非就是一个函数中嵌套了另一个函数,而且内部函数前面加了一个return操作符,在内部函数接收到propertyName参数后,它会使用方括号表示法来取得给定属性的值,取得了想要的属性值之后,定义比较函数就非常简单了。上面这个函数可以向下面例子这样使用
var data = [{name: "Zachary",age:28},{name:"Nicholas",age:29}]; data.sort(createComparisonFunction("name")); alert(data(0).name); //Nicholas data.sort(createComparisonFunction("age")); alert(data(0).name); //Zachary
这里,我们创建了一个包含两个对象的数组,每个对象都包含了一个name属性和age属性,在默认情况下,sort方法会调用每个对象的toString()方法以确定他们的顺序,但得到的结果往往并不符合人类的思维习惯。因此,我们调用createComarsionFunction("age")方法返回的比较函数,这个是按照对象的age属性进行排序。
1.5 函数内部属性
在函数内部,有两个特殊的对象,arguments和this,其中,arguments是一个类数组对象,包含传入函数的所有参数,虽然arguments的主要用途是用来保存函数参数,但这个对象还有一个名叫callee的属性,该属性是一个指针,执向拥有这个arguments对象的函数
function factorial(num){ if(num <= 1) { return 1; } else { return num * factorial(n - 1) } }
定义阶乘函数一般都会用到递归算法,如上所示,在函数有名字,而且名字以后也不会变得情况下,这样定义时没有问题的,但问题是这个函数的执行与函数名factorial紧紧耦合在了一起,为了消除这种紧密耦合的现象,可以像下面这样使用arguments.callee。
function factorial(num){ if(num <= 1) { return 1; } else { return num * arguments.callee(n - 1) } }
在这个重写后的函数中,没有引用到函数名,这样,无论函数使用什么名字,都能正常的完成递归调用。
var trueFactorial = factorial; factorial = function(){ return 0 ; } alert(trueFactorial(5)) //120 factorial(5) //0
在此,变量trueFactoraial获得了factorial的值,实际上是在另一个位置保存了函数的指针,然后,我们又将一个简单的返回0的函数赋值给factorial变量,如果像原来的factorial()那样,不使用arguments.callee(),调用trueFactorial()就会返回0,可是,在解除了函数体内的代码与函数名的耦合状态后,trueFactorial()仍然能够正常的返回阶乘,至于factorial(),他现在只是一个返回0 的函数。
函数内部的另一个特殊对象是this,this引用的是函数据以执行的环境对象,或者也可以说是this值(当在网页的全局作用域调用函数时,this对象引用的就是window)。
window.color = "red"; var o = {color:"blue"}; function sayColor(){ alert(this.color); } sayColor(); //red o.sayColor = sayColor(); o.sayColor(); //blue
标签:style oms 表示 函数名 对象属性 而不是 对象 表示法 环境
原文地址:https://www.cnblogs.com/yu-lin/p/9217143.html