函数
JavaScript 函数是由事件驱动的或者当它被调用时执行的可重复使用的代码块。
函数对象
JavaScript中的函数就是对象,可以把函数赋值给变量,或者作为参数传递给其他函数,并且可以给它们设置属性,甚至调用它们的方法。函数与众不同的是它们可以被调用,且每个函数在创建时会附加两个隐藏属性,函数的上下文和实现函数行为的代码。
每个函数对象在创建时会有一个 prototype 属性,它的值是一个拥有 constructor 属性且值为该函数的对象。
函数字面量
函数对象通过函数字面量来创建:
// 创建一个名为 add 的变量,并用来把两个数字相加的函数赋值给它
var add = function (a, b) {
return a + b;
};
// 箭头函数
var add = (a, b) => return a + b;
函数字面量包括四个部分:
- 关键词 function
- 函数名,可有可无
- 包含在括号内的参数,当然参数也是可有可无的,括号不能少。
- 是一组包裹在大括号内的语句块,也就是函数要执行的具体代码,当然不写代码也没问题,{}是必不可少的。
(function () {});
var a = function() {};
var obj = {fn: function() {}};
上面三种函数的写法都是可以的。
调用
调用一个函数会暂停当前函数的执行,传递控制权和参数给新函数。除了声明时定义的形式参数,每个函数还接收两个附加的参数: this 和 arguments。
有4种方式可以调用JavaScript函数:
1. 作为方法调用
2. 作为函数调用
3. 作为构造函数调用pply
4. 通过apply()和call()方法间接调用
方法调用模式
方法调用是通过对象的属性来调用函数。方法调用的上下文是调用它的对象,可以通过this关键字引用该对象。
- this是一个关键字,不是变量,也不是属性名。JavaScript不允许给this赋值。
// increment 方法接收一个可选的参数,如果参数不是数字,那么默认使用数字1
var myObject = {
value: 0,
increment: function (inc) {
this.value += typeof inc === 'number' ? inc : 1;
}
};
myObject.increment();
console.log(myObject.value); // 1
myObject.increment(2);
console.log(myObject.value); // 3
函数调用模式
函数调用就是直接通过function对象来调用函数。
var sum = add (1, 2); // sum值为3
函数调用的上下文(this的值)是全局对象(window),即 this 被绑定到全局对象。
构造器调用模式
如果函数或方法调用之前带有关键字new,它就是构造函数调用。
- 构造函数调用和普通的函数调用以及方法调用在实参处理、调用上下文和返回值方面都有不同。
- 构造函数调用会创建一个新的空对象,这个对象继承自构造函数的 prototype 属性。构造函数使用这个新创建的对象作为调用上下文,同时 this 会被绑定到新创建的对象。
var Quo = {
fun: function() {
console.log(this === Quo);
}
};
Quo.fun(); // true,方法调用
var myQuo = new Quo.fun(); // false,构造函数调用
Apply调用模式和Call调用模式
JavaScript中的函数也是对象,函数对象也可以包含方法。其中的2个方法call()和apply()可以用来间接地调用函数。
- apply方法让我们构建一个参数数组传递给调用函数。它允许我们选择 this 的值。
- apply和call的功能是一样的,只是传入的参数列表形式不同。
var array = [1, 2];
var sum = add.apply(null, array); // sum值为3
var sum1 = add.call(null, 2, 3); // sum1值为5
参数
JavaScript中的函数定义并未指定函数形参的类型,函数调用也不会对传入的实参值做任何类型检查。实际上,JavaScript函数调用甚至不检查传入形参的个数。函数对于未传入的参数赋值为undefined,对于多余的参数忽略。
当函数被调用时,会得到一个参数: arguments 数组。函数可以通过此参数访问所有它被调用时传递给它的参数列表,包括那些没有被分配给函数声明时定义的形式参数的多余参数。arguments 拥有一个 length 属性,但它没有任何数组的方法。
var sum = function () {
var i, sum = 0;
for (i = 0; i < arguments.length; i++){
sum +=arguments[i];
}
return sum;
};
console.log(sum(1, 2, 4, 5)); // 12
返回
当一个函数被调用时,它从第一个语句开始执行,并在遇到关闭函数体的 } 时结束。
- return 语句可用来使函数提前返回。 当 return 执行时,函数立即返回而不再执行余下的语句。
- 一个函数总是会返回一个值。如果没有指定返回值,则返回 undefined。
- 如果函数调用时在前面加上了 new 前缀,且返回值不是一个对象,则返回 this (该新对象)。
异常
JavaScript 提供一套异常处理机制。异常是干扰程序的正常流程的不寻常的事故。下面有几种异常类型:
- 1.SyntaxError:解析代码时发生语法错误;
- 2.ReferenceError:引用一个不存在的变量时发生错误;或将一个值分配给无法分配的对象,比如对函数的运行结果或者this赋值;
- 3.RangeError:当一个值超出有效 范围时发生的错。(数组长度为负数 或Number对象的方法参数超出范围 或函数堆栈超过最大值);
- 4.TypeError:变量或参数不是预期类型时发生的错误。比如对字符串等原始类型的值使用new命令,就会抛出这种错误;因为new命令的参数应该是一个构造函数;
扩充类型的功能
JavaScript 允许给语言的基本类型扩充功能。 通过给Object.prototype添加方法, 可以让该方法对所有对象都可用。 这样的方式对函数、数组、字符串、数字、正则表达式和布尔值同样适用。
// 移除字符串首尾空白的方法
Function.prototype.method = function (name, func) {
this.prototype[name] = func;
return this;
};
String.method('trim', function () {
return this.replace(/^\s+|\s+$/g, '');
});
console.log('"' + " neat ".trim() + '"'); // "neat"