函数
函数实际上就是对象,因此 Function 有自己的属性和方法。函数名是指向函数对象的指针。
函数定义方式有:函数声明、函数表达式、箭头函数、构造函数。
函数声明
函数声明后不会立即执行,会在我们需要的时候调用。
function functionName(a,b){
return a + b;
}
函数声明的语法中不含分号,因分号是用来分隔可执行 JavaScript 语句,而函数声明不是一个可执行语句,所以不以分号结束。
函数表达式(匿名函数)
通过一个表达式定义,即创建一个函数再把它赋值给一个值,这样创建的函数叫做匿名函数(函数没有名称)。
var x = function(a,b){
return a + b;
};
函数表达式没有函数提升。
箭头函数
ES6 新增了箭头函数,使得表达式更简洁。
箭头函数不带大括号会隐式的返回这行代码的值。
//多个参数或者没有参数需要带圆括号
(多个参数或者没有参数) => {函数声明};
//只有一个参数时,圆括号是可选的
单一参数 => {函数声明};
箭头函数简介的语法非常适合嵌入函数的场景:
son.addEventListener('click', function () {
alert('son');
}, true);
//箭头函数的简介语法
son.addEventListener('click', () => {
alert('son');
}, true);
构造函数(不推荐)
最后一种定义函数的方式是使用 Function()构造函数。这个构造函数接收任意多个字符串参数,最后一个参数始终会被当成函数体,而之前的函数都是新函数的参数。
var function = new Funciton("a","b","return a + b");
虽然我们不推荐使用这种定义函数的方式,
但把函数想象为对象,把函数名想象为指针是很重要的。
函数提升
JavaScript 引擎在任何代码执行之前,会先读取函数声明,并在执行上下文中生成函数定义,这个过程称为函数提升。
//没问题
console.log(sum(a,b));
function sum(a,b){
return a * b;
}
//会出错
console.log(sum(a,b));
const sum = function(a,b){
return a * b;
};
函数参数
ECMAScript 函数既不关心传入参数的个数,也不关心传入参数的数据类型。
之所以会这样,主要是因为 ECMAScript 函数的参数在内部表现为一个数组。函数被调用时总会接收一个数组,但函数并不关心这个数组中包含什么。
默认参数
ES5及以前,实现默认参数的一种常用方式是检测某个参数是否等于 undefined ,如果是则意味着没有传这个参数,那就给它赋一个值:
function myFunction(x,y){
if(y === undifined){
y = 0;
}
}
但在 ES6 后就不用这么麻烦,因为它支持显示定义默认参数了。
function myFunction(x,y = 0){
//代码块
}
函数内部
在 ES5 中,函数内部存在两个特殊的对象:arguments 和 this。在 ES6 中,又新增了 new.target 属性。
arguments 对象
JavaScript 函数有个内置的对象 arguments 对象。
arguments 对象包含了函数调用的参数数组。
通过 arguments 对象可以很方便的找到函数参数。
x = sumAll(1, 123, 500, 115, 44, 88);
function sumAll() {
var i, sum = 0;
for (i = 0; i < arguments.length; i++) {
sum += arguments[i];
}
return sum;
}
this 对象
this 对象用来引用把函数当作方法调用的上下文对象。this 到底引用哪个对象必须到函数被调用时才能确定。
function myFunction() {
return this;
}
myFunction(); // 返回 window 对象
new.target 对象
函数既可以作为构造函数来实例化一个对象,也可以作为方法被调用。ES6新增了用来检测函数的用途的属性 new.target 。
当函数用来实例化一个对象时,new.target 将引用被调用的构造函数;如果用来作为方法被调用,则 new.target 的值是 undefined 。
函数的属性
前面提到函数是对象,因此有属性和方法。
每个函数都有两个属性:length 和 prototype。
- length:保存函数定义的命名参数的个数。
function sum(num1,num2){
return num1 + num2;
}
console.log(sum.length);//2
- prototype:保存公共方法,如toString ( )、valueOf ( )等方法,进而可以被所有实例共享。
函数的方法
函数有两个预定义的方法:call ( ) 和 apply ( )。
这两个方法都用来调用函数。且第一个参数必须是 this 或调用函数的对象本身。
区别在于传参的方式不同。call( )传参必须一个一个列出来。
function myFunction(a, b) {
return a * b;
}
myObject = myFunction.call(myObject, 10, 2); // 返回 20
function myFunction(a, b) {
return a * b;
}
myArray = [10, 2];
myObject = myFunction.apply(myObject, myArray); // 返回 20
闭包
闭包实际上是一种利用作用域链的机制来保护私有变量的机制。在函数调用期间形成一个不销毁的栈环境。通常体现为嵌套函数里面的匿名函数。
var add = (function () {
var counter = 0;
return function () {
return counter += 1;
}
})();