文章目录
函数
-
值可以传递给一个函数,函数将返回一个值。
-
可以像任何其他对象一样具有属性和方法。
- 它们与其他对象的区别在于函数可以被调用。
- 简而言之,它们是Function对象。
-
如果一个函数中没有使用return语句,则它默认返回undefined。
-
要想返回一个特定的值,则函数必须使用 return 语句来指定一个要返回的值。
- 使用new关键字调用一个构造函数除外。
1. 内置函数
1)JavaScript内置函数都默认被包含在window对象(全局对象)上。
- 使用时,可以采用“window.函数名( )”的形式,也可以直接书写”函数名( )”。
2)常见内置函数
-
alert( )、confirm( )、prompt( )
-
parseInt( )、parseFloat( )
-
eval( )
-
isNaN( )、isFinite( )
-
escape( )、unescape( )
JavaScript语言顶级的内建函数
eval()
eval()方法会对一串字符串形式的JavaScript代码字符求值。
uneval()
uneval()方法创建的一个Object的源代码的字符串表示。
isFinite()
isFinite()函数判断传入的值是否是有限的数值。 如果需要的话,其参数首先被转换为一个数值。
isNaN()
isNaN()函数判断一个值是否是NaN。注意:isNaN函数内部的强制转换规则十分有趣; 另一个可供选择的是ECMAScript 6 中定义Number.isNaN() , 或者使用 typeof来判断数值类型。
parseFloat()
parseFloat() 函数解析字符串参数,并返回一个浮点数。
parseInt()
parseInt() 函数解析字符串参数,并返回指定的基数(基础数学中的数制)的整数。
decodeURI()
decodeURI() 函数对先前经过encodeURI函数或者其他类似方法编码过的字符串进行解码。
decodeURIComponent()
decodeURIComponent()方法对先前经过encodeURIComponent函数或者其他类似方法编码过的字符串进行解码。
encodeURI()
encodeURI()方法通过用以一个,两个,三个或四个转义序列表示字符的UTF-8编码替换统一资源标识符(URI)的某些字符来进行编码(每个字符对应四个转义序列,这四个序列组了两个”替代“字符)。
encodeURIComponent()
encodeURIComponent() 方法通过用以一个,两个,三个或四个转义序列表示字符的UTF-8编码替换统一资源标识符(URI)的每个字符来进行编码(每个字符对应四个转义序列,这四个序列组了两个”替代“字符)。
escape()
已废弃的 escape() 方法计算生成一个新的字符串,其中的某些字符已被替换为十六进制转义序列。使用 encodeURI或者encodeURIComponent替代本方法。
unescape()
已废弃的 unescape() 方法计算生成一个新的字符串,其中的十六进制转义序列将被其表示的字符替换。上述的转义序列就像escape里介绍的一样。因为 unescape 已经废弃,建议使用decodeURI()或者decodeURIComponent 替代本方法。
2. 自定义函数
1) 函数的声明
function 函数名([参数1],[参数2]…){
函数体;
[return 表达式]
}
- 在函数定义语法格式中,function是定义函数的关键字,后面是函数名。函数名是必选项,且函数名在同一文件中是唯一的,命名规则同变量命名规则一致。
- 参数1,参数2…,是可选项。多个参数之间要用逗号分隔开,最多255个。
- 函数体是必选项,用于实现函数功能的语句。
- return语句,是可选的,用于返回函数值。表达式可以为任意的表达式、变量或者常量。
例如,以下的代码定义了一个简单的square函数:
function square(number) {
return number * number;
}
函数square使用了一个参数,叫作number。这个函数只有一个语句,它说明该函数将函数的参数(即number)自乘后返回。函数的return语句确定了函数的返回值:
return number * number;
原始参数(比如一个具体的数字)被作为值传递给函数;值被传递给函数,如果被调用函数改变了这个参数的值,这样的改变不会影响到全局或调用函数。
如果传递一个对象(即一个非原始值,例如Array或用户自定义的对象)作为参数,而函数改变了这个对象的属性,这样的改变对函数外部是可见的。
如下面的例子所示:
function myFunc(theObject) {
theObject.make = "Toyota";
}
var mycar = {make: "Honda", model: "Accord", year: 1998};
var x, y;
x = mycar.make; // x获取的值为 "Honda"
myFunc(mycar);
y = mycar.make; // y获取的值为 "Toyota" (make属性被函数改变了)
2) 函数表达式
- 函数表达式和函数声明非常相似,它们甚至有相同的语法(查看函数表达式了解详情)。
- 一个函数表达式可能是一个更大的表达式的一部分。
- 可以定义函数“名字”(例如可以在调用堆栈时使用)或者使用“匿名”函数。例如,函数square也可这样来定义:
var square = function(number) {
return number * number;
};
var x = square(4); // x gets the value 16
- 然而,函数表达式也可以提供函数名,并且可以用于在函数内部代指其本身,或者在调试器堆栈跟踪中识别该函数:
var factorial = function fac(n) {
return n<2 ? 1 : n*fac(n-1)
};
console.log(factorial(3));
- 当将函数作为参数传递给另一个函数时,函数表达式很方便。下面的例子演示了一个叫map的函数如何被定义,而后使用一个表达式函数作为其第一个参数进行调用:
function map(f,a) {
var result = [],i; //创建一个新数组
for (i = 0; i != a.length; i++)
result[i] = f(a[i]);
return result;
}
下面的代码:
function map(f, a) {
var result = []; // 创建一个数组
var i; // 声明一个值,用来循环
for (i = 0; i != a.length; i++)
result[i] = f(a[i]);
return result;
}
var f = function(x) {
return x * x * x;
}
var numbers = [0,1, 2, 5,10];
var cube = map(f,numbers);
console.log(cube);
//返回 [0, 1, 8, 125, 1000]。
- 在 JavaScript 中,可以根据条件来定义函数。比如下面的代码,当num 等于 0 的时候才会定义 myFunc :
var myFunc;
if (num == 0){
myFunc = function(theObject) {
theObject.make = "Toyota"
}
}
- 函数表达式不会提升,所以不能在定义之前调用。
var myFunction = function name([param[, param[, ... param]]]) {
statements
};
name:函数名,可以省略。当省略函数名的时候,该函数就成为了匿名函数。
param:传递给函数的参数的名称,一个函数最多可以有255个参数.
statements:组成函数体的声明语句。
- 除了上述的定义函数方法外,你也可以在运行时用 Function 构造器由一个字符串来创建一个函数 ,很像 eval() 函数。
当一个函数是一个对象的属性时,称之为方法。
3)比较一下两种函数的定义方法
3. 函数作用域
JavaScript 将函数认为是唯一的局部作用域。
- 函数参数(形参)和函数内部声明的变量为局部变量。
- 函数作用域中的变量随函数的调用而产生,随函数的执行完毕而销毁。
在函数内定义的变量不能在函数之外的任何地方访问,因为变量仅仅在该函数的域的内部有定义。相对应的,一个函数可以访问定义在其范围内的任何变量和函数。换言之,定义在全局域中的函数可以访问所有定义在全局域中的变量。在另一个函数中定义的函数也可以访问在其父函数中定义的所有变量和父函数有权访问的任何其他变量。
例如:
// 下面的变量定义在全局作用域(global scope)中
var num1 = 20,
num2 = 3,
name = "Chamahk";
// 本函数定义在全局作用域
function multiply() {
return num1 * num2;
}
multiply(); // 返回 60
// 嵌套函数的例子
function getScore() {
var num1 = 2,
num2 = 3;
function add() {
return name + " scored " + (num1 + num2);
}
return add();
}
getScore(); // 返回 "Chamahk scored 5"
4. 函数参数
1) 函数的调用
-
调用函数时,传递给函数的值被称为函数的实参(值传递),对应位置的函数参数名叫作形参。
-
如果实参是一个包含原始值(数字,字符串,布尔值)的变量,则就算函数在内部改变了对应形参的值,返回后,该实参变量的值也不会改变。
-
如果实参是一个对象引用,则对应形参会和该实参指向同一个对象。假如函数在内部改变了对应形参的值,返回后,实参指向的对象的值也会改变。
-
-
定义一个函数并不会自动的执行它。定义了函数仅仅是赋予函数以名称并明确函数被调用时该做些什么。调用函数才会以给定的参数真正执行这些动作。例如,一旦你定义了函数square,你可以如下这样调用它:
square(5);
上述语句通过提供参数 5 来调用函数。函数执行完它的语句会返回值25。
-
函数一定要处于调用它们的域中,但是函数的声明可以被提升(出现在调用语句之后),如下例:
console.log(square(5)); /* ... */ function square(n) { return n*n }
-
函数域是指函数声明时的所在的地方,或者函数在顶层被声明时指整个程序。
-
//注意//:只有使用如上的语法形式(即 function funcName(){})才可以。而下面的代码是无效的。就是说,函数提升仅适用于函数声明,而不适用于函数表达式。
console.log(square); // square is hoisted with an initial value undefined. console.log(square(5)); // TypeError: square is not a function var square = function (n) { return n * n; }
-
函数的参数并不局限于字符串或数字。你也**可以将整个对象传递给函数,**如数组,object等。
-
函数可以被递归,就是说函数可以调用其本身。例如,下面这个函数就是用递归计算阶乘:
function factorial(n){ if ((n == 0) || (n == 1)) return 1; else return (n * factorial(n - 1)); }
可以计算1-5的阶乘如下:
var a, b, c, d, e; a = factorial(1); // 1赋值给a b = factorial(2); // 2赋值给b c = factorial(3); // 6赋值给c d = factorial(4); // 24赋值给d e = factorial(5); // 120赋值给e
还有其它的方式来调用函数。常见的一些情形是某些地方需要动态调用函数,或者函数的实参数量是变化的,或者调用函数的上下文需要指定为在运行时确定的特定对象。
显然,函数本身就是对象,因此这些对象也有方法。
例如:
var sum = new Function('a', 'b', 'return a + b'); console.log(sum(2, 6)); // expected output: 8
2) 参数传递
观察示例,分析结果。
3) arguments对象
- 函数的实际参数会被保存在一个类似数组的arguments对象中。
- 每个函数都存在自己的arguments对象。
4) 默认参数
- 如果没有值或传入了未定义的值,默认函数参数允许形式参数使用默认值初始化。
- JavaScript 中函数的参数默认是undefined。
function multiply(a, b) {
return a * b;
}
multiply(5, 2); // 10
multiply(5); // NaN !
5. 函数闭包
词法作用域中使用的域,是变量在代码中声明的位置所决定的。嵌套的函数可以访问在其外部声明的变量。
6. 回调函数
当函数作为参数传递给另一个函数时,被传递的函数称为回调函数(callback)。