button执行onclick函数_JavaScript函数详解

8bda8c70b21e837e60a75049b9dadf3a.png
本文 目录:
  • 函数的 5 种声明
  • return
  • 词法作用域
  • 执行上下文
  • js的变量提升
  • this arguments
  • 不同场景的this指向
  • call apply bind
  • call stack
  • 闭包
  • 柯里化/高阶函数
  • 回调
  • 构造函数

函数的 5 种声明

1.具名函数

function 

2.匿名函数

var 

3.具名函数赋值

var 

4.window.Function 函数对象

var 

5.箭头函数

var 

return

每个函数都有 return
如果你不写 return,就相当于写了 return undefined

词法作用域

如题:

3bd75893706efb58c432bf8d1f6fdb37.png

作用域其实就是一个树:

05819dc604676f01a4f0d93a5fbc6d7d.png
编译型语言,编译步骤分为:词法分析、语法分析、语义检查、代码优化和字节生成。
而解释型语言,通过词法分析和语法分析得到语法分析树后,就可以开始解释执行了。

js执行过程:

  1. 读入第一个代码段(js执行引擎并非一行一行地执行程序,而是一段一段地分析执行的)
  2. 做词法分析和语法分析,有错则报语法错误(比如括号不匹配等),报错后不再向后执行
  3. 对【var】变量和【function】定义做“预解析“(永远不会报错的,因为只解析正确的声明)
  4. 执行代码段,有错则报错(比如变量未定义)
  5. 如果还有下一个代码段,则读入下一个代码段,重复步骤2
  6. 结束

上面的过程,我们主要是分成两个阶段

javascript解析:就是通过语法分析和预解析构造合法的语法分析树。javascript执行:执行具体的某个function,JS引擎在执行每个函数实例时,都会创建一个执行环境(ExecutionContext)和活动对象(activeObject)(它们属于宿主对象,与函数实例的生命周期保持一致)

测试:

var 

查看:词法作用域

执行上下文

每调用一个函数,就会创建一个新的执行上下文。

上下文建立过程:

  1. 声明变量,函数,确定arguments对象,参数
  2. 做词法分析形成语法分析树,建立作用域链
  3. 确定this的值
  4. 变量赋值,函数引用,执行其它代码
var 

第一步:

var a,b,foo;

第二步:

48ad2a3e842cc4cb4ddc8058e47327ba.png

第三步:

全局环境内this为window

b.fn 和 b.fn1内this为b

foo内this为window

第四步:

a 

题外:如果 let a = 10, foo > this.a 返回undefined

因为let存在块级作用域,所以let a=10 仅在全局window下有意义

402dba63accb576efc79ee9895562614.png

如下的道理:

