JavaScript函数理解
本文参考自简书javaScript之函数详解
这里从函数的构造函数开始。
在js中,函数都是对象,它们都是Function构造函数的实例。因此,类似Java中的对象,函数名可以理解为指向该Function构造函数实例的指针。下面很多内容都将与该点相关。
一个函数的定义方法有如下3种。
1.即最原始的使用构造函数定义,也是我们基本不使用也不推荐使用的方法
var foo = new Function("a","console.log(a)");
foo(11); //
var foo = new Function("a","b","console.log(a+b)");
foo(11,22); //
foo(11); //NaN
看到,该构造函数的最后一项参数为函数体执行的部分,前面不论几项都是该函数的参数,不推荐的原因也很明显,太难写了!
2.函数表达式写法,即对一个匿名函数赋予一个函数名
var foo = function() {
console.log("aa");
};
var bar = foo;
foo = undefined;
bar();
// foo();
3.普通的函数声明
console.log(a); // undefined
foo3(); //
// foo4(); //is not a function
function foo3() {
console.log(33)
}
var foo4 = function() {
console.log(44)
}
foo4(); //
var a = 4;
2、3两种方法在平时是最常用到的,因此不单独写了,代码中加了一部分测试语句。
再次申明本文的主题:函数名是指向函数对象的一个指针。
首先看第一段代码。Js中,重复的申明一个变量并不会报错。第一次将一个函数赋予给foo,即将foo的地址指向第一个函数;当再次赋予第二个函数时,可以看到,第一个函数被覆盖了。这里可以简单的理解为,foo所保存的地址被改为了指向第二个函数的地址。因此也可以理解:js中的函数没有重载的概念。
再看第二段代码,继续理解该概念。函数是一个对象,函数名为指向该对象的指针。因此我们可以将多个变量名指向一个函数对象;如第二段代码所示,将变量bar指向变量foo所指的函数变量,此时,foo和bar两个变量所保存的都为同一个函数对象的地址。此时将foo指向undefined,可以看到,函数对象并没有消失,bar可以正常使用。
最后,说一下函数声明提升。我们都知道,在正常使用过程中,对于普通的函数声明语句而言,无论我们在哪里声明,我们可以在任意位置直接使用。这是因为在代码执行之前,解析器通过函数声明提升,将函数添加到执行环境中。在我参考的文章中,作者提出函数声明与函数表达式之间的区别在于解析器的函数声明提升对于函数声明是有效的,而不作用于函数表达式。这里我更倾向于认为函数表达式也能经过函数声明提升,只不过此时对象虽然已被创建,但是并没有将该对象赋值给函数名。当然结果是一样的,单纯的匿名函数的存在对于我们而言并没有什么意义。
下面看下一个例子,该例子包括函数名是一个变量和函数声明提升的概念。
var getName = function(){
console.log(2);
}
function getName (){
console.log(1);
}
getName(); //2
此时getName()打印出的值为2。根据函数声明提升,4-6行代码将首先被解析器执行并加入上下文中。此时上下文中保存的内容为变量getName和其指向的函数对象。随后在js执行时,getName再次被声明,此时单纯的声明变量并不会将变量之前的内容覆盖掉,所以此时并没有什么影响。之后第一行执行完后getName被赋予了新的函数对象。再次运行到4-6行时,由于其已被解析器执行过,将会跳过。最终打印出2。另外,该例子并不能说明之前我的猜测是错误的,虽然我刚看到这个例子时也怀疑了下。
函数作为第一公民,它也可以作为另一个函数的参数或者返回值,不过这里我暂时并没有看到它太大的意义,先不谈,具体可以看开篇引用的文章。
函数自带2个特殊的对象:arguments和this。
arguments:
arguments的主要作用为保存传入该函数的参数。此外,该对象有一个callee的属性,该属性效果和函数变量名一致,指向用有该arguments的函数对象。不过在严格模式下访问该属性将出错,因此使用严格模式的同学可以忽略它。该属性主要作用于递归中,例子如下:
function factorial(num) {
if (num <= 1) {
return 1;
} else {
return num * factorial(num - 1)
(return num * arguments.callee(num - 1))
}
}
var trueFactorial = factorial;
factorial = function() {
return 0;
};
console.log(trueFactorial(5)); //
console.log(factorial(5)); // 0
this:
this指向的是函数运行的环境对象,其基本情况与Java中一样。
this引用的是函数据以执行的环境对象(当在网页的全局作用域中调用函数时,this对象引用的就是window)。示例见下:
window.color = 'red'; function sayColor() {
console.log(this.color);
};
var foo = {
color: 'blue',
sayColor: function() {
console.log(this.color);
}
}
sayColor(); //red
foo.sayColor(); //blue
console.log(this); //window
基础的this相对比较简单。但与Java中不同的一点是,js中的this是可以被指定的。参考资料见JavaScript秘密花园,或见顶部的参考。示例如下
//this 可变的
function bar2(color) {
this.color = color;
console.log(this)
}
var bar = new bar2('blue');
sayColor.call(bar); //blue
call(Object,arg1,arg2,...)和apply(Object,arguments)方法可以将函数内部的this显示的指定为传入的第一个参数object。它们的唯一区别在于传入参数的方式不同,call方法必须显式的将参数一个个传入,而apply方法第二个参数为一个参数数组。
bind(Object)的作用同样是将函数内部的this赋值为Object,但和call、bind不同的是,call和bind是将该函数改变this后直接执行了,而bind返回的是一个函数对象,它可以赋值给一个变量,并在适当的时候执行。
js的this的晚绑定特训,简单看例子:
var test = someObject.methodTest;
test();
test就像一个普通的函数被调用;因此,函数内的this将不再被指向到someObject对象。
js中基础的函数就讲到这了,以上内容参考自文内的两个链接的文章,这里记录下自己所学。
end
JavaScript函数理解的更多相关文章
- 深入理解javascript函数系列第一篇——函数概述
× 目录 [1]定义 [2]返回值 [3]调用 前面的话 函数对任何一门语言来说都是一个核心的概念.通过函数可以封装任意多条语句,而且可以在任何地方.任何时候调用执行.在javascript里,函数即 ...
- 深入理解javascript函数系列第二篇——函数参数
× 目录 [1]arguments [2]内部属性 [3]函数重载[4]参数传递 前面的话 javascript函数的参数与大多数其他语言的函数的参数有所不同.函数不介意传递进来多少个参数,也不在乎传 ...
- 深入理解javascript函数系列第三篇——属性和方法
× 目录 [1]属性 [2]方法 前面的话 函数是javascript中的特殊的对象,可以拥有属性和方法,就像普通的对象拥有属性和方法一样.甚至可以用Function()构造函数来创建新的函数对象.本 ...
- 理解javascript函数的重载
javascript其实是不支持重载的,这篇文章会和java语言函数的重载对比来加深对javascript函数重载的理解. 以下我会假设读者不了解什么是重载所以会有一些很基础的概念 ...
- 理解JavaScript函数参数
前面的话 javascript函数的参数与大多数其他语言的函数的参数有所不同.函数不介意传递进来多少个参数,也不在乎传进来的参数是什么数据类型,甚至可以不传参数. arguments javascri ...
- 深入理解javascript函数系列第一篇
前面的话 函数对任何一门语言来说都是核心的概念.通过函数可以封装任意多条语句,而且可以在任何地方.任何时候调用执行.在javascript里,函数即对象,程序可以随意操控它们.函数可以嵌套在其他函数中 ...
- 深入理解javascript函数系列第三篇
前面的话 函数是javascript中特殊的对象,可以拥有属性和方法,就像普通的对象拥有属性和方法一样.甚至可以用Function()构造函数来创建新的函数对象.本文是深入理解javascript函数 ...
- 深入理解JavaScript函数
本篇文章主要介绍了"深入理解JavaScript函数",主要涉及到JavaScript函数方面的内容,对于深入理解JavaScript函数感兴趣的同学可以参考一下. JavaScr ...
- 深入理解javascript函数进阶系列第一篇——高阶函数
前面的话 前面的函数系列中介绍了函数的基础用法.从本文开始,将介绍javascript函数进阶系列,本文将详细介绍高阶函数 定义 高阶函数(higher-order function)指操作函数的函数 ...
随机推荐
- 2018.10.15 bzoj3564: [SHOI2014]信号增幅仪(坐标处理+最小圆覆盖)
传送门 省选考最小圆覆盖? 亦可赛艇(你们什么都没看见) 在大佬的引领下成功做了出来. 就是旋转坐标使椭圆的横轴跟xxx轴平行. 然后压缩横坐标使得其变成一个圆. 然后跑最小覆盖圆就可以了. 注意题目 ...
- 2018.07.09 顺序对齐(线性dp)
顺序对齐 题目描述 考虑两个字符串右对齐的最佳解法.例如,有一个右对齐方案中字符串是 AADDEFGGHC 和 ADCDEGH. AAD~DEFGGHC ADCDE~~GH~ 每一个数值匹配的位置值 ...
- HDU 2058 The sum problem (数学+暴力)
题意:给定一个N和M,N表示从1到N的连续序列,让你求在1到N这个序列中连续子序列的和为M的子序列区间. 析:很明显最直接的方法就是暴力,可是不幸的是,由于N,M太大了,肯定会TLE的.所以我们就想能 ...
- Sublime必用快捷键[私人]
最近一年前端开发都是用sublime这款编辑器, 相对于webStorm强大而启动慢.editplus快启动而功能弱, sublime恰好在两者之间:而且其指令行安装.更新.卸载插件比eclipse之 ...
- 抓包工具 - HttpWatch(功能详细介绍)
HttpWatch是功能强大的网页数据分析工具,集成在IE工具栏,主要功能有网页摘要.cookies管理.缓存管理.消息头发送/接收,字符查询.POST数据.目录管理功能和报告输出.HttpWatch ...
- (线段树)Just a Hook -- hdu -- 1689
链接: http://acm.hdu.edu.cn/showproblem.php?pid=1698 思路: 我的想法很简单,像上一题一样从后面向前面来算,前面已经覆盖的,后面自然不能再来计算了,具体 ...
- eclipse 安装
做一个项目,需要搭建环境.使用sql server 2005,tomcat,eclipse.过程真复杂,碰到些小问题,不过都解决了,还算顺利. win7下sql server 2005安装:http: ...
- 使用工厂方法配置bean的两种方式
1.使用静态工厂方法: 对应的配置.xml文件: 2.通过实例工厂的方法来配置bean: 对应的xml文件:
- 玩了下STM8单片机
偶然的机会,发现STM8真是又便宜又好用啊,哈哈! 买了一个STM8S103F3的小板子,再加一个ST-Link调试器,总共才35块钱!对于我们这种玩习惯了动辄上千上万的FPGA开发板的人来说,就是白 ...
- App主导现在 HTML5领衔未来
HTML5能够让开发人员构建丰富的基于Web应用程序,使其能在任何设备中使用标准的Web浏览器.很多人认为HTML5将会让App过时.到底App还是HTML5会是谁赢得最后的胜利,在业界也有不少讨论, ...