1.多参数
在js中,Math.max()方法可以接受任意数量的参数,
Math.max(1,2,3,4);//4
Math.max(1,2,3,4,5,6,7,8,9,10)//10
在max方法里面有一个rest参数,它接受了所有参数全部合成到了一个number数组里面,
function rest(a,b,...arg){// 使用rest 参数时,必须放在参数列表的最后console.log(arg);
}rest(1,2,3,4,5,6,7,8,9,10)//[3,4,5,6,7,8,9,10]
注意:使用rest 参数时,必须放在参数列表的最后
rest参数:类似扩展运算 ...,rest参数也使用...符号,但它的功能相反,在定义函数时使用,表示将多余的参数收集到一个数组中
和扩展运算区分开
- 扩展运算:用于使用方法时,拆分数组或对象
- rest参数 :用于定义方法时,合并参数
使用rest参数可以任意多个参数合成一个数组,并在函数内调用,理论上来说函数使用rest可以使用无数多个参数,
实现max方法
// 对rest参数进行比较
function myMax(...args) {// 设置max接受最大值,初始值为第一个参数let max = args[0];// 遍历数组,如果当前值大于max,则将max设置为当前值args.forEach((item)=>{if(item>max){max=item;}})return max;
}
console.log(myMax(1,2,3,4,30,5,6,7,8,9,10));//30
2.函数属性
在js中函数也是对象,一个函数也能像对象一样设置属性,同时它还有一些默认属性
console.dir(function name(){})
name
绝大部分函数都有name属性值,它存储了函数的名称
function fn(){console.log(fn.name);return fn.name;
}fn();//fn
console.log(fn());//fn fn
console.log(fn.name);//fn
值得注意的是,函数属性是绑定在函数对象上的,在函数体外也能访问
// 对于赋值给变量的函数,函数本身是匿名的,函数name是变量名,
// 非匿名函数赋值,函数name是函数名
const f = function(){};
const fun = ()=>{}
const Fn = function F(){}console.log(f.name);//f
console.log(fun.name);//fun
console.log(Fn.name);//F
对于赋值给变量的函数,函数本身是匿名的,函数name是变量名,非匿名函数赋值,函数name是函数名,
没有name属性值的情况
// 没有name属性值
const fArr = [function(){}]
console.log(fArr[0].name);//''
length
函数的length属性表示了函数形参的个数,但是不包括rest参数
function fa(a,b,c,...arg){console.log(fa.length);return fa.length;
}
console.log(fa.length);//3
fa(1,2,3,4,5,6,7,8,9,10);//3,和实参数量无关
要注意和argments的length区分开
- function.length:表示的是函数除了rest参数外的形参数量,定义函数时的普通参数个数
- argments.length:表示使用函数时的实参数量,使用函数传入的参数个数
自定义函数属性
除了默认的属性,还可以自定义函数的属性
function add(){ return add.count++;
}add.count = 0;
console.log(add(),add(),add(),add());//0 1 2 3
设置函数属性,可以重写一个闭包结构,关于闭包可以参考:
js闭包------简单理解闭包含义_js 闭包累加-CSDN博客
// 使用内置变量的闭包
function count(){let sum = 0;return function (){return sum++;}
}
const addSum = count();console.log(addSum(),addSum(),addSum(),addSum());//0 1 2 3// 使用函数属性的闭包
function c(){c.count = 0;return function (){return c.count++;}
}
const addCount = c();console.log(addCount(),addCount(),addCount(),addCount());//0 1 2 3
都达到了累加的效果,但是它们的区别在于,闭包中的变量不能被外部访问,而函数属性可以被外部访问
c.count = 20;
console.log(addCount());//20
注意:count++会先赋值在自增
3.字符串生成函数
使用字符串生成函数:接受一串字符串,将字符串转成函数,这常常在服务端返回脚本时的场景使用,
常规生成一个函数的方法有,function,new Function,
eval()
eval()将传入的字符串当做 JavaScript 代码进行执行,这是一个危险的api,容易被注入攻击,
let str = `function newFn(){console.log('这是eval改变字符串新生成的函数')
}`//eval()函数会将字符串作为JavaScript代码进行解析和执行
eval(str);
newFn();//这是eval改变字符串新生成的函数
new Function()
new Function()会将字符串转成函数体内容
// new Function()() 也可以将字符串作为函数体进行解析和执行
new Function('console.log("这是new Function()改变字符串新生成的函数")')();//这是new Function()改变字符串新生成的函数
let newF= new Function('console.log("这是new Function()改变字符串新生成的函数")');
newF();//这是new Function()改变字符串新生成的函数
setTimeout()
setTimeout()会将字符串参数识别成函数执行,
// 使用setTimeout()函数
setTimeout(`(function newFn(){console.log('这是setTimeout()改变字符串新生成的函数')})()`
);//这是setTimeout()改变字符串新生成的函数
第一个参数支持输入函数或者字符串,字符串会自动解析成js代码,第二个参数没有时会被塞到事件队列最前面等待执行,所有这是一个异步过程,
script标签
可以通过script标签的innerHTML属性将字符串转成函数,但是这种方法只能在浏览器种使用,node环境下是没有dom对象的
// 使用script标签
const script = document.createElement('script');
script.innerHTML = `(function newFn(){console.log('这是script标签改变字符串新生成的函数')
})()`
document.body.appendChild(script);//这是script标签改变字符串新生成的函数
这是一个同步的代码,在setTimeout之前执行
总结
一共有以上4种方法将字符串改成函数
异步: setTimeout()
同步:eval() ,new Function(),script标签
完整代码以及运行结果展示
// 1.多参数的函数,rest参数
Math.max(1,2,3,4);//4
Math.max(1,2,3,4,5,6,7,8,9,10)//10// Math.max()方法可以接受任意数量的参数,
// 类似扩展运算符...,rest参数也使用...符号,但它在定义函数时使用,表示将多余的参数收集到一个数组中。
function rest(a,b,...arg){// 使用rest 参数时,必须放在参数列表的最后console.log(arg);
}rest(1,2,3,4,5,6,7,8,9,10)//[3,4,5,6,7,8,9,10]// 对rest参数进行比较
function myMax(...args) {// 设置max接受最大值,初始值为第一个参数let max = args[0];// 遍历数组,如果当前值大于max,则将max设置为当前值args.forEach((item)=>{if(item>max){max=item;}})return max;
}
console.log(myMax(1,2,3,4,30,5,6,7,8,9,10));//30// 2.函数属性console.dir(function name(){})// name
function fn(){console.log(fn.name);return fn.name;
}fn();//fn
console.log(fn());//fn fn
console.log(fn.name);//fn// 对于赋值给变量的函数,函数本身是匿名的,函数name是变量名,
// 非匿名函数赋值,函数name是函数名
const f = function(){};
const fun = ()=>{}
const Fn = function F(){}console.log(f.name);//f
console.log(fun.name);//fun
console.log(Fn.name);//F// 没有name属性值
const fArr = [function(){}]
console.log(fArr[0].name);//''// length
function fa(a,b,c,...arg){console.log(fa.length);return fa.length;
}
console.log(fa.length);//3
fa(1,2,3,4,5,6,7,8,9,10);//3,和实参数量无关// 自定义函数属性function add(){ return add.count++;
}add.count = 0;
console.log(add(),add(),add(),add());//0 1 2 3// 使用内置变量的闭包
function count(){let sum = 0;return function (){return sum++;}
}
const addSum = count();console.log(addSum(),addSum(),addSum(),addSum());//0 1 2 3// 使用函数属性的闭包
function c(){c.count = 0;return function (){return c.count++;}
}
const addCount = c();console.log(addCount(),addCount(),addCount(),addCount());//0 1 2 3c.count = 20;
console.log(addCount());//20// 字符串生成函数let str = `function newFn(){console.log('这是eval改变字符串新生成的函数')
}`//eval()函数会将字符串作为JavaScript代码进行解析和执行
eval(str);
newFn();//这是eval改变字符串新生成的函数// new Function()() 也可以将字符串作为函数体进行解析和执行
new Function('console.log("这是new Function()改变字符串新生成的函数")')();//这是new Function()改变字符串新生成的函数
let newF= new Function('console.log("这是new Function()改变字符串新生成的函数")');
newF();//这是new Function()改变字符串新生成的函数// 使用setTimeout()函数
setTimeout(`(function newFn(){console.log('这是setTimeout()改变字符串新生成的函数')})()`
);//这是setTimeout()改变字符串新生成的函数// 使用script标签
const script = document.createElement('script');
script.innerHTML = `(function newFn(){console.log('这是script标签改变字符串新生成的函数')
})()`
document.body.appendChild(script);//这是script标签改变字符串新生成的函数