JavaScript 之函数
刚开 始学习 JS 时,挺不习惯它函数的用法,就比如一个 function 里面会嵌套一个 function,对于函数里创建变量的作用域也感到很迷惑,这个的语法和 JAVA 相差太多,为此,阅读了《JavaScript高级程序设计》这本书里的相关内容,在 Google 查 阅相关资料,并在此做个总结
函数的创建
// 这是最普通的创建方法
function sum(sum1,sum2){
return num1+num2;
}
// 将函数赋值给一个变量,需要这样调用 sum(10,10)
var sum = function(num1,num2){
return num1 + num2;
};
// 利用这种方式创建的函数阅读性差
// 不推荐使用这种方法
var sum = new Function("num1","num2","return num1 + num2");
参数
说到函数,第一个不可避免的话题就是参数了。在 JS 中,函数对于参数的传递方法和 JAVA 相差无几,都是通过复制变量值的方法来进行传递的。变量一般分为基本变量(Boolean、int 等类型)和引用变量(对象)。基本变量的复制是直接将值复制给对应的变量,而引用变量的复制是将变量的地址复制给对应的变量,接下来这两个例子有助于理解。
// 在这个例子中,changeNumber 接收一个 args 变量,这个变量是一个基本类型
// 然后在函数中对 args 进行修改,最后查看这次修改会不会影响外部 num 的值
// 从结果可知,参数对于基本类型的复制仅仅是对它的值进行复制,不会对原来的值进行修改
var num = 9;
function changeNumber(args){
args = 8;
}
changeNumber(num);
alert(num); // 结果为 9
// 在这个例子中,我们传入的参数是一个 Array 对象
// 修改 Array 第一个元素的值,查看是否会影响外部的 Array
// 通过结果我们可以看到,对外部的 Array 会产生影响。
var array = new Array();
array[0] = 9;
function changeArray(arr){
arr[0] = 8;
}
changeArray(array);
alert(array[0]); // 结果为 8
函数是个对象
在 JAVA 中,经常听到是一句话便是:“在 JAVA 的世界里,无处不对象”,在 JS 中,这句话也是成立的。那么函数是否也是一个对象呢?答案是肯定的。作为一个对象,应该具备独立的属性和方法,接下来就介绍下 Function 这个对象的属性与方法。
this 属性
this 是 JavaScript 中的一个关键字。
它代表函数运行时,自动生成的一个内部对象,只能在函数内部使用。由于函数使用的场合不同,this 代表的对象不同,但是有一个总的原则,那就是 this 指的是调用这个函数的那个对象。
借助例子我们可以更好的理解这个概念var name = "window"; function getName(){ var name = "function"; alert(this.name); } getName(); // 结果为 windowarguments 属性
在 JS 的函数中,对于传入参数的个数和类型都是不做限制的,这样显得有点无拘无束了,那么,它是怎么做到这一点的呢? arguments 起了很大的作用。arguments 是一个类似 Array 的对象,它包含了函数中传入的所有参数,我们可以通过 arguments[i] 的方式来访问指定位置的参数。function add(num1,num2){ alert(arguments[0]+arguments[1]); } add(1,2); // 结果为 3arguments除了这个功能之外,还有一个重要的方法:callee,该属性指向函数对象,我们可以借助一下这个例子感受下 callee 的作用,也可以顺便理解一下这句话:“函数是一个对象,函数名是指针”
// 首先,这是一个递归函数 function factorial(num){ if(num<=1){ return 1; }else{ return num * factorial(num-1); } } // 调用过程把 factorial 置为 null var trueFactorial = factorial(10); factorial = function(){ return 0; } alert(trueFactorial(5)); // 结果为 120 alert(factorial(5)); // 结果为 0 // 从中我们可以看出,factorial 是一个指向函数的指针 // 因此 var trueFactorial = factorial(10)是把函数地址赋予 trueFactorial // 当 factorial 函数改变了内容之后,trueFactorial 指向的地址并不会受到影响 // 这样的写法有可能会使结果出错,而且难免会使函数名和函数产生耦合 // 这时 callee 就派上用场了 function factorial(num){ if(num<=1){ return 1; }else{ return num*arguments.callee(num-1); } }思考:
通过上面的例子,我们也应该思考下在 JS 中是否有重载这个概念呢?
- prototype 属性
我们创建的每个函数都有一个 prototype(原型)属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。如下面的例子:
``` javascript
function Person(){}
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
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
```
当创建了一个函数之后,就会根据一组特定的规则为该函数创建一个 prototype 属性,这个属性指向原型对象。默认情况下,所有原型对象都会自动会的一个 construct(构造函数)属性,这个属性包含一个指向 prototype 属性所在函数的指针。当创建一个实例之后,这个实例会存在一个指向构造函数的指针,我们称这个指针为[[Prototype]]。我们可以通过下面的关系图来理解这段话:
虽然存在着 [[Prototype]] 这个指针,但是我们并不能访问它,不过我们可通过 isPrototypeOf 来确定对象之间是否存在这种关系。
alert(Person.prototype.isPrototypeOf(person1)); // true
alert(Person.prototype.isPrototypeOf(person2)); // true
在 ECMAScipt 5 增加了一个新方法,叫 Object.getPrototypeOf,这个方法返回[[Prototype]] 的值。例如:
alert(Object.getPrototypeOf(person1) == Person.prototype); // true
alert(Object.getprototypeOf(person1).name); // "Nicholas"
当想要使用 person1 的 name 属性时,搜索过程是这样子的:首先,编译器会问“person1 有 name 属性吗?”没有。那么编译器就会接着问,person1 的原型有 name 属性吗?有,就返回 “Nicholas”。
根据上面搜索的过程,我们就可以理解下面这段代码了:
function Person(){
}
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function(){
alert(this.name);
};
var person1 = new Person();
var person2 = new Person();
person1.name = "Greg";
alert(person1.name); // "Greg"
alert(person2.name); // "Nicholas"
- call 和 apply 方法
这两个函数都是在特定的作用域中调用特定的函数,实际上等于设置函数体内 this 对象的值。 apply
apply 方法接收两个参数,一个是在其中运行函数的作用域,另一个是参数数组。其中参数数组可以是 Array 的实例,也可以是 arguments 对象。function sum(num1,num2){ return num1 + num2; } function callSum1(num1,num2){ return sum.apply(this,arguments); // 传入 arguments 对象 } function callSum2(num1,num2){ return sum.apply(this,[num1,num2]); // 传入数组 } alert(callSum1(10,10)); // 20 alert(callSum2(10,10)); // 20call
call 方法与 apply 方法的作用域相同,它们的区别仅在于接收参数的方式不同。对于 call 而言,第一个参数 this 值没什么变化,变化的是其余参数都直接传递给函数。function sum(sum1,sum2){ return num1 + num2; } function callSum1(num1,num2){ return sum.call(this,num1,num2); } alert(callSum(10,10)); // 20作用扩充函数作用域
下面这个例子就是通过 call 方法改变函数的作用域。window.color = "red"; var o = {color:"blue"}; function getColor(){ alert(this.color); } sayColor(); // red; sayColor.call(this); // red sayColor.call(window); // red sayColor(o); // bluebind 方法
我个人认为 bind 和 call、apply 方法没有什么差别。还是通过看一个例子来了解它的看法。
``` javascript
window.color = "red";
var o = {color:"blue"};
function sayColor(){
alert(this.color);
}
var objectSayColor = sayColor.bind(o);
objectSayColor(); // blue
```
JavaScript 之函数的更多相关文章
- JavaScript中函数函数的定义与变量的声明<基础知识一>
1.JavaScript中函数的三种构造方式 a.function createFun(){ } b.var createFun=function (){ } c.var createFun=new ...
- 理解 JavaScript 回调函数并使用
JavaScript中,函数是一等(first-class)对象:也就是说,函数是 Object 类型并且可以像其他一等对象(String,Array,Number等)一样使用.它们可以"保 ...
- 5种 JavaScript 调用函数的方法
一次又一次的,我发现,那些有bug的Javascript代码是由于没有真正理解Javascript函数是如何工作而导致的(顺便说一下,许多那样的代码是我写的).JavaScript拥有函数式编程的特性 ...
- javascript escape()函数和unescape()函数
javascript escape()函数和unescape()函数 escape() 函数可对字符串进行编码,这样就可以在所有的计算机上读取该字符串. 语法: escape(string) stri ...
- JavaScript调用函数的方法
摘要:这篇文章详细的介绍了Javascript中各种函数调用的方法及其原理,对于理解JavaScript的函数有很大的帮助! 一次又一次的,我发现,那些有bug的Javascript代码是由于没有真正 ...
- Javascript常用方法函数收集(二)
Javascript常用方法函数收集(二) 31.判断是否Touch屏幕 function isTouchScreen(){ return (('ontouchstart' in window) || ...
- javascript工具函数
第一部分 JavaScript工具函数 转义特殊字符为html实体 HtmlEncode: function(str){ return str.replace(/&/g, '&') ...
- [转]javascript eval函数解析json数据时为什加上圆括号eval("("+data+")")
javascript eval函数解析json数据时为什么 加上圆括号?为什么要 eval这里要添加 “("("+data+")");//”呢? 原因在于: ...
- javascript篇-----函数作用域,函数作用域链和声明提前
在一些类似C语言的编程语言中,花括号内的每一段代码都具有各自的作用域,而且变量在声明它们的代码段之外是不可见的(也就是我们不能在代码段外直接访问代码段内声明的变量),我们称之为块级作用域,然而,不同于 ...
- JavaScript 常用函数总结
javascript函数: ·常规函数 ·数组函数 ·日期函数 ·数学函数 ·字符串函数 .cookie函数 1.常规函数 javascript常规函数包括以下9个函数: (1)alert ...
随机推荐
- 《java入门第一季》之Arrays类前传(排序案例以二分查找注意的问题)
根据排序算法,可以解决一些小案例.举例如下: /* * 把字符串中的字符进行排序. * 举例:"dacgebf" * 结果:"abcdefg" * * 分析: ...
- cat .git/config查看远端服务器信息(git的配置信息:远端服务器连接信息)
本地git库中,查找其连接的远端服务器信息: 每个git库都会有一个配置信息文件.git/config. cat .git/config,可以看到信息如下: [core] reposi ...
- UML之包图
包图是UML中用类似于文件夹的符号表示的模型元素的组合,系统中的每个元素都只能为一个包所有,一个包可嵌套在另一个包中,使用包图可将相关元素归入一个系统,一个包中包含附属包.图表或单个元素.简单的来说, ...
- 说说struts2中拦截器的请求流程一(模拟大致流程)
本文可作为北京尚学堂struts2课程的学习笔记. 首先 什么是拦截器?拦截器能干什么? 拦截器,顾名思义就是拦截对象然后做操作的东西,至于是拦截谁?那自然是拦截action了.能做什么操作呢?你想让 ...
- Java-Cookie源码
public class Cookie implements Cloneable { private static final String LSTRING_FILE = "javax.se ...
- Android性能优化典例(一)
在Android开发过程中,很多时候往往因为代码的不规范.api使用不恰当.控件的使用场景考虑不全面和用户不恰当的操作等都能引发一系列性能问题的,下面就是我目前整理的一些Android开发过程中需要注 ...
- Android ROM开发(二)——ROM架构以及Updater-Script脚本分析,常见的Status错误解决办法
Android ROM开发(二)--ROM架构以及Updater-Script脚本分析,常见的Status错误解决办法 怪自己二了,写好的不小心弄没了,现在只好重新写一些了,上篇简单的配置了一下环境, ...
- PS 图像调整算法— —渐变映射
这个调整简单来说就是先建立一张lookup table, 然后以图像的灰度值作为索引,映射得到相应的颜色值.图像的灰度值是由图像本身决定的,但是lookup table 却可以各种各样,所以不同的lo ...
- SoftMax regression
最终收敛到这个结果,巨爽. smaple 0: 0.983690,0.004888,0.011422,likelyhood:-0.016445 smaple 1: 0.940236,0.047957, ...
- android studio比较长用的几款插件
不懂安装studio插件,看参考博文:android stuido插件安装:http://blog.csdn.net/liang5630/article/details/46372447 1.Butt ...