定义
常规定义
function 函数名(参数)
{
...
}
匿名函数
无需给函数取名,举例:
let x = function() { ... }
箭头函数
举例:
let x = data => { ... }
通过原型构建
通过Function
对象,可以构建函数,举例:
x = new Function("x", "y", "return x + y")
x(1, 2)
// 3
函数参数
函数里参数个数和调用时传入的参数个数没有限制,比如:
function fun(x,y)
{
alert(x)
alert(y)
return x+y
}
alert(fun(1))
结果依次弹出:
1 undefined NaN
因为只传入1,所以x=1,但是y没有值所以就是未赋值的undefined
,而number和一个非number相加,就会显示NaN
上面那个调用时还可以传入超过函数定义的参数个数,举例:
alert(fun(1,2,3,4,5))
结果依次弹出:
1 2 3
arguments
函数参数还可以用arguments
来代替,其相当于一个数组,用来存放传过来所有实参,函数如果有形参,就分别按顺序对应,比如arguments[0]
对应第一个形参…,且arguments
接收参数数量不限,举例求接收的所有参数值之和:
function abc() {
num = 0;
for (i = 0; i < arguments.length; i++) {
num += arguments[i]
}
return num;
}
alert(abc(1, 2, 3, 4, 5, 6));
注意点
函数声明function xxx(){}/xxx = function(){}区别
前者会被加入到window
对象里,后者用let
之类的声明就不会压到window
对象里,举例:
console.log(window.history);
function history() {
console.log(1);
}
console.log(window.history);
// 会发现window.history被覆盖了,不过这里由于涉及到函数提升问题,所以如果一起执行会发现两次输出的都是被覆盖过的函数
而使用let
结果:
console.log(window.history);
let history = function() {
console.log(1);
}
console.log(window.history);
// 会发现history没有覆盖window对象下的history
因此前者也被称为全局函数定义,后者为匿名函数定义
函数提升
test();
function test() {
...
}
会发现执行成功,相当于:
function test() {
...
}
test();
而匿名函数的方式则不一样:
test();
let test = function() {
...
}
会发现test没定义,因为let的暂时性死区问题,然后通过var
定义:
test();
var test = function() {
...
}
会发现test定义了,但不是一个函数,因为变量提升,test
现在是undefined,即下面这样:
var test;
test();
test = function() {
...
}
立即执行函数
通过该方式作为插件之类的时候可以避免作用域冲突问题:
(function() {
function aaa() {}
})()
例如下面这块代码,aaa就无法被直接使用,此时我们可以将其放入一个对象里,对外暴露接口:
(function(window) {
function aaa() {}
function bbb() {}
window.$ = {aaa, bbb}
})(window)
$.aaa()
// 此时aaa和bbb必须通过`$`来调用
当然通过let
定义匿名函数的话,上面的内容还可以这样解决:
{
let aaa = function () {};
let bbb= function () {};
window.$ = {aaa, bbb}
}
caller/callee
参考:
https://blog.csdn.net/qq_17335153/article/details/52575064
https://blog.csdn.net/chaoguo1234/article/details/81277945
https://blog.csdn.net/Web_J/article/details/88995450