这里只讨论function(){}类型的函数
1. 在js中,function函数是什么
-
是对象,一种特殊的对象,可以通过在后面添加括号来调用
-
有三个隐含参数:
- name:函数的名字。如果是匿名函数,那name的值就是anonymous;
在实际环境中打印匿名函数的name,会输出''
-
length:函数形参的个数
-
code:函数逻辑的代码,以字符串的形式储存在内存中。 当执行到一个函数的调用语句时,V8便会从函数对象中取出code的属性值,也就是函数代码,然后再解释执行这段函数的代码
在实际环境中打印函数的code,会输出undefined
2. 形参、实参,分别是什么意思
- 形参就是在声明函数的时候,所填入的参数。该参数会在函数实际调用的时候,被赋予真正的值。可以理解为形参就是占位用的,形式参数
//此处声明了一个函数foo
//a, b 两个就是这个函数的形参
function foo( a, b ){
return a + b;
}
- 实参是在函数调用的时候,所填入的参数,此处填入的参数具有真实值,所以被叫做实参--实际参数;
在下面的例子中,我们可以知道
- 形参和实参的名字可以不一样
- 实参可以为变量,也可以为常量
//此处调用了上面声明的foo,并且填入了两个实参
const param1 = 12;
foo(para1, 23);
3. 如何获取形参,或者实参的个数
- 形参的个数可以通过函数的名字来访问
//下面,变量len的值就是函数的形参个数了
const len = foo.length;
console.log(len);
- 实参的个数,可以通过在函数内部访问arguments来获取
function foo( a, b ){
//在函数foo被调用的时候,此处就在控制台打印了实参的个数
console.log('length:', arguments.length);
return a + b;
}
4. 匿名函数和非匿名函数
- 下面的例子中,foo就是非匿名函数,也就是又名的函数,又叫具名函数。
- bar等式右边就声明了一个匿名函数,然后将这个匿名函数赋给了bar这个变量,之后bar所指向的就是该函数,最后得到了一个具名函数。即bar(), 就是调用该函数
- 第三个例子,直接获取匿名函数的name,得到了一个空字符串''
function foo( a, b ){
return a + b;
}
console.log(foo.name); //'foo'
const bar = function(){
return a + b;
}
console.log(bar.name); //'bar'
const name_3 = (function(){
})().name;
console.log(name_3); //''
5. 匿名函数的缺点
- 在非匿名函数内部调用自身,可以直接引用函数的名字。
- 而匿名函数调用自身的时候,就没有名字可以引用了。
在之前的javascript中,只能使用已经过期的arguments.callee引用自身
6. 剩余参数、默认参数、结构赋值是什么意思
- 剩余参数可以实现定义数量不定的形参
function sum(...theArgs) {
return theArgs.reduce((previous, current) => {
return previous + current;
});
}
console.log(sum(1, 2, 3));
// expected output: 6
console.log(sum(1, 2, 3, 4));
// expected output: 10
- 默认参数,当我们声明一个函数的时候,填入了两个形参,当用户没有传入其中一个参数的时候,我们要赋予其默认值
function foo( a, b = 0 ){
return a + b;
}
foo(12); //12
foo(12,11); //23
- 结构赋值。我们在声明函数的时候,形参可能是一个对象,或者是数组,我们想快速的获取对象当中某个字段的值,这个时候我们可以用结构赋值
function foo( { name } ){
console.log(name);
}
const Bob = {
name:'bob name';
}
foo(Bob); //'bob name'
还可以嵌套解构
function foo({ name, brithDate: { time } }) {
console.log('name: ', name);
console.log('day: ', time);
}
const Bob = {
name: 'bob name',
brithDate: {
day: '2021-09-09',
time: '20:00'
}
}
foo(Bob);
//name: bob name
//day: 20:00
7. 我们在函数的执行的时候,是否可以改变形参的值呢?
函数中是否包含剩余参数、默认参数、结构赋值,决定了arguments对象是否会跟踪参数的值
function func(a) {
arguments[0] = 99; // 更新了arguments[0] 同样更新了a
console.log(a);
}
func(10); // 99
function func(a) {
a = 99; // 更新了a 同样更新了arguments[0]
console.log(arguments[0]);
}
func(10); // 99
const foo = function(n){
if(n===1){
return;
}
console.log(n);
foo(n-1);
}
function func(a = 55) {
arguments[0] = 99; // updating arguments[0] does not also update a
console.log(a);
}
func(10); // 10
function func(a = 55) {
a = 99; // updating a does not also update arguments[0]
console.log(arguments[0]);
}
func(10); // 10
8. 文档中的特别要求
arguments不允许被泄露。可能是因为里面有涉及到代码安全的信息
- 下面的例子中,返回arguments,在arguments上面调用slice,将arguments包含在返回函数的闭包中,都算泄露
为什么在arguments上面调用slice也不行呢?
- 对参数使用slice会阻止某些JavaScript引擎中的优化 (比如 V8 - 更多信息)。如果你关心性能,尝试通过遍历arguments对象来构造一个新的数组。另一种方法是使用被忽视的Array构造函数作为一个函数:
- 估计有泄漏的风险,所以不建议
function leaksArguments1() {
return arguments;
}
function leaksArguments2() {
var args = [].slice.call(arguments);
}
function leaksArguments3() {
var a = arguments;
return function() {
return a;
};
}
- 创建一个新的数组不算是泄露
function doesntLeakArguments() {
//.length is just an integer, this doesn't leak
//the arguments object itself
var args = new Array(arguments.length);
for(var i = 0; i < args.length; ++i) {
//i is always valid index in the arguments object
args[i] = arguments[i];
}
return args;
}
结尾小技巧:快速创建html列表的方法
定义创建HTML列表的方法
这个例子定义了一个函数通过一个字符串来创建HTML列表。这个函数唯一正式声明了的参数是一个字符。当该参数为 "u" 时,创建一个无序列表 (项目列表);当该参数为 "o" 时,则创建一个有序列表 (编号列表)。该函数定义如下:
function list(type) {
var result = "<" + type + "l><li>";
var args = Array.prototype.slice.call(arguments, 1);
result += args.join("</li><li>");
result += "</li></" + type + "l>"; // end list return result;
}
你可以传递任意数量的参数到该函数,并将每个参数作为一个项添加到指定类型的列表中。例如:
var listHTML = list("u", "One", "Two", "Three");
/* listHTML is: "<ul><li>One</li><li>Two</li><li>Three</li></ul>" */
总结:
-
在js中,function函数是什么?
- 函数就是一个特殊的对象
-
形参,实参分别是什么意思?
- 一个声明函数时期的函数,一个调用函数时期的函数
-
如何获取形参或者实参的个数?
-
匿名函数和非匿名函数表示什么意思?
-
匿名函数的缺点?
- 无法调用自身
-
剩余参数、默认参数、结构赋值表示什么意思?
- 第一个是功能性的优化,第二,第三个是写法上的简化
-
在函数执行的时候,是否可以改变形参的值?
- 非严格模式下,没有剩余参数,默认参数,结构赋值的话,可以改变
-
文档中特别要求,谨防arguments泄露
- 可能是基于安全考虑吧,我也不太懂
-
快速创建html列表。原始html开发中,相同的功能的代码。包装成函数特别有效
- 思想很重要