本文参考自简书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函数理解的更多相关文章

  1. 深入理解javascript函数系列第一篇——函数概述

    × 目录 [1]定义 [2]返回值 [3]调用 前面的话 函数对任何一门语言来说都是一个核心的概念.通过函数可以封装任意多条语句,而且可以在任何地方.任何时候调用执行.在javascript里,函数即 ...

  2. 深入理解javascript函数系列第二篇——函数参数

    × 目录 [1]arguments [2]内部属性 [3]函数重载[4]参数传递 前面的话 javascript函数的参数与大多数其他语言的函数的参数有所不同.函数不介意传递进来多少个参数,也不在乎传 ...

  3. 深入理解javascript函数系列第三篇——属性和方法

    × 目录 [1]属性 [2]方法 前面的话 函数是javascript中的特殊的对象,可以拥有属性和方法,就像普通的对象拥有属性和方法一样.甚至可以用Function()构造函数来创建新的函数对象.本 ...

  4. 理解javascript函数的重载

        javascript其实是不支持重载的,这篇文章会和java语言函数的重载对比来加深对javascript函数重载的理解.       以下我会假设读者不了解什么是重载所以会有一些很基础的概念 ...

  5. 理解JavaScript函数参数

    前面的话 javascript函数的参数与大多数其他语言的函数的参数有所不同.函数不介意传递进来多少个参数,也不在乎传进来的参数是什么数据类型,甚至可以不传参数. arguments javascri ...

  6. 深入理解javascript函数系列第一篇

    前面的话 函数对任何一门语言来说都是核心的概念.通过函数可以封装任意多条语句,而且可以在任何地方.任何时候调用执行.在javascript里,函数即对象,程序可以随意操控它们.函数可以嵌套在其他函数中 ...

  7. 深入理解javascript函数系列第三篇

    前面的话 函数是javascript中特殊的对象,可以拥有属性和方法,就像普通的对象拥有属性和方法一样.甚至可以用Function()构造函数来创建新的函数对象.本文是深入理解javascript函数 ...

  8. 深入理解JavaScript函数

    本篇文章主要介绍了"深入理解JavaScript函数",主要涉及到JavaScript函数方面的内容,对于深入理解JavaScript函数感兴趣的同学可以参考一下. JavaScr ...

  9. 深入理解javascript函数进阶系列第一篇——高阶函数

    前面的话 前面的函数系列中介绍了函数的基础用法.从本文开始,将介绍javascript函数进阶系列,本文将详细介绍高阶函数 定义 高阶函数(higher-order function)指操作函数的函数 ...

随机推荐

  1. shell的基本语法

    一 赋值运算符 1 += :使用方法是,((x+=需要增加的数字))算和值. 2 *=  :使用方法是,((x*=需要怎加的倍数))算乘值. 3 %= :使用方法是,((x%=需要除以的数字))算余数 ...

  2. 2018.09.09 bzoj4403: 序列统计(Lucas定理)

    传送门 感觉单调不降序列什么的不好做啊. 于是我们序列中下标为i的元素的值加上i,这样就构成了一个单调递增的序列. 问题就变成了: 求出构造长度分别为1 ~ n且每个元素的值在l+1 ~ r+n之间的 ...

  3. 2018.08.29 NOIP模拟 table(拓扑排序+建图优化)

    [描述] 给出一个表格,N 行 M 列,每个格子有一个整数,有些格子是空的.现在需要你 来做出一些调整,使得每行都是非降序的.这个调整只能是整列的移动. [输入] 第一行两个正整数 N 和 M. 接下 ...

  4. 如何开发一个产品级的Node.js 应用

    介绍 Node.js是一个开源的javascript运行时环境.非常简单可以快速开发一个网络应用.这个平台运行在Linux.OSX和Windows,而且运行在这个平台上的应用都是用javascript ...

  5. vc中使用SendMessage正确发送自定义消息的方法

    最近在用VC2008做开发,后来由于要用到消息的发送,而且需要自定义消息,在网上查找了很多例子,根据他们所说的,虽然大致都差不多,但是基本上没有 一个能完全做出来的.要知道VC编程有一个小地方出错,都 ...

  6. Nodejs书写爬虫工具

    看了几天的nodejs,的确是好用,全当是练手了,就写了一个爬虫工具. 爬虫思路都是一致的,先抓取页面数据,然后分析页面,获取到所需要的数据,最后获得这些数据,是写入到硬盘,还是显示到网页,自己看着办 ...

  7. LeetCode134:Gas Station

    题目: There are N gas stations along a circular route, where the amount of gas at station i is gas[i]. ...

  8. TCP实现一个简易的聊天室 (Unity&&C#完成)

    效果展示 TCP Transmission Control Protocol 传输控制协议 TCP是面向连接的流模式(俗称:网络流).即传输数据之前源端和终端建立可靠的连接,保证数据传输的正确性. 流 ...

  9. 使用n g r o k将本地主机URL暴露给互联网

    在本地开发对接第三方服务的时候,对方有的时候会要求我们提供一个线上的URL地址.例如微信登录 1.下载ngrok https://ngrok.com/download 顺便注册一个账号(使用GitHu ...

  10. ASP.NET Core 2 学习笔记(五)静态文件

    之前的ASP.NET网站,只要把*.html.*.css.*.jpg.*.png.*.js等静态文件放在项目根目录,默认都可以直接被浏览:但ASP.NET Core 小改了浏览静态文件的方式,默认根目 ...