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)指操作函数的函数 ...
随机推荐
- ORACLE实用函数之一 ratio_to_report的简单使用
应用场景: 查询学生成绩级别(ABCDE)个人数和所占百分比(案列简单,勿喷). 表结构: create or replace table stu_grade( id varchar2(36), le ...
- 浅析10种常见的黑帽seo手法
虽然博主并不认同黑帽seo手法,但是一些常见的黑帽手法还是需要了解的,增加自己对黑帽的认知,也可以在自己优化网站时适时的规避开这些黑帽手法,从而避免自己的网站被搜索引擎惩罚.好了,话不多说,下面进入今 ...
- 2018.08.09 bzoj4719: [Noip2016]天天爱跑步(树链剖分)
传送门 话说开始上文化课之后写题时间好少啊. 这道题将一个人的跑步路线拆成s->lca,lca->t,然后对于第一段上坡路径要经过的点,当前这个人能对它产生贡献当且仅当dep[s]-dep ...
- 2018.07.09 顺序对齐(线性dp)
顺序对齐 题目描述 考虑两个字符串右对齐的最佳解法.例如,有一个右对齐方案中字符串是 AADDEFGGHC 和 ADCDEGH. AAD~DEFGGHC ADCDE~~GH~ 每一个数值匹配的位置值 ...
- python3.4用循环往mysql5.7中写数据并输出
#!/usr/bin/env python # -*- coding:utf-8 -*- # __author__ = "blzhu" """ pyt ...
- verilog基础--altera培训
参数化 Localparam :与prameter一样,但不能被重写. Verilog-2001 格式, module mult_acc #(parameter size = 8 ) (...); 数 ...
- 端口模式(IN,OUT,INOUT,BUFFER)
in: OUT: INOUT: BUFFER:缓冲模式,与OUT类似可作为输出使用,但也可把输出的信号作为输入使用.
- <a href=“#”>
在html中看到这样的属性:<a href=“#”>搜了好久,感觉不甚明白,现记之,等遇到了再做补充. # is called an anchor (or hash...). so the ...
- 为上海莫大型重工企业提供基于TFS的软件研发流程管理培训
这周,和微软公司的朋友一起,受上海莫大型重工企业的要求,为企业软件部门一个60多人的软件团队提供了为其2天的全流程培训,培训基于微软Team Foundation Server 2017(TFS 20 ...
- WPF Out Of Memory
起因 程序发布后,运行突然奔溃报Out of Memory,查看日志发现如下类似错误(以下堆栈信息来之网络): System.OutOfMemoryException: Insufficient me ...