1. 函数的返回值由什么确定?
答:’x1’
当初在JS故意这么设计的,如果a像参数x一样也是在调用的时候确认的话,那和干脆把a也直接传入不就好了,所以a由定义时的环境决定。
同理:下图结果为’x2’
2. 闭包
对象也可以模拟闭包
1 2 3 4 5 6
| const self = { _a: 1, fn() { return this.a++ } }
|
函数可以模拟对象
1 2 3 4 5 6 7 8 9 10 11
| function fn(age, name) { return function(key) { if (key === 'age') return age; if (key === 'name') return name; } }
const obj = fn('18', 'zch') obj('age') // 18 obj('name') // zch
|
3. this(this是参数,箭头函数中this是环境)
答button是错的!
完美打法,我现在无法确定this的值是什么(this只有在调用的时候才能确定*(因为this是参数)*),如果是用户点击时调用的话,this就是button,如果 var fn = button.onclick; fn()
,此时的this就是window
看到此题时,我们先改写
1 2 3 4 5 6 7 8 9 10 11
| let length = 10 function fn() { console.log(this.length) }
let obj = { lengh: 5, methods(fn) { fn.call(undefined) arguments[0].call(arguments) } } obj.methods.call(obj, fn, 1)
|
所以第一次打印出的值是 window.length
(窗口中iframe的个数)
第二次为 arguments.length
(函数实参的个数)
记法
3. 闭包
如果在函数里面能访问外面的变量,那么这个函数+这些变量=闭包
并不是所有语言都有闭包, ruby
就没有, ruby用def声明的函数就不能使用闭包, 使用lambda才可以
4. 递归
栗子:阶乘
调用栈中的图:
栗子:斐波那契数列(0,1,1,2,3,5………)每一项都是前两项的和
我们发现在计算中会爆栈,因为会重复计算,如下图,会重复计算
解决方法:尾递归优化或者记忆化函数
- 尾递归
js基本不考虑,语言没有做优化,依旧会记忆很多东西
- 记忆化函数
1 2 3 4 5 6 7 8
| const fn = (n) => { let array = [0, 1] for (let i = 0; i < n-2; i++) { array[i+2] = array[i+1] + array[i] } return array[array.length-1] }
|
react 中的记忆栗子
测试题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| const memo = (fn) => { 请补全 }
const x2 = memo((x) => { console.log('执行了一次') return x * 2 }) console.log(x2(1)) console.log(x2(1)) console.log(x2(1))
|
答案
5.科里化
1 2 3
| const add = (a, b) => a + b
const add = a => b => a+b
|
分析: const add = a => b => a+b
一、正常理解我们可以拆解为两个部分1. 函数接受一个参数 a。2. 返回一个函数 b => a + b。即:
1 2
| >const add = a => b => a +b
|
二、如果是函数式的思想来理解,将会拆解成如下两部分1. 接受参数a, 接受参数b。2.返回a+b
1 2 3
| >const add = a => b => a + b
|
测试题
1 2 3 4 5 6 7 8 9 10 11 12
| const currify = (fn, params = [])=> 请补全
addTwo = (a,b)=>a+b addThree = (a,b,c)=>a+b+c
newAddTwo = currify(addTwo) newAddThree = currify(addThree)
console.log(newAddTwo(1)(2)) console.log(newAddThree(1)(2)(3))
|
答案
6.高阶函数
把函数作为参数或者返回值的函数。
推理 bind.call()
是什么意思
1 2 3 4 5 6 7 8 9 10 11
| var bind = Function.prototype.bind const fn = function() { console.log('this', this) console.log('arguments', arguments) }
const newFn = fn.bind({ name: 'zch' }, 1, 2, 3)
const newFn = fn.bind.call(fn, { name: 'zch' }, 1, 2, 3)
bind.call(fn, { name: 'zch' }, 1, 2, 3)
|
所以就是第一个参数是fn,所以bind把函数作为参数的函数,验证bind为高级函数。
- apply
- call
- sort
- map
- filter
- reduce
同理
函数组合(pipe)
1 2 3 4 5 6 7 8 9 10 11 12
| function dobuleSay(str) { return str + ', ' + str } function capitalize(str) { return str[0].toUpperCase() + str.substring(1) } function exclaim(str) { return srt + '!' }
let result = exclaim(capitalize(dobuleSay(str))) // 痛点:这样子的写法太麻烦 // "Hello, hello"
|
如果使用将来的js语法 |>
改写
1 2 3 4 5 6 7 8
| let result = "hello" |> doubleSay |> captitalize |> exclaim
// 如果现在想用,只能使用 Ramda.js 库 // const say = R.compose(doubleSay, captitalize, exclaim) // let result = say('hello')
|
可以应用 react 组件之中,比如 from 的表单提交按钮,可以放到外部
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| function App() { return ( <div> <From> <button>提交</button> // 注意:此时的button无法将From元素提交出去,所以我们将使用高级组件 </From> </div> ) }
function From() { const submit = () => console.log('submit') return ( <div> //...一堆的表单组件 {props.children} </div> ) }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| function App() { return ( <div> <From> { submit => (<button onClick={submit}>提交</button>) } // 这里改成函数的形式,返回button组件 </From> </div> ) }
function From() { const submit = () => console.log('submit') return ( <div> //...一堆的表单组件 { props.children() } // 这里改成调用 </div> ) }
|