javascript基础(五)函数
原文http://pij.robinqu.me/
通过call和apply间接调用函数(改变this)
call 和 apply带有多个参数,call和apply把当前函数的this指向第一个参数给定的函数或对象中,并传递其余所有的参数作为当前函数的参数。
var O = function () {
this.foo = 'hello';
this.hello = function () {
return 'world';
}
};
var fn = function () {
console.log('call', this);
};
var o = new O();
fn.call(o);//此时fn的this指向o
call和apply的不同之处,在于call传递的参数是作为arguments依次传入的,例如
fn.call(o, 1, 2, 3);
而apply传递的参数是以一个数组的方式传入的,例如fn.apply(o, [1, 2, 3]);
参数
当传入参数少于函数声明的参数时,留空的参数的值是undefined。
JavaScript允许传入参数的个数大于声明时制定的参数个数。可以用arguments来访问这些参数
function f(){
var i;
for( i = 0; i < arguments.length ; i++) {
console.log(arguments[i]);
}
}
f(1,2,3,4,5,6);
函数通过取得arguments的长度得到传入参数的个数,使用一个循环获取每一个参数。
arguments还有两个属性,callee和callercallee表示正在执行的function对象,caller表示调用当前function的function
例如
function f(){
console.log(arguments.callee);//[Function: f]
console.log(arguments.callee.caller);[Function: g]
var i;
for( i = 0; i < arguments.length ; i++) {
console.log(arguments[i]);
}
}
function g(){
f(1,2,3,4,5,6);
}
g();
callee 的重要用法之一是在匿名函数中实现递归
var result = function (x) {
if (x <= 1) return 1;
return x * arguments.callee(x - 1);
}(3);
console.log(result);
上例使用了一个匿名函数和callee实现了一个阶乘。
作为值的函数
javascript中的函数可以作为值来传递,这种赋值方式可以认为是传内存地址
function square(x) {
return x * x;
}
var s = square;
s(4);
作为命名空间的函数
(function() {
}());
闭包
JavaScript函数对象的内部状态不仅包含着函数的代码逻辑,还引用当前的作用域链。函数对象通过作用域链相互关联起来,函数体内部变量包含在函数作用域内,这就叫闭包。
例如
var scope = 'global scope';
function checkscope() {
var scope = 'local scope';
function f() {
return scope;
}
return f;
} checkscope()();
这段checkscope声明了一个局部变量,定义了一个函数f,函数f返回了这个局部变量的值,最后返回了这个函数f。在定义函数f的作用域外调用f,得到的返回仍然是函数f创建时所在的作用域的局部变量scope。
又例如
var counter = (function() {
var count = 0;
return function () {
return count++ ;
}
}());
代码定义了一个立即执行函数并返回给counter,这个函数定义了一个局部变量count,返回了一个子函数,该子函数每次调用,都会吧count加一并返回。
闭包的注意事项
观察下面的示例:
var add_the_handlers = function (nodes) {
var i;
for (i = 0; i < nodes.length; i += 1) {
nodes[i].onclick = function (e) {
alert(i);
};
}
};
这个函数期望的结果,是在运行的时候为每个node在onclick的时候alert出各自的序号,但是实际运行的结果却不同:所有的node在单击的时候alert出来的数字总是同一个。
这是因为alert所在的匿名函数的闭包中存放的i是第一行的i,而不是在循环中获得的i的当前值。
所以如果希望达到预期结果,应该在循环中创建多个闭包,在闭包中存放当前循环的i的值:
var add_the_handlers = function (nodes) {
var i;
for (i = 0; i < nodes.length; i += 1) {
nodes[i].onclick = function (i) {
return function(e){
alert(e);
};
}(i);
}
};
这里使用一个立即执行函数并传递当前的i的值,返回一个新生成的函数。在这个新生成的函数的闭包中就保存了当前的i的值。
函数中的this对象
在一个对象中的this始终引用当前对象,但是在函数中,特别是在闭包中,this有一些特殊的行为。
函数中的this对象始终绑定在函数运行时的上下文环境上。所以在普通模式下调用一个全局函数,this始终指向window(客户端),在严格模式下调用一个全局函数,this始终是undefined
示例
var name = "The Window";
var object = {
name: "My Object",
getNameFunc: function () {
return function () {
return this.name;
};
},
getName : function () {
return this.name;
}
}; console.log(object.getNameFunc()());
console.log(object.getName());
getNameFunction()返回了一个匿名函数,这个匿名函数在调用的时候,上下文是window(浏览器中),所以在浏览器中输出的是the Window
而getName()调用的时候上下文是object,所以成功输出object的name
其实以上代码中
object.getNameFunc()()
等效于
var fnc = object.getNameFunc();//这时候的fnc已经脱离了object对象
fnc();
所以如果想要getNameFunction()正确返回Object的Name,需要在返回的匿名函数的闭包中保存在函数声明时的this,
getNameFunc: function () {
var that = this;
return function () {
return that.name;
};
},
这样就可以了。。
函数柯里化
函数柯里化是指,把接受多个参数的函数转换成接受一个单一参数的函数,并且返回接受余下的参数而且返回结果的新函数的技术。
示例
var add1 = add.curry(1);
console.log(add1(2));
其中,add是接受两个参数的函数,add调用了curry返回一个只接受一个参数的新函数,之后调用add1便等效于调用add(1, 2);
javascript并不原生支持curry,可以用prototype来模拟
Function.prototype.curry = function () {
var slice = Array.prototype.slice,
args = slice.apply(arguments),
that = this;
return function () {
return that.apply(null, args.concat(slice.apply(arguments)));
};
};
function add(n1, n2) {
return n1 + n2;
}
var add1 = add.curry(1);
console.log(add1(2));
curry创建了一个新函数,在新函数的闭包中保存了原先传递的参数。
函数的属性和方法
length 函数的length表示函数实参的数量,是只读的
prototype 指向一个该函数的原型对象的引用
toString 返回一个字符串
javascript基础(五)函数的更多相关文章
- JavaScript 基础(五) 函数 变量和作用域
函数定义和调用 定义函数,在JavaScript中,定义函数的方式如下: function abs(x){ if(x >=0){ return x; }else{ return -x; } } ...
- (Frontend Newbie)JavaScript基础之函数
函数可以说是任何一门编程语言的核心概念.要能熟练掌握JavaScript,对于函数及其相关概念的学习是非常重要的一步.本篇从函数的基本知识.执行环境与作用域.闭包.this关键字等方面简单介绍Java ...
- JavaScript基础学习-函数及作用域
函数和作用域是JavaScript的重要组成部分,我们在使用JavaScript编写程序的过程中经常要用到这两部分内容,作为初学者,我经常有困惑,借助写此博文来巩固下之前学习的内容. (一)JavaS ...
- JavaScript 基础回顾——函数
在JavaScript中,函数也是一种数据类型,属于 function 类型,所以使用Function关键字标识函数名.函数可以在大括号内编写代码并且被调用,作为其他函数的参数或者对象的属性值. 1. ...
- Javascript 基础--JS函数(三)
一.基本概念:未完成某一个功能的代码(语句,指令)的集合. 二.函数的调用方式: 2.1.函数名(传递参数1,传递参数2) 基本语法 function 函数名(参数列表){ //代码; retur ...
- javascript基础知识-函数
1.javascript中函数有两种定义方式: 函数语句定义和表达式定义 //函数有定义 function test(){ console.log("This is a function&q ...
- JavaScript基础——创建函数
JavaScript的最重要的一个部分是制作其他代码可以重用的代码.要做到这一点,你可以把代码组织成执行特定任务的函数.函数是结合在一个单一的块中,并给予一个名称的一系列代码语句.然后,你就可以通过引 ...
- JavaScript基础之函数与数组
函数 函数的基本概念 为完成某一功能的程序指令(语句)的集合,称为函数.有的程序员把函数称为方法,希望大家不要被这两个名词搞晕了. 函数分为:自定义函数.系统函数(经常查看js帮助手册). j ...
- javascript基础知识--函数定义
函数声明式 function funname( 参数 ){ ...执行的代码 } 声明式的函数并不会马上执行,需要我们调用才会执行:funname(); * 分号是用来分隔可执行JavaScript语 ...
随机推荐
- AR/VR行业是否会像智能手机一样的飞速崛起
从硬件和内容两方面来看,VR(虚拟现实)应该会比AR(增强现实)率先普及大众.当然,这是建立在解决无线化.眩晕.便携等问题之后的事儿,内容上不用担心,照现在这个发展速度-- 说到"风口&qu ...
- RelativeLayout各个属性
android:layout_above="@id/xxx" --将控件置于给定ID控件之上 android:layout_below="@id/xxx" ...
- scp命令报错(IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!)
使用scp命令移动某一服务器的文件到另外的服务器时报出一下错误: [root@bogon vm_sys1]# scp project.tar.gz root@172.31.0.90:/webdata/ ...
- 离线安装gcc(CentOS7)
安装Redis时,需要使用gcc.如果系统是联网的,那么直接使用如下命令联网安装. yum -y install gcc 但是如果系统不可联网,那么就需要一种离线安装的方式了.步骤如下: 1. 从Ce ...
- HDU 1269 迷宫城堡(DFS)
迷宫城堡 Problem Description 为了训练小希的方向感,Gardon建立了一座大城堡,里面有N个房间(N<=10000)和M条通道(M<=100000),每个通道都是单向的 ...
- ios版本更新总结
更新思路,获取APP Store 版本号与项目本地版本号对比,如果本地低于商店版本号,就提示用户更新(说明:在上架项目时请保持本地和商店版本号一致,避免检测更新问题被拒) 1.获取商店版本号,代码如下 ...
- AForge.net 使用之录像拍照功能实现
连接摄像头设备,这里需要引入 AForge.Video; AForge.Video.DirectShow; AForge.Video.FFMPEG; 还需要添加引用,aforge.dll,aforge ...
- Alyona and copybooks
题目连接 题意: 给 n,a,b,c四个数,n为已有的书的数目,问再买k本书所需花费最少是多少,(k+n)%4==0: 有三种套餐 第一种只有一本书,花费a 第二种有两本书,花费b, 第三种有三本书, ...
- 必须掌握的Linux命令
章节简述: 本章节讲述系统内核.Bash解释器的关系与作用,教给读者如何正确的执行Linux命令以及常见排错方法. 经验丰富的运维人员可以恰当的组合命令与参数,使Linux字符命令更加的灵活且相对减少 ...
- linux 安装php的redis拓展
安装步骤: #wget https://github.com/nicolasff/phpredis/archive/2.2.4.tar.gz #tar -zxvf 2.2.4 #cd phpredi ...