JavaScript作为一种基于对象(非严格面向对象)的语言,函数在JS中的地位非同一般:用函数声明类和对象。甚至函数本身也是对象。

一、函数的三种声明方式辨析。

1.function命令

function printAbc(){

console.log('ABC');

}

2.函数表达式(变量赋值形式)

var printAbc = function (){

console.log('ABC');

};

注意:1、使用函数表达式形式时务必要有分号。

2、此时function后函数名可有可无,且只在函数内部有效

var fname = function abc(){

console.log(abc.name);  /* xxx.name 方法非ECMAScript标准 */

}

fname();   //abc

abc(); //ReferenceError: abc is not defined

这种写法的用处有两个,一是可以在函数体内部调用自身,二是方便除错(除错工具显示函数调用栈时,将显示函数名,而不再显示这里是一个匿名函数)。

3.使用Function构造函数

JS中一切都是对象,声明函数也可以看作构造函数对象。

var f = new Function("a","b","return a+b");

f(1,2);   //3

第1到第N-1个参数是函数参数,第N个参数是函数体。

有些人认为,这种定义方式只有傻逼才会用,因为除了奇葩以外别无好处,但是其实真的是有用的- -。

实现一个在线运行和编辑JS代码的程序:

<html>
<head>
<title>JS Run Online</title>
<script type="text/javascript">
function btnOnclick(){
var getDiv = document.getElementById("TextArea");
var text = getDiv.value;
var f = new Function(text);
f();
}
</script>
</head>
<body>
<div align="center">
<textarea id="TextArea" cols="30" rows="10"></textarea>

<input type="button" value="Run" onclick="btnOnclick()">
</div>
</body>
</html>

这段程序功能看起来简单,但是如果用静态语言将是很难实现的,Function构造函数正是JavaScript是动态语言的有力证明——可以在运行过程中让程序修改程序本身,而动态语言的核心就是:所有参数,包括函数体,都视作字符串。(个人理解,不妥望指正)。

二、函数名的提升。

JS中,使用function命令声明函数是,该声明会被提到代码头部,如:

f();

function f() {};

以上代码并不报错,因为function f() {};被提到了代码头部。

但是,如果采用函数表达式,就是另外一种情况了:

f();

var f = function () {};

// TypeError: undefined is not a function

因为以上代码等同于:

var f;

f();

f = function () {};

当调用f的时候,f只是被声明,还没有被赋值,等于undefined,所以会报错。因此,如果同时采用function命令和赋值语句声明同一个函数,最后总是采用赋值语句的定义。

var f = function (){

console.log('1');

};

function f() {

console.log('2');

}

f();//1

因此,

1、函数若重复声明,则视作只声明了一次,以最后一次声明为准。

2、不能在条件语句中声明函数。

现实情况下,由于浏览器的容错性,条件语句中使用function命令不会报错,但是由于函数名提升,条件语句本身就会无意义:

if (0){

function f() { console.log('1'); }

}

f();//1

3、若确实需要用条件语句生成函数,只可采用函数表达式。

if (xxx){

var f = function (){xxx;};

};

三、函数的参数。

1、length属性。

函数定义时参数的个数。

function f (a,b) {}

console.log(f.length); //2

2、参数的省略。

函数从前向后取用参数,若多余,则后面忽略,若不足,则后面补undefined。若欲省略前面的参数,则应该主动显式传入undefined。

function f(a,b){
return a;
} f(,1) // error
f(undefined,1) // undefined

3、默认值。

可以通过以下方式设置参数默认值:

function f(a){
a = a || 1;
return a;
} f('') // 1
f(0) // 1

缺点是:a不能为0或空字符串,否则函数即使有参数也会使用默认值。

4、函数参数的传递方式。

JS的参数传递方式是值传递,这意味着函数体内修改参数值不会影响到外部:

var a = 1;

function f (a){

a = 2;

}

f(a);

console.log(a);    //1

值得注意的是,对于符合类型的数据,属性值得传递是地址传递:

var o = {a:1};

function f(o){

o.a = 2;

}

f(o);

console.log(o.a);    //2

var a = [6,7,8];

function f(a){

a[0] = 0;

a[1] = 1;

a[2] = 2;

}

f(a);

console.log(a[0],a[1],a[2]); // 0 1 2

利用这个特性,当我么需要对某个变量采用地址传递时,可以将它写成全局对象的一个属性:

var a = 1;

function f(a){

window.a = 2;

}

f(a);

console.log(a);   //2

4、arguments对象

//未完待续

