通常而言,一个函数是一个子程序,他们可以被外部代码调用(亦或被滴管函数在内部调用)。和程序一样,函数是由一系列声明(被称为函数体function body)组合而成。值可以传递给函数,并且函数可以返回一个值。

在javascript中,函数是一个对象,因为她可以拥有属性和方法,就像对象一样。将函数和对象区分的是函数可以被调用,他们是函数对象(Function objects)。

描述

js中的所有函数都是函数对象Function object

函数和程序不一样,函数总是返回一个值,但是程序不一定。

为了返回一个值,一个班函数必须要有return的声明。一个没有return声明的函数将会返回一个默认值。

在用new关键字调用的构造函数中,默认值是this参数。对于其他的函数而言,默认值返回的是undefined。

函数调用个参数是函数的arguments属性。参数按值传递给函数,所以函数内部改变argument的值将不会影响函数外的参数的值。

然而对象的引用作为值传递给函数时,函数内部对于对象的改变将会影响到函数外部。

/* Declare the function 'myFunc' */
function myFunc(theObject) {
theObject.brand = "Toyota";
} /*
* Declare variable 'mycar';
* create and initialize a new Object;
* assign reference to it to 'mycar'
*/
var mycar = {
brand: "Honda",
model: "Accord",
year:
}; /* Logs 'Honda' */
console.log(mycar.brand); /* Pass object reference to the function */
myFunc(mycar); /*
* Logs 'Toyota' as the value of the 'brand' property of the object, as changed to by the function.
*/
console.log(mycar.brand);

关键字this并不指向当前正在执行的函数(指向的是windows对象),所以你必须通过名字将其指向函数对象。

定义函数

有以下方式来定义函数:

函数声明(function 声明)

function name([param[, param[, ... param]]]) {
statements
}
name
函数名
param
传递给函数的参数.参数个数的上限是255个。
statements
函数主体

函数表达式 (function 表达式)

function [name]([param[, param[, ... param]]]) {
statements
}
name
函数名. 可以省略,省略后被叫做匿名函数.
param
参数,上限255个参数
statements
函数主体

函数构造器

注意!使用Function构造器来创建函数不被推荐,因为它需要将函数主体作为一个字符串,这将阻止JS引擎优化并且会造成其他的问题。

new Function (arg1, arg2, ... argN, functionBody)
arg1, arg2, ... argN
0个或者多个参数名
functionBody
一个包含函数主体的字符串

还有一些新式的ECMAScript 6创建函数的方式,姐姐我不说了,等什么时候流行了再说 (✿◡‿◡)

函数属性

arguments对象

你可以在函数中使用arguments对象来指代函数的arguments属性。

  • arguments:一个类数组对象,包含了传递给正在执行的函数的参数。
  • arguments.callee : 正在执行的函数(API说不赞成这个属性被使用,但是仍然可以使用)
  • arguments.caller  : 废弃了,我不说了,和上面的作用一样
  • arguments.length: 传递给函数的参数个数

定义函数方法

getter和setter方法

你可以在任何支持新属性添加的内置对象或用户定义对象中定义getter(accessor方法)和 setter(mutator方法) 。定义setters和getters使用了对象字面量语法。

get

绑定一个对象属性到一个函数中,当读取一个属性的时候被调用。

set
绑定一个对象属性到一个函数中,当设置一个属性的时候被调用。

函数构造器VS函数声明VS函数表达式

比较如下:

定义一个函数使用Function构造函数,并且赋值给变量multiply

function multiply(x, y) {
return x * y;
}

一个匿名的函数表达式,并赋值给变量 multiply:

var multiply = function(x, y) {
return x * y;
};

一个函数表达式,并将函数命名为func_name,并赋值给变量multiply:

var multiply = function func_name(x, y) {
return x * y;
};

不同:

上述所有好像都在做着差不多的事情,但是有一些细微的不同。

在函数名和将函数赋值给的变量之间存在不同。

函数名是不可以改变的,但是变量是可以被再次赋值。

函数名只能在函数体里面使用。当尝试在函数外部使用时将会导致一个错误(如果函数名事先声明将build报错undefined)

例如:

var y = function x() {};
alert(x); // throws an error

在函数通过Function的toString方法序列化的时候同样也可以出现。

就像第四个例子展示的一样,函数名可以和函数赋值的变量不一样。他们之间没有相互关系。一个函数声明也可以创建一个拥有同样名字的变量。所以,和通过函数表达式被定义的函数不同,通过函数声明定义的函数可以在他们被定义的范围内通过他们的名字来获取函数本身。

