首页 > 学院 > 开发设计 > 正文

引用类型之Function类型

2019-11-08 18:48:31
字体:
来源:转载
供稿:网友
<!DOCTYPE html><html><head><meta charset="UTF-8"><title></title></head><body><script>Function类型:在ECMAScript中,函数实际上是对象.每个函数都是Function类型的实例,而却都与其它引用类型一样,都有属性和方法.由于函数是对象,因此函数名也是一个指向函数对象的指针./**** 定义函数的3中方式(创建函数的3种方式)* **/1.函数声明的方式function sum (num1,num2) {return num1+num2;}2.函数表达式(又叫函数字面量)var sum = function(num1,num2) {return num1 + num2;};3.Function构造函数   var sum = new Function('num1','num2','return num1+num2');     不推荐使用构造函数创建函数,因为这种方式会导致解析两次代码(一次是解析常规的ECMAScript代码,第二次是解析传入构造函数的字符串).从而影响性能    /**** 1.函数可以有多个名字*/由于函数名仅仅是指向函数的指针,因此函数名与包含对象指针的其它变量没什么不同,换句话说,函数可以有多个名字.function sum (num1,num2) {return num1 + num2}alert(sum(10,10));  //20;var anotherSum = sum;alert(anotnerSum(10,10)); //20sum=null;alert(anotnerSum(10,10)); //20/**** 没有重载* 重载: 在同一个类中,方法的名字相同,但参数个数,参数类型,或返回值类型不同* 重写: 它是子类和父类的关系,子类重写了父类的方法,但方法名,参数类型,参数个数必须相同*/function addSomeNumber(num){return num + 100;}function addSomeNumber(num){return num + 200;}var result = addSomeNumber(100); //结果为300声明了两个同名的函数,结果前面一个被后面的给覆盖了.以上代码实际上与下面的代码没区别.var addSomeNumber = function(num){return num + 100;}addSomeNumber = function(num){return num +200;}var result = addSomeNumber(100); //结果为300   在创建第二个函数的时候,实际上覆盖了引用第一个函数的变量addSomeNumber/*** *函数声明与函数表达式的区别* * 除了什么时候可以通过变量访问函数这一点区别之外,函数声明与函数表达式的语法其实是等价的。**/实际上,解析器在向执行环境中加载数据时,对函数声明和函数表达式并非一视同仁.解析器会率先读取函数声明,并使其在执行任何代码之前可用(可以访问).至于函数表达式,则必须等到解析器执行到它所在的代码行,才会被真正的解释执行. (函数声明提升);alert(sum(10,10));function sum(num1,num2){return num1 + num2;}以上代码可以正确的执行,因为在代码执行之前,解析器已经通过一个名为函数声明提升的过程,读取,并将函数添加到执行环境中.对代码求值时,javaScript引擎在第一遍会声明函数,并将它放到源代码树的顶部.所以,即使声明函数的代码放在调用它的代码之后,Javascript引擎也能把函数声明提升到顶部.sum(10,10);  //、执行错误var sum = function (num1,num2){return num1+ num2};如果把函数声明改为等价的函数表达式,就会在执行期间出错./***作为值的函数* * */因为ECMASCript中函数名本省就是变量,所以函数也可以当做值来使用. 1.做函数的参数  2.作为另一个函数的返回结果function callSomeFunction(someFunction,someArgument){return someFunction(someArgument);}function add10(num){return num + 10;}要访问函数的指针而不执行函数的话,必须去掉函数名后面的那对圆括号var  result = callSomeFunction(add10 , 10);alert(result); //10       将 对象数组按照name属性排序  var data = [{name: "Zachary", age: 28}, {name: "Nicholas", age: 29}];data.sort(createComparisonFunction("name"));alert(data[0].name); //Nicholasdata.sort(createComparisonFunction("age"));alert(data[0].name); //Zacharyfunction createComparisonFunction(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;}};}/**** * 函数内部属性 arguments和this* * */在函数内部有两个特殊的对象:arguments 和 this. arguments 是一个类数组对象,包含着传入函数的所有参数,虽然 arguments 的主要作用是保存函数参数,但这个对象还有一个叫callee的属性,该属性是一个指针,指向拥有 arguments 对象的函数(callee的作用:解耦)阶层函数:function factorial(num){if(num <=1){return 1;}else{return num* factorial(num -1);}}函数可以正常执行,但是问题在于这个函数的执行与函数名 factorial紧紧的耦合在一起,我们可以利用  callee 解耦function factorial(num){if(num < 1){return 1;}else{return num * arguments.callee(num-1);}}这样就可以保证 无论引用函数时使用的是什么名子,都可以保证正常完成递归调用.var trueFactorial = factorial;factorial = function(){return 0;};alert(trueFactorial(5)); //120alert(factorial(5));   //01.案例1function factorial(num){if(num < 1){return 1;}else{return num * arguments.callee(num-1);}}var trueFactorial = factorial;  //我的理解是  这行代码重新定义了一个函数 trueFactorial 说以trueFactorial的toString方法会返上面的那个函数factorial = function(){return 0;};alert(trueFactorial(5));  //120alert(factorial(5)); //02.案例2function factorial(num){if(num < 1){return 1;}else{return num * arguments.callee(num-1);}}factorial = function(){return 0;};var trueFactorial = factorial;  alert(trueFactorial(5));  //0alert(factorial(5)); //03.案例3function factorial(num){if(num < 1){return 1;}else{return factorial * factorial(num-1);}}var trueFactorial = factorial;factorial = function(){return 0;};alert(trueFactorial(5)); // NaNalert(factorial(5));    // 04.案例4function factorial(num){if(num < 1){return 1;}else{return factorial * factorial(num-1);}}factorial = function(){return 0;};var trueFactorial = factorial;alert(trueFactorial(5));  // 0alert(factorial(5));      // 0// this  引用的是函数执行环境的对象,(当在网页的全局作用域中调用函数时,this引用的就是window)/*** *函数对象属性 caller* **/ECMAScript5也规范了另外一个函数对象的属性:caller.caller : 这个属性保存着调用当前函数的函数的引用,如果在全局作用域中调用当前函数,它的值为nullfunction outer(){inner();}function inner(){alert(inner().caller);}outer();弹框显示outer函数的源码,因为outer调用了inner,所以inner.caller指向outer();为了实现更松散的耦合,也可以通过 arguments.callee.caller来访问相同的信息function outer(){inner();}function inner(){alert(arguments.callee.caller);}outer();注意:  1.在严格模式下  arguments.callee会报错   2.在严格模式下 arguments.caller 会报错    在非严格模式下 为 undefined,ECMAscript定义 arguments.caller 是为了区分和函数的caller属性 /*** * 函数内部属性和方法* 属性:length,prototype* 方法:call,apply* * **/length: 该属性表示函数的参数prototype: 我们创建的每一个函数都有一个prototype(原型)属性,该属性是一个指针,指向一个对象,这个对象包含着特定类型的所有实例共享的属性和方法.使用原型的好处是,可以让所有实例共享它包含的属性和方法.换句话说就是不必在构造函数中定义对象实例的信息,而是可以将这些信息直接添加到原型对象中.function Person(){}Person.prototype.name = 'Nichollas';Person.prototype.age = 29;Person.prototype.job = 'Software Enginner';Person.prototype.sayName = function(){alert(this.name);}var person1 = new Person();person1.sayName(); //Nicholas"var person2 = new Person();person2.sayName(); // Nicholas"alert(person1.sayName() == person2.sayName()); //true注: 对于ECMAScript5中的引用类型而言,prototype是保存它们所有实例方法的真正所在.换句话说,诸如 toString()和valueOf()等方法,实际上都保存在prototype名下,只不过是通过各自对象的实例访问罢了.在创建自定义引用类型以及实现. prototype属性是不可枚举的,因此使用 for-in 无法发现.// call apply方法: 每个函数都包含两个非继承而来的方法: call和apply.  作用 : 在特定的作用域中调用函数,实际上等于设置函数体内this对象的值(扩充函数赖以运行的作用域)apply方法: 接受两个参数,一个是在其中运行函数的作用域,另一个是参数数组. 第二个参数可以是 Array 的实例,也可以是  arguments 对象function sum (num1, num2){return sum1 + sum2;}function callSum1(num1,num2){sum.apply(this,[num1,num2])  //传入数组}function callSum2(num1,num2){sum.apply(this,arguments)  //传入 arguments 对象}alert(callSum1(10,10)); //20alert(callSum2(10,10)); // 20call方法: call方法的作用与apply相同,区别在于接受参数的方式不同,第一个是this值没变化,变化的是其余的参数都直接传递给函数(一一列举出来)function sum(num1 ,num2){return sum1+sum2;}function callSum(num1,num2){return sum.call(this,num1,num2);}alert(callSum(10,10));  // 20事实上传递参数并非call()和apply()真正的用武之地,他们强大的地方在于能够扩充函数赖以运行的作用域.window.color= 'red';var o ={'color':'blue'};function sayColor(){aletr(this.color);}sayColor() ; // redsayColor.call(this) //redsayColor.call(window) // thissayColor.call(o);  // blue// ECMASCript5 还定义了一个方法bind()bind()方法会创建一个函数的实例,其this值会被绑定到传给bind函数的值.window.color = 'red';var color = 'blue';function sayColor(){alert(this.color);}var objectSayColor = sayColor.bind(o);objectSayColor(); //blue在这里,sayColor()调用bind()并传入对象 o,创建了objectSayColor函数. objectSayColor()函数的this值就等于 o,因此即使在全局函数作用域中调用这个函数 ,也会看到'blue'</script></body></html>
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表