name:可以获得函数的名称function foo(){ } console.log(foo.name);//foo'运行
length:用于返回函数参数的个数,rest参数不算在内var bar = (name, age, ...args) => { } console.log(bar.length);//2'运行
arguments 是一个 对应于 传递给函数的参数 的 类数组(array-like) 对象。函数的所有参数都会传给arguments:
function foo(x, y) { console.log(arguments) // [arguments] {'0': 10, '1': 20, '2': 30, '3': 40} } foo(10, 20, 30, 40)'运行
array-like表示它不是一个数组类型,而是一个对象类型:
将arguments转成Array后可以使用数组的一些特性。
方法1:遍历arguments,添加到一个新数组中
var newArray = [] function foo(x, y) { for (arg of arguments) { newArray.push(arg); } } foo(1, 2, 3, 4, 5) console.log(newArray);//(5) [1, 2, 3, 4, 5]'运行
方法2:调用数组slice函数的call方法,了解即可
对数组做一个截取,截取的是this。
这里slice没有参数,所以是从头截取到尾。
把this绑定到arguments上,就可以截取整个arguments。
function foo() { var args1 = [].slice.call(arguments) console.log(args1); } foo(1, 2, 3, 4, 5, 6)//(6) [1, 2, 3, 4, 5, 6]'运行
方法3:ES6中的两个方法
Array.fromfunction foo() { var args1 = Array.from(arguments) console.log(args1); } foo(1, 2, 3, 4, 5, 6)//(6) [1, 2, 3, 4, 5, 6]'运行
[…arguments]function foo() { var args1 = [...arguments] console.log(args1); } foo(1, 2, 3, 4, 5, 6)//(6) [1, 2, 3, 4, 5, 6]'运行
箭头函数是不绑定arguments的,所以我们在箭头函数中使用arguments会去上层作用域查找:
var bar = () => {
console.log(arguments);
}
bar(1, 2, 3)
//报错:ncaught ReferenceError: arguments is not defined
箭头函数不绑定arguments,于是就会去上层找:箭头函数——全局——window。发现都没有就报错了。
ES6中引用了rest parameter,可以将不定数量的参数放入到一个数组中。
如果最后一个参数是 … 为前缀的,那么它会将剩余的参数放到该参数中,并且作为一个数组。
function foo(x, y, ...rest) { console.log(x, y);//1 2 console.log(rest);//[3,4,5] } foo(1, 2, 3, 4, 5)'运行
剩余参数与arguments:
满足以下要求则此函数为纯函数:
省流版:
什么是副作用?
在执行一个函数时,除了返回函数值之外,还对调用函数产生了附加的影响
如:修改了全局变量,修改参数或者改变外部的存储。
function foo(info) { console.log(info.name, info.age, info.height); info.flag = "打印结束了"; } var obj = { name: "kaisa", age: 18, height: 1.88, }; foo(obj); console.log(obj);'运行
这里调用函数就为obj添加了一个flag属性,这就是副作用。
纯函数在执行过程中不能产生这样的副作用,因为副作用是bug的温床。
1
var names = ["aaa", "bbb", "ccc", "ddd"]; // slice截取数组时不会对原数组进行任何操作, 而是生成一个新的数组 var newNames1 = names.slice(0, 2); console.log(newNames1); // splice截取数组, 会返回一个新的数组, 也会对原数组进行修改 var newNames2 = names.splice(0, 2); console.log(newNames2); console.log(names);'运行
slice是纯函数,splice函数不是纯函数。
2
function foo(item1, item2) {
return = item1 + item2
}
是纯函数.
3
var foo = 5; function add(num) { return foo + num; } console.log(add(5)); // 10 foo = 10; console.log(add(5)); // 15'运行
不是纯函数.
4
function printInfo(info) { console.log(info.namem, info.age); info.name = "哈哈哈"; }'运行
不是纯函数.
React中就要求我们无论是函数还是class声明一个组件,这个组件都必须像纯函数一样,保护它们的props不被修改。
只传递给函数一部分参数来调用它,让它返回一个函数去处理剩余的参数,这个过程就称之为柯里化
也就是将一个函数从可调用的 f(a, b, c) 转换为可调用的 f(a)(b)©。
举个例子:
柯里化前:
function foo(x, y, z) { console.log(x + y + z) // 60 } foo(10, 20, 30)'运行
柯里化后:
// 柯里化函数 普通写法 function foo1(x) { return function foo2(y) { return function foo3(z) { console.log(x + y + z); // 60 }; }; } foo1(10)(20)(30);'运行
// 柯里化函数 箭头函数写法 var foo = (x) => { return (y) => { return (z) => { console.log(x + y + z); }; }; }; foo(10)(20)(30); // 简写箭头函数 var foo1 = x => y => z => console.log(x + y + z); foo1(10)(20)(30);'运行
优势1:函数的职责单一
如:传入的函数需要分别被进行如下处理
function foo(x) { x = x + 2; return function foo1(y) { y = y * 2; return function foo2(z) { z = z ** 2; return x + y + z; } } }'运行
优势2:函数的参数复用
function makeAdder(num) { return function (count) { return num + count; }; } // 将num参数固定为5, 以后和5相加, 只需要调用add5 var add5 = makeAdder(5); add5(10); // 15 add5(100); // 105 // 将num参数固定为10, 以后和10相加, 只需要调用add10 var add10 = makeAdder(10); add10(10); // 20 add10(100); // 110'运行
实际开发中, 一般引用的第三库中都有自动柯里化的函数。
一种对函数的使用技巧、模式。举个例子:我们想对多个数字进行先*2,再平方的操作。
不组合:
function fn1(num) { return num * 2; } function fn2(num) { return num ** 2; } console.log(fn2(fn1(10)));//400 console.log(fn2(fn1(20)));//1600'运行
组合:
function fn3(num){
return fn2(fn1(num))
}
console.log(fn3(10));//400
console.log(fn3(20));//1600
了解即可。

with语句扩展一个语句的作用域链。
不建议使用 with语句,因为它可能是混淆错误和兼容性问题的根源。
这里如果没有with,js会直接在全局里面找。使用with就可以查找obj中的属性。
var obj = { name: "kaisa", age: 18, height: 1.88, }; //使用with可以查找obj中的属性 with (obj) { console.log(name, age, height); }'运行
更多可以看看这里:JavaScript中 with的用法
内建(内置)函数 eval 允许执行一个代码字符串。
eval是一个特殊的函数,它可以将传入的字符串当做JavaScript代码来运行,如:
var string = `var name = "kaisa"; console.log(name);`; eval(string); // kaisa'运行
eval会将最后一句执行语句的结果,作为返回值,如:
var string = `var name = "kaisa"; console.log(name); 123`; var result = eval(string); console.log(result) // 123'运行
不建议在开发中使用eval:
严格模式对正常的JavaScript语义进行了一些限制:
可以在js文件开启,也可以对某一个函数开启。
严格模式通过在文件或者函数开头使用 use strict 来开启
文件:
<script>
// 给整个script标签开启严格模式
"use strict"
</script>
函数:
function foo() { // 在foo函数作用域中开启严格模式 "use strict"; }'运行
更具体的可以看这里:JavaScript 严格模式(use strict)
在非严格模式下,一些错误也被认为是正确的,但在严格模式下就会报错。如:
1.无法意外的创建全局变量
在非严格模式下, 不使用var变量创建变量, 会默认创建到全局变量
在严格模式下是不允许的,会报错
2.严格模式会使引起静默失败(silently fail,注:不报错也没有任何效果) 的赋值操作抛出异常
"use strict"
var obj = {
name: "why"
}
// 明确设置obj对象中的name属性不可修改
Object.defineProperty(obj, "name", {
writable: false
})
obj.name = "kobe"
console.log(obj.name); // name
非严格模式下不允许修改, 但是也不会报错
严格模式下, 明确说明obj中的name不可修改, 如果修改就会报错
3.严格模式下试图删除不可删除的属性会报错
非严格模式下, 不允许删除, 也不会报错。(无事发生)
4.严格模式不允许函数参数有相同的名称
非严格模式下允许。
5.严格模式不允许0开头的八进制语法
非严格模式下, 0开头的数字都会被默认为八进制
严格模式下, 0开头8进制是不允许写的, 0o是允许的
6.严格模式下,不允许使用with
7.严格模式下,eval不能为上层创建变量
8.严格模式下,this绑定不会默认转成对象
非严格模式下, 字符串和数字类型会转换成对应的包装类对象
严格模式下, 不会转换成对象, 且严格模式下独立函数调用不绑定全局对象window, 而是一个undefined
coderwhy的课
JS高级函数的增强使用、纯函数、柯里化、组合函数的详细介绍-及手写柯里化、手写组合函数
JavaScript函数式编程(纯函数、柯里化以及组合函数)
JavaScript函数的增强知识(argument、纯函数)
MDN-with语句
JavaScript中 with的用法
JavaScript 严格模式(use strict)