通过new Function定义的函数没有函数名。但是在SpiderMonkey的js引擎中,函数序列化后的格式表示他们拥有anonymous的函数名

例如:alert(new Function())的输出结果是:

function anonymous() {
}

因为函数的确没有一个名称,anonymous并不是一个可以在函数内可以使用的变量(函数声明或者函数表达式中的函数名可以在函数体内使用),例如,下面的例子将会报错:

var foo = new Function("alert(anonymous);");
foo();

和用函数表达式或者Function构造器定义函数不同的是,通过函数声明定义的函数可以在函数声明前使用(使用了一个叫做函数声明提前的机制),例如:

foo(); // alerts FOO!
function foo() {
alert('FOO!');
}

一个通过函数表达式定义的函数继承了当前的环境。也就是说,这个函数形成了一个闭包。

然而,通过Function构造器定义的函数没有继承除了全局环境(所有函数都继承)以外的任何环境。

通过函数表达式和函数声明定义的函数只被解析一次,但是被函数构造器定义的函数被解析不仅一次。就是说,函数体字符串传递给Function 构造函数的时候必须被解析,此时将会调用构造函数(所以每次在使用函数构造器定义的函数的函数体的时候,都会调用构造函数)。虽然函数表达式会每次创建一个闭包,但是函数在调用个时候不会被每次解析,所以函数表达式仍然比"new Function(...)"要快,因此,函数构造器通常会尽可能的避免被使用。

需要注意的是,函数表达式和函数声明中嵌套着函数构造器定义的函数将不会被重复解析。如下图:

var foo = (new Function("var bar = \'FOO!\';\nreturn(function() {\n\talert(bar);\n});"))();
foo(); // The segment "function() {\n\talert(bar);\n}" of the function body string is not re-parsed.

函数声明非常容易且常常是无意识的变成一个函数表达式。一个函数声明在下面任何一种情况将变成函数表达式:

1.成为表达式的一部分

2.不再是一个函数或者程序的“源元素(source element)”。一个source element是一个在程序亦或函数体中不内嵌的声明。

  • var x = ;               // source element
    if (x == ) { // source element
    x = ; // not a source element
    function boo() {} // not a source element
    }
    function foo() { // source element
    var y = ; // source element
    function bar() {} // source element
    while (y == ) { // source element
    function blah() {} // not a source element
    y++; // not a source element
    }
    }

    举例:

//函数声明
function foo() {}
// 函数表达式
(function bar() {})
// 函数表达式
x = function hello() {} if (x) {
//函数表达式
function world() {}
} //函数声明
function a() {
//函数声明
function b() {}
if () {
// 函数表达式
function c() {}
}
}

块级函数(block-level functions)

在严格模式下,从 ES2015 (ES6)开始,在一个块(花括号)里面的函数,它的作用域将属于那个块。

在ES6之前,块级函数禁止在严格模式下使用。

'use strict';

function f() {
return ;
} {
function f() {
return ;
}
} f() === ; // true // f() === 2 in non-strict mode

块级函数在非严格模式下使用

简而言之:不要用!

在非严格模式下,在花括号中的函数声明将会表现的非常奇怪。如下:

if (shouldDefineZero) {
function zero() { // DANGER: compatibility risk
console.log("This is zero.");
}
}

ES2015定义了如果shouldDefineZero(应该定义zero么)是false,那么说明zero没有被定义,那么花括号里面的代码也不会执行。

但是,这是新标准的一部分。历史上是遗留的没有定义的标准,并且一些浏览器将定义zero不管判断语句执行成功与否。

在严格模式下,所有的浏览器都支持ES2015标准,所以他们都将按照一样的方式执行:zero在只有shouldDefineZero为true的时候才能执行,并且只在if语句块中执行。

一个更加安全的做法是将将函数表达式赋值给一个变量。

var zero;
if () {
zero = function() {
console.log("This is zero.");
};
}

判断一个函数方法是否存在

你可以通过typeof判断一个函数是否存在。

在下面的方法中,进行了一个用于判断window对象是否有noFunc的属性,并且是noFunc是一个函数类型的测试。

if ('function' == typeof window.noFunc) {
// use noFunc()
} else {
// do something else
}

注意在if的条件判断中,只是引用了noFunc函数名,但是函数名后面没有(),也就是说实际上没有执行。

原文链接:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions

