函数定义、函数属性和方法
2016-02-04 09:43
204 查看
函数
函数是定义一次但却可以调用或执行任意多次的一段js代码。通过函数可以封装任意多条语句,而且可以在任何地方任何时候调用执行。函数本身没有运行功能,必须被调用才可以执行。
function fn() {//函数声明 console.log("我只有被调用才可以执行!"); } fn(); //调用
一、 函数定义
1、函数声明(常用方式):
ECMAScript中的函数使用function关键字来声明,后跟一组参数以及函数体.语法如下:
function functionName(arg0, arg1,,, aegN() { statements(声明,表现); } //括号结束位置不能有分号
示例:
function sayHi(name,message) { alert("hello" + name + message); }
函数会在return语句执行完之后停止并立即退出.因此,位于return语句之后的代码永远都不会执行!
function sayHi(name,message) { return name + message; alert("hello"); //不会执行 }
2、 函数表达式
2.1、函数表达式
var test = function 函数名称(参数) { 函数体 }; //括号结束位置必须有分号
2.2、 构造函数(不推荐使用)
构造函数从技术角度来讲,也是一个函数表达式。构造函数,这种语法会导致解析两次代码(第一次是解析常规ECMAScript代码,第二次是解析传入构造函数中的字符串),从而影响性能。
var test = new Function("num1", "num2", "num3", "num4"); var sayHi = new Function("sName", "sMessage", "alert('Hello ' + sName + sMessage);"); sayHi("jzj,", "你好!");//Hello jzj,你好!
2.3、立即调用函数
新建作用域,防变量污染【养成使用立即调用函数的好习惯!!】方式一: (function() { console.log(1); }()); //1 空括号在里面 (function(x,y) { console.log(x*y); //6 }(2,3)); 方式二: (function() { console.log(2); })(); //2 空括号在外面
此处不加括号会报错(语法上的错误).只能用一次
其他方式详见:《function与感叹号、一元操作符》
二、return返回值
函数会在执行完return语句之后停止并立即退出。因此,位于return语句之后的任何代码永远都不会执行。注意与break的区别:break只能用在循环和switch分支语句中。function fn() { return 234; return 78; //永远不会执行 console.log("hi"); //永远不会执行 } fn();
推荐的做法是要么让函数始终都返回一个值,要么永远都不要返回值。否则,如果函数有时候返回值,有时候又不返回值,会给调试代码带来不便。
三、参数
1、理解参数
ECMAScript函数不介意传入多少个参数,也不介意传入的参数是什么数据类型.即:即使定义了两个参数,在传入的时候,也可以传入一个,或三个甚至不传.原因是ECMAScript中的参数在内部是用一个数组表示的.函数接收到的始终是这个数组,而不关心数组中包含哪些参数.没有传递值的命名参数,它的值将被自动赋予undefined值.
2、arguments对象
在函数体内可以通过arguments对象来访问这个参数数组,从而获取传递给函数的每个参数.arguments对象只是与数组类似(并不是Array实例无关),arguments[INDEX]来回去参数的值(不显示地使用命名参数)。示例:
function sayHi() { alert("hello" + arguments[0] + arguments[1]); //返回hello+传入参数的第一个和第二个 }
2.1、arguments有length属性,返回传入参数的个数.例如:
例: function fn() { var marks = 0; for(var i = 0; i < arguments.length; i++) { marks += arguments[i]; } return marks; } console.log(fn(1,3));
2.2、arguments对象也可以和命名参数一起使用.
argument对象的长度是有传入的参数个数决定的,不是有定义函数是的命名函数的个数决定的.例如:
function sayHi(name,message) { if(arguments == 1) { alert(name + "hello"); } else if(argument == 2) { alert(name + message) } } sayHi("w"); //whello sayHi("he","1"); //he2
name和arguments[0]的值相同,因此可以互换使用(message和arguments[1]也是如此).
2.3、argument[INDEX]和命名参数区别
它们的内存空间是独立的,但它们的值会同步.四、重载
ECMAScript中的函数,没有像其他高级语言那种函数重载功能。因此如果出现同名的函数则后声明的函数将前面的函数覆盖掉。所谓重载功能:即可以为一个函数编写两个定义,只要这两个定义的签名(接收的参数的类型和数量)不同即可。
例: function fn(x) { return x + 100; } function fn(x) { return x + 200; } //覆盖前面同名函数 console.log(fn(1)); //201
五、函数声明式和函数表达式
函数声明和函数表达式的区别:解析器会率先读取函数声明,并使其在执行任何代码之前可用(可访问);而函数表达式,则必须等到解析器执行到它所在的代码行,才会真正被执行。
六、函数作为返回值
function createComparisonFn(params) { //传入对象属性的名称 return function(obj1, obj2) { //obj1和obj2为数组的项 var val1 = obj1[params]; //获取对象属性值 var val2 = obj2[params]; if(val1 > val2) { return 1; } else if(val1 < val2) { return -1; } else { return 0; } } }
var arr = [{name: “zhangsan”, age: 12}, {name: “lis”, age: 38}, {name: “wanger”, age: 32}];
console.log(arr.sort(createComparisonFn(“age”))); //按age升序排列
console.log(arr); //按age升序排列
根据对象age属性进行排序。//sort()方法的比较函数接收两个参数,即要比较的值。
七、函数内部属性(arguments和this对象、caller属性)
在函数内部,有两个特殊的对象:arguments; 保存函数的参数。arguments.callee指向有这个arguments对象的函数。
this; 指向函数据以执行的环境对象。
函数对象的属性:
caller。指向调用当前函数的函数(即当前函数的调用者)。
1、arguments
arguments的主要用途是保存函数参数,这个对象还有一个名叫 callee 的属性,该属性是一个指针,指向拥有这个 arguments 对象的函数。var fn = function(num) { if(num <= 1) { return 1; } else { return num * fn(num - 1); } }; var total = fn; console.log(total(3)); //6 fn = function() { return 1000; }; console.log(total(3)); //3000 首先调用第一个fn进入第一个fn方法体内,return的时候3 * fn()调用的是第二个fn
定义阶乘函数一般都要用到递归算法;如上面的代码所示,在函数有名字,而且名字以后也不会变
的情况下,这样定义没有问题。但问题是这个函数的执行与函数名 factorial 紧紧耦合在了一起。为
了消除这种紧密耦合的现象,可以像下面这样使用 arguments.callee。
var fn = function(num) { if(num <= 1) { return 1; } else { return num * arguments.callee(num - 1); } }; var total = fn; console.log(total(3)); //6 fn = function() { return 1000; }; console.log(total(3)); //6 var fn = function(num) { console.log(arguments.callee); }; var total = fn; fn(); //function(num);——指向第一个fn total(); //function(num);——指向第一个fn fn = function(a) { console.log(arguments.callee); }; fn(); //function();——指向第二个fn total(); //function(num);——指向第一个fn
2、this
函数内部的另一个特殊对象是this。this引用的是函数据以执行的环境对象——或者也可以说是this 值(当在网页的全局作用域中调用函数时,this 对象引用的就是 window。因为定义在全局中的所有变量或函数都是window对象的属性)。color = "red"; //定义在全局中的变量 var obj = {color: "blue"}; var fn = function() { console.log(this.color); }; obj.foo = fn; fn(); //red obj.foo(); //blue
由于在调用函数之前,this的值并不确定,因此this可能会在代码执行过程中引用不同的对象。
【注意:】函数的名字仅仅是一个包含指针的变量而已。因此,即使是在不同的环境中执行,全局的fn函数与obj.foo()指向的任然是同一个函数。
3、caller
这个属性中保存着调用当前函数的函数的引用(即当前函数的调用者),如果是在全局作用域中调用当前函数,它的值为 null。
window.onload = function() { var obj = {color: "blue"}; var fn = function() { console.log(fn.caller); //指向调用当前函数的函数的引用 }; var fn1 = function() { fn(); }; fn(); //window.onload调用的fn,因此指向window.onload; fn1(); //fn1调用的fn,因此指向fn1 }; var fn = function() { //定义在全局中的函数fn console.log(fn.caller); //指向调用当前函数的函数的引用 }; fn(); //null
为了实现更松散的耦合,也可以通过 arguments.callee.caller
来访问相同的信息。
var fn = function() {
console.log(arguments.callee.caller); //指向调用当前函数的函数的引用
};
当函数在严格模式下运行时,访问 arguments.callee 会导致错误。ECMAScript 5 还定义了
arguments.caller 属性,但在严格模式下访问它也会导致错误,而在非严格模式下这个属性始终是
undefined。定义这个属性是为了分清 arguments.caller 和函数的 caller 属性。以上变化都是为
了加强这门语言的安全性,这样第三方代码就不能在相同的环境里窥视其他代码了。
严格模式还有一个限制:不能为函数的 caller 属性赋值,否则会导致错误。
八、函数属性和方法
每个函数都包括两个属性:length和prototype。- length属性表示函数希望接收的命名参数的个数(即函数定义的形式参数的个数)。
- prototype属性;
1、length属性
var fn = function() { return ; }; var fn1 = function(a) { return a; }; var fn2 = function(a, b) { return a+b; }; console.log(fn.length); //0 console.log(fn1.length); //1 console.log(fn2.length); //2
2、prototype属性
在 ECMAScript 5中,prototype 属性是不可枚举的,因此使用 for-in 无法发现。3、apply()、call()和bind()方法
每个函数都包含两个非继承而来的方法:apply()和 call()。这两个方法的用途都是在特定的作用域中调用函数,实际上等于设置函数体内this对象的值。
- apply(); 接收两个参数:一个是在其中运行函数的作用域,另一个是参数数组。其中,第二个参数可以是Array的实例,也可以是arguments对象。
- call(); 与apply方法作用相同,唯一不同的是除了第一个参数,其他参数都必须一一罗列出来。
- bind(); 绑定传入this的值
3.1、apply()
var count = function(a, b) { return a + b; }; var fn1 = function(a, b) { return count.apply(this, arguments); }; var fn2 = function(a, b) { return count.apply(this, [a, b]); }; var fn3 = function() { return count.apply(this, [10, 10]); }; console.log(fn1(10, 10)); console.log(fn2(10, 10)); console.log(fn3());
3.2、call()
call()方法与 apply()方法的作用相同,它们的区别仅在于接收参数的方式不同。var count = function(a, b) { return a + b; }; var fn1 = function(a, b) { return count.call(this, a, b); }; console.log(fn1(10, 10)); //20
事实上,传递参数并非 apply()和 call()真正的用武之地;它们真正强大的地方是能够**扩充函数
赖以运行的作用域**。如下:
color = "red"; //定义在全局中的变量 var obj = {color: "blue"}; var fn = function() { console.log(this.color); }; fn(); //red fn.call(obj); //blue
前两个都是显示地在全局作用域中调用函数的方式,因此结果返回“red”。而fn.call(obj)将执行环境指向了obj,因此返回“blue”。在前面的例子中,先将obj对象的foo指向fn,在通过obj来调用它的,而在这个例子中就简化了许多。
使用call()或apply()来扩充作用域的最大好处就是:对象不需要与方法有任何耦合关系。
3.3、bind()
ECMAScript 5还定义了一个方法:bind()。这个方法会创建一个函数的实例,其 this 值会被绑定到传给 bind()函数的值。
color = "red"; //定义在全局中的变量 var obj = {color: "blue"}; var fn = function() { console.log(this.color); }; fn(); //red var foo = fn.bind(obj); foo(); //blue
//这种技巧的优点请参考第 22章。
支持 bind()方法的浏览器有 IE9+、Firefox 4+、Safari 5.1+、Opera 12+和 Chrome。
4、toString()、toLocaleString()和valueOf()方法
toString()toLocaleString()
valueOf()
始终返回函数方法体。返回代码的格式则因浏览器而异——有的返回的代码与源代码中的函数代码一样,而有的则返回函数代码的内部表示,即由解析器删除了注释并对某些代码作了改动后的代码。
相关文章推荐
- SQL Server 诊断查询-(4)
- Mysql coalesce()函数认识和用法
- MySQL中事务的概述ACID了解
- Python-一张图
- Spring动态对Quartz定时任务的管理,实现动态加载,停止的配置实例代码
- Icinga2监控web、mysql状态
- Android自定义图片集合
- dsplib->cfft
- 聊一聊MD5
- java数据库编程——事务
- Apache添加多端口
- DWR3.0框架入门(1) —— 实现ajax
- 安卓自己定义对话框及The specified child already has a child问题
- 在Github上搭建自己的博客(Windows平台)
- 最简明扼要的 Systemd 教程,只需十分钟
- linux 命令 more
- SQL Server 诊断查询-(5)
- radosgw单机多实例
- python 对象拷贝, 值相同,同一对象的区别
- Redis java操作