浅谈JavaScript函数的更多相关文章

  1. 浅谈javascript函数节流

    浅谈javascript函数节流 什么是函数节流? 函数节流简单的来说就是不想让该函数在很短的时间内连续被调用,比如我们最常见的是窗口缩放的时候,经常会执行一些其他的操作函数,比如发一个ajax请求等 ...

  2. [转载]浅谈JavaScript函数重载

     原文地址:浅谈JavaScript函数重载 作者:ChessZhang 上个星期四下午,接到了网易的视频面试(前端实习生第二轮技术面试).面了一个多小时,自我感觉面试得很糟糕的,因为问到的很多问题都 ...

  3. [转]浅谈javascript函数劫持

    转自:Ph4nt0m Security Team 这么多年了,现在学习依然还是有很多收货,向前辈致敬.转载一方面是自己存档一份,另一方面是让更多喜欢安全的人一同学习. ================ ...

  4. 浅谈JavaScript 函数作用域当中的“提升”现象

    在JavaScript当中,定义变量通过var操作符+变量名.但是不加 var 操作符,直接赋值也是可以的. 例如 : message = "hello JavaScript ! " ...

  5. 浅谈javascript函数,变量声明及作用域

    javascript函数跟变量的声明.作用域这些概念网上都已经讲烂了. 这里写个博客,也相当于做个笔记. 变量声明 首先看个例子: var globalVar = "gv"; fu ...

  6. 浅谈javascript函数执行过程

    javascript函数执行过程: 1. 为函数创建一个执行环境 2. 复制函数的 [[scopes]] 属性中的对象构建起执行环境的作用链域 3. 创建函数活动对象并推入执行环境作用链域的前端 4. ...

  7. 浅谈JavaScript函数重载

    上个星期四下午,接到了网易的视频面试(前端实习生第二轮技术面试).面了一个多小时,自我感觉面试得很糟糕的,因为问到的很多问题都很难,根本回答不上来.不过那天晚上,还是很惊喜的接到了HR面电话.现在HR ...

  8. 浅谈JavaScript中的闭包

    浅谈JavaScript中的闭包 在JavaScript中,闭包是指这样一个函数:它有权访问另一个函数作用域中的变量. 创建一个闭包的常用的方式:在一个函数内部创建另一个函数. 比如: functio ...

  9. 浅谈JavaScript浮点数及其运算

    原文:浅谈JavaScript浮点数及其运算     JavaScript 只有一种数字类型 Number,而且在Javascript中所有的数字都是以IEEE-754标准格式表示的.浮点数的精度问题 ...

随机推荐

  1. jsp页面表单的遍历要怎么写

    1.传统的方式使用request.getAttribute(“list”);获取表单的值, 2.也可以用struts2提供的标签进行遍历 备注 // 传统的接受参数方法 // String sfz=t ...

  2. 序列化- 使用BinaryFormatter进行序列化

    可以使用属性(Attribute)将类的元素标为可序列化的(Serializable)和不可被序列化的(NonSerialized)..NET中有两个类实现了IFormatter借口的类中的Seria ...

  3. 寻找链表中倒数第K个结点的位置

    输入一个链表,输出该链表中倒数第K个结点. struct ListNode { int m_nValue; ListNode* m_pNext; }; ListNode* FindKthToTail( ...

  4. 【BZOJ2281】【博弈论+DP】 [Sdoi2011]黑白棋

    Description 黑白棋(game) [问题描述] 小A和小B又想到了一个新的游戏. 这个游戏是在一个1*n的棋盘上进行的,棋盘上有k个棋子,一半是黑色,一半是白色. 最左边是白色棋子,最右边是 ...

  5. 『重构--改善既有代码的设计』读书笔记----Inline Class

    如果某个类没有做太多的事情,你可以将这个类的所有特性搬移到另外一个类中,然后删除原类.可以看到,Inline Class正好和Extract Class相反,后者是将一个巨类分解成多个小类从而来分担责 ...

  6. xubuntu14.04截图,彻底到Linux一个半月后记

        前言 自学计算机技术,越到后面,越依赖ubuntu,以致于很多时候都是一开机就打开虚拟机上的ubuntu10.04,Linux已经变得越来越重要了. 2014-04-17,ubuntu14.0 ...

  7. JavaScript 获取当月天数

    getDate() 方法可返回月份的某一天.取值范围是1~31 如果是0的话,就返回最后一天.这样就能取得当月的天数了 比如获取16年2月份的天数 var day = new Date(2016,2, ...

  8. SVN更新失败,提示locked

    使用SVN更新资源时,提示locked,解决方案如下: 首先找到是哪个文件不能进行更新/提交,在本地工作区间中找到这个文件对应的目录,目录里面会有.svn文件夹,这个文件夹默认是隐藏的,需要设置文件夹 ...

  9. 【随记】解决:VS2010 调试器无法继续继续运行该进程,无法启动调试

    今天在调试项目的时候突然出现错误: 按照网上的一些方法弄了后还是同样报错,把本地代码删除后从库上重现拉下来的项目依然报错,到这里就明白不是项目本身问题了,而是VS2010 的问题,经过网上查资料,问同 ...

  10. Ubuntu You don't have permission to access解决方案!

    最近对Linux越来越喜欢了,就直接安装了一个Ubuntu,配制好LAMP后,在做小项目时,出现了下面的问题:Ubuntu You don't have permission to access ** ...