Function javascript的更多相关文章

  1. javascript的 Object 和 Function

    一. javascript 的 内置对象: Object 和 Function javascript所有东西,包括 Function 都是对象 . Array  其实是一个 Function 类型的对 ...

  2. javascript 中 function bind()

    Function bind() and currying <%-- All JavaScript functions have a method called bind that binds t ...

  3. javascript中的操作符详解1

    好久没有写点什么了,根据博主的技术,仍然写一点javascript新手入门文章,接下来我们一起来探讨javascript的操作符. 一.前言 javascript中有许多操作符,但是许多初学者并不理解 ...

  4. Javascript常用方法函数收集(二)

    Javascript常用方法函数收集(二) 31.判断是否Touch屏幕 function isTouchScreen(){ return (('ontouchstart' in window) || ...

  5. javascript常用方法函数收集

    收集了一些比较常用的javascript函数. 1.字符串长度截取 function cutstr(str, len) { var temp, icount = 0, patrn = /[^\x00- ...

  6. javascript版Ajax请求

    什么是Ajax请求,Ajax也就是“Asynchronous JavaScript and XML”(异步JavaScript和XML),无刷新数据读取.能减少流量的消耗,也提高了浏览的流畅性,给用户 ...

  7. Java基础 —— JavaScript

    Javascript:基于对象与事件驱动的脚本语言,主要用于客户端 特点: 交互性:信息动态交互. 安全性:不能访问本地硬盘. 跨平台性:只要有浏览器就支持Javascript,与平台无关. Java ...

  8. 100个直接可以拿来用的JavaScript实用功能代码片段(转载)

    把平时网站上常用的一些实用功能代码片段通通收集起来,方面网友们学习使用,利用好的话可以加快网友们的开发速度,提高工作效率. 目录如下: 1.原生JavaScript实现字符串长度截取2.原生JavaS ...

  9. Javascript核心概述 - 深入了解javascript

    /* 一.执行上下文:堆栈(底部全局上下文+顶部当前活动上下文) */ /* 二.变量对象: 变量根据执行上下文,找到数据存储位置,这种机制叫变量对象 1. 变量都要var定义,且都不能delete ...

随机推荐

  1. LINQ体验(13)——LINQ to SQL语句之运算符转换和ADO.NET与LINQ to SQL

    运算符转换 1.AsEnumerable:将类型转换为泛型 IEnumerable 使用 AsEnumerable<TSource> 可返回类型化为泛型 IEnumerable 的參数.在 ...

  2. 两点C#的propertyGrid的使用心得【转】

    源文:http://www.cnblogs.com/bicker/p/3318934.html 最近接触C#的PropertyGrid比较多,得到了两个小心得记录一下. 第1点是关于控制Propert ...

  3. WeX5开发指南

    WeX5入门.UI2开发.App开发.服务端开发.扩展资料学习. 1 新手入门 1.1 运行WeX5的demo(视频) 1.2 App开发.调试.打包部署完整过程(视频) 1.3 创建第一个应用(视频 ...

  4. Ejb in action(六)——拦截器

    Ejb拦截器可以监听程序中的一个或全部方法.与Struts2中拦截器同名,并且他们都可以实现切面式服务.同一时候也与Spring中的AOP技术类似. 不同的是struts2的拦截器的实现原理是一层一层 ...

  5. 实例讲解SVN分支和合并问题(转)

    本节向大家简单描述一下SVN分支和合并方面的知识,在学习SVN的过程中SVN分支和合并时经常遇到的问题,在这里和大家分享一下,希望本文对大家有用. 关于主线同SVN分支合并的概念及如何使用的误区此问题 ...

  6. 系统安全-SElinux

    Selinux是[security-Enhanced Linux]的简称,是美国国家安全局[NSA]和[SCC]开发的Linux的一个扩张强制访问控制安全模块. 因为企业的业务平台的服务器上存储着大量 ...

  7. Django-select_related优化查询

    对于一对一字段(OneToOneField)和外键字段(ForeignKey),可以使用select_related 来对QuerySet进行优化. select_related 返回一个QueryS ...

  8. Mataplotlib事例操作

    刚开始需要的文件是和前边的两个连载一起的

  9. python--面向对象组合

    面向对象的命名空间 类中的方法   类中的静态属性   对象的属性类的组合应用 面向对象的命名空间 class A: country='中国' a=A() a.name='alex' print(a. ...

  10. Linux随笔记

    Linux配置apt-get源地址 以Ubuntu配置网易开源镜像站为例: 访问地址:http://mirrors.163.com/,找到对应的系统. 先将source.list进行备份,执行: su ...