{
   

js的变量提升

执行代码前,先变量提升!!

例1:

7bbafa20c6cf9319f94da7a9af30370c.png

结果:3 undefined 1

例2:

var 

例3: ul 下有5个li,点击打印的都是5,因变量i提升到全局

d3feb9ac1ea7d54dc1e6cdd451294679.png

this 和 arguments

设计this的初衷是js必须长得像java。this 就是 call 的第一个参数!call 的其他参数统称为 arguments
当传参为undefined时,this为window(除严格模式下是undefined):

2da61b2c67f85963a082f969941f4f66.png


this 是call的第一个参数,且一般是对象或undefined,this让函数有一个可依托的对象,每个函数都有两个对象,如果不传this就是window,如果传的不是对象,就会帮你转换为对象(除严格模式),不传argument就是空数组,arguments是一个伪数组

function 

转为对象:

ef6dc83c22e139305056d53e4851a90d.png
  1. 希望里面的函数和外面的函数 this是一样的,需要使用箭头函数
  2. function本身一定有this,每次进入函数,一定把他弄到callStack里面,确定一个this,没传也会给你一个this,就是window,如果不想指定this,就使用箭头函数,因为没有this,且永远无法指定,this是每次进入一个函数都会被传一个值的变量,不是普通变量
  3. 编译器打印的this是global, global对象是单体内置对象,即不依赖宿主环境的对象,而window对象依赖浏览器
  4. 箭头函数不可以做构造函数,没有this,arguments
  5. 箭头函数也不能指定this

58fd299fa3b19118712bf856a5fd9b31.png

关于arguments的length:

7d4ed5b75c30f1d49f286123ad336321.png

此外:局部变量i和形参i指向同一个存储地址

function 

不同场景的this指向

  1. fn() 里面的 this 就是 window
  2. fn() 是 strict mode,this 就是 undefined
  3. a.b.c.fn() 里面的 this 就是 a.b.c
  4. new Fn() 里面的 this 就是新生成的实例
  5. () => console.log(this) 里面 this 跟外面的 this 的值一模一样
  6. $("#btn").on("click",function(){ 事件监听里面的this是监听的那个DOM对象,就是#btn})
  7. 使用事件委托的事件监听里面的this仍然是开头绑定的DOM对象
  8. setInterval,settimeout 里面的this是window
改变this指向通过 apply,call ,bind

call apply bind

函数调用的本质 call,call原意为调用

语法:f.call(asThis, input1,input2)

其中 asThis 会被当做 this,[input1,input2] 会被当做 arguments

fn.call(asThis, p1,p2) 是函数的正常调用方式,而fn(p1,p2)是语法糖。

当你不确定参数的个数时,就使用 apply 。

没有call的世界:

var 

如果用call:

var 

call 和 apply 是直接调用函数,而 bind 则是返回一个新函数(并没有调用原来的函数),这个新函数会 call 原来的函数,call 的参数由你指定。

举例:错误示范:

var 

这里this.element.onclick 里面的this是element,如果需要调用click方法,

第一种:

var 

第二种使用bind:

var 

具体查看call apply bind 的整理

call stack (栈,先进后出)

js是单线程语言,执行函数1进入新环境时会做一个记号,return后从这里退出,如果函数1里面还有函数2,再做一个记号,这些记号就保存在栈里面,这个栈就叫做调用栈,出来的时候先退出函数2,再退出函数1,这就是调用堆栈

1.普通调用 1+1+1

function 

2.嵌套调用 1>2>3

7d169b4b45ae7c6d663d6c1b741e7deb.png

a.call() >>进入a(栈1),

b.call() >>进入b(栈3),

c.call() >>进入c(栈5),

其中a先进去最后出来,出来次序为栈5>栈3>栈1

3.递归

function 

ddf0d25135df50ae7bceb3a30a6c632a.png

栈溢出:超出最大栈数则溢出报错

测试: 我的电脑最多 9665个栈

a05a0f7234ab5b27ed6bc709108ddd05.png

闭包Closure

如果一个函数,使用了它范围外的变量,那么(这个函数+这个变量)就叫做闭包。

查看:关于闭包的理解

柯里化/高阶函数

柯里化

简单说:返回函数的函数,参数比原函数少一个参数

应用:柯里化可以将真实计算拖延到最后再做, 可以做惰性求值

>>柯里化:将 f(x,y) 变成 f(x=1)(y) 或 f(y=1)x

//柯里化之前

关于柯里化的高级文章:

  1. http://www.yinwang.org/blog-cn/2013/04/02/currying
  2. https://zhuanlan.zhihu.com/p/31271179

高阶函数

wiki:在数学和计算机科学中,高阶函数是至少满足下列一个条件的函数:

1.接受一个或多个函数作为输入:forEach sort map filter reduce

2.输出一个函数:bind, lodash.curry

fn.bind.call(fn,1,2,3)

3.不过它也可以同时满足两个条件:Function.prototype.bind

应用:将函数任意的组合

7b44c4f744416882d1009cc2f9364482.png

回调callback

名词形式:被当做参数的函数就是回调
动词形式:调用这个回调
注意回调跟异步没有任何关系

    1. 同步回调 eg: arr.forEach(function(){})
    2. 异步回调 eg: setTimeout(f, 1000) >> setTimeout("console.log(1)",1000)>>字符串其实就是一个函数

构造函数

返回对象的函数就是构造函数
一般首字母大写,使用:

function 

关于new:

new是语法糖,只是少几行代码。。


柯里化测试题:

请写出一个柯里化其他函数的函数 curry,这个函数能够将接受多个参数的函数,变成多个接受一个参数的函数,具体见示例(这是 lodash.curry 的文档示例):

function 

答案:

function 

end~

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值