本文参考自简书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. 2018.09.30 bzoj2223: [Coci 2009]PATULJCI(主席树)

    传送门 主席树经典题目. 直接利用主席树差分的思想判断区间中数的个数是否合法然后决定左走右走就行了. 实际上跟bzoj3524是同一道题. 代码: #include<bits/stdc++.h& ...

  2. git 删除追踪状态

    当不小心添加一个不想被git记录等文件时,这个时候就算将该文件记录在了.gitignore里也是没有用的,因为那个文件已经被git记录过了,只有那些从来没有被git记录过的文件(即:自添加进项目后,从 ...

  3. Spark RDD详解

    1.RDD是什么 RDD(Resilient Distributed Dataset):是Spark的核心数据结构,指的是一个只读的.可分区的分布式数据集,这个数据集的全部或部分可以缓存在内存中,在多 ...

  4. Hibernate中OpenSessionInViewFilter(通常配置在web.xml文件中)的作用

    Spring为我们解决Hibernate的Session的关闭与开启问题. Hibernate 允许对关联对象.属性进行延迟加载,但是必须保证延迟加载的操作限于同一个 Hibernate Sessio ...

  5. 查看Linux服务器被映射的公网ip

    查看Linux服务器被映射的公网ip   现在云服务器非常流行,不仅企业甚至是个人都可能拥有自己的云服务器,但是目前的云服务器厂商提供的公网IP大都是映射而来,所以在Linux服务器上执行ifconf ...

  6. mod_pagespeed

    https://github.com/pagespeed/mod_pagespeed.git https://developers.google.com/speed/pagespeed/module/ ...

  7. 【TFS错误】TF30063: 您没有访问 Microsoft-IIS/8.5 的权限

    问题现象 开发人员报告,所有的生成都失败了,日志显示下载源代码出错,系统提示错误信息为"-TF30063: 您没有访问 Microsoft-IIS/8.5 的权限-". 图1 - ...

  8. .NET高级代码审计(第二课) Json.Net反序列化漏洞

    0X00 前言 Newtonsoft.Json,这是一个开源的Json.Net库,官方地址:https://www.newtonsoft.com/json ,一个读写Json效率非常高的.Net库,在 ...

  9. Python 爬虫实战—盘搜搜

    近期公司给了个任务:根据关键搜索百度网盘共享文件并下载. 琢磨了几天写下了一段简单的demo代码,后期优化没有处理. 主要的思路:(1)根据关键字爬取盘搜搜的相关信息 (2)解析并获取盘搜搜跳转到百度 ...

  10. 【CronExpression表达式详解和案例】(转载)

    原文地址:https://www.cnblogs.com/pipi-changing/p/5697481.html   找了下Cron的资料,这篇作者写的比较清晰,转载记录一下,方便后面使用的时候在g ...