函数的五种声明方式
![](https://img.haomeiwen.com/i15505523/522ce35b38a8e9bb.png)
![](https://img.haomeiwen.com/i15505523/b8d529fce7676d65.png)
![](https://img.haomeiwen.com/i15505523/7c5521439a2d23ff.png)
console.log打印出来的和返回的没关系。不用管他为什么返回undefined,因为它源代码写了
1.具名函数
![](https://img.haomeiwen.com/i15505523/7847a505d0e6b100.png)
没有返回值的话一般会写一个return undefined就算你不写return undefind 也会自动给你补上。
2.匿名函数
匿名函数需要先给一个变量,然后赋值给变量要不然会报错
![](https://img.haomeiwen.com/i15505523/b9561e50d58f2fdc.png)
3.把有名字的函数赋值给变量
![](https://img.haomeiwen.com/i15505523/32d6c415895e6fa9.png)
但是比如var x = function y (){},然后你console.log(y)的时候会报错,因为这个y只能在x内部用,你在外面是会报错的。y的作用域在里面。然后你console.log(x)的话会打出y(){}。这个居然面试经常考。
4.
![](https://img.haomeiwen.com/i15505523/a04ffc86be8cb5bc.png)
里面都是字符串,用字符串拼接。这个这么奇怪有人用吗?
5.最炫的
![](https://img.haomeiwen.com/i15505523/6f2516a4a3ec1e65.png)
如果只有一句话可以把return和{}都去掉。如果函数体里面内容太多的话可以用enter或者用分号隔开。
![](https://img.haomeiwen.com/i15505523/971da407728424ff.png)
![](https://img.haomeiwen.com/i15505523/e37da3c356f329e8.png)
如果参数只有一个,那么()可以去掉。
![](https://img.haomeiwen.com/i15505523/40f52cd201c5a5f6.png)
那以后可以都用这个方法。所以其实就是把function变成了=>,然后如果只有一个参数就能少了()只有一句return的话可以省略{}和return。不过看着高级很多。
name
![](https://img.haomeiwen.com/i15505523/79d4b72a20caa1de.png)
![](https://img.haomeiwen.com/i15505523/fafb74fed977fd3f.png)
变量是直接用的,用函数叫做调用
call
函数到底是啥,内存是怎么存的
![](https://img.haomeiwen.com/i15505523/b12101bcae640db5.png)
stack里面就放了f这个变量名,f的内容是object的地址,objec里面存放了函数的代码,全部以字符串的形式存着。另外这个object有一个--proto--:Function 指向函数的公共属性。这个公共属性里面有一个call的API可以调用函数。
函数=函数名+参数+函数体
再回顾一遍
![](https://img.haomeiwen.com/i15505523/f57da53aafa2d228.png)
![](https://img.haomeiwen.com/i15505523/3400a25ea2486539.png)
eval:给字符串,然后把字符串当代码执行
![](https://img.haomeiwen.com/i15505523/7f1be17896d38860.png)
自己造一个函数,先搞个对象,然后加一个call的属性,call里面用eavl把函数执行了
![](https://img.haomeiwen.com/i15505523/6bff350a5ad40233.png)
所以执行函数的时候平时直接f()实际上是f.call(),所以直接打f没用,出来的是这个函数的代码。打f()才能执行函数体的结果。
函数终极问题:可以执行代码的对象,叫做函数
![](https://img.haomeiwen.com/i15505523/40a90440eb3eece4.png)
这是js数据结构的知识体系,函数主要特殊在他的公共属性,有call,apply,bind还重写了toString本来object公共属性有toString的。一般都用 它的,函数用自己的toString。还有其他一些对象比如Date Error等
世纪难题:
为什么大家不用f.call(undefined,1,2)而是用f(1,2),第一种才是正确的,以后调用都这么写。因为第二种对学this很有帮助,第一种不行。
![](https://img.haomeiwen.com/i15505523/7834ed13a8984a11.png)
![](https://img.haomeiwen.com/i15505523/f2dcd1c5f90086cd.png)
反正听方方的没错,以后都用f.call(undefined,1,2)就行了
this和arguments
![](https://img.haomeiwen.com/i15505523/6b52c2aacfd6355e.png)
![](https://img.haomeiwen.com/i15505523/c9e7201a6d7165f7.png)
普通模式下,如果this是undefined浏览器会默认把this变成window
![](https://img.haomeiwen.com/i15505523/c95cd755bda5e127.png)
如果用'use strict'开启严格模式,那this就是undefined
![](https://img.haomeiwen.com/i15505523/88ebe579c8de997a.png)
如果f.call()传入其他参数,那么this就会打出其他参数。反正结果就是f.call的第一个参数就是this,后面所有参数加起来是arguments
那this怎么来的呢?为啥要有this
![](https://img.haomeiwen.com/i15505523/a608452c3b1003f3.png)
就跟new Number没人用,f = new Function()没人用一样,this也是当初设计的时候强行要像java所以js之父没办法就放到f.call里面去了。目的是吸引java程序员来学js,然后学了以后发现果然是长得像还可以更方便,然后就上当了。所以这些东西都是打广告用的。
![](https://img.haomeiwen.com/i15505523/34752153e7198e9a.png)
arguments就是除了第一个参数后面的参数。这些参数会组成一个伪数组。啥是伪数组?__proto__ 不等于array.prototype的。上面__proto__是指向Object的不是指向array。所以它看着像数组但是没有数组的公共属性,不能用数组的API,比如push这些都不能用。
![](https://img.haomeiwen.com/i15505523/93f811c7d03c8d2b.png)
正常的数组是会指向Array的。
方方说得画内存图就是画原型链
call stack
之所以存在stack是因为本来内存按顺序每个地址上面放了代码。然后按地址顺序开始执行代码,突然到了function a这里发现这个a的内容是其他函数的地址,那就得跳到那个函数去执行啊。那待会儿我怎么回来呢?那就用一个叫stack的放a的地址,待会我回来就去stack里面拿地址。
但是如果function a内部又有函数functionb、b里面又有function c怎么办呢?同样再把这个function b、function c的地址放到stack里面把,待会c的函数执行完了我再看一下stack就行了。
那现在stack里面放了三个函数的地址了。我计算机会先拿哪个地址呢?如果我拿了a的地址,那我c执行完直接回到主函数去了,因为a在主函数上。所以a,b都没执行完啊。因为我是a执行了一半去b的,b执行到一半去c的。本来c执行完我是要拿到c的地址继续执行b剩下代码,然后拿到b地址执行a剩下代码,然后拿到a地址执行主函数代码。
所以从结论上就是新进后出,从计算机上看它只要去找stack里面放的地址,从上往下一个个拿就行了,不用多想。如果没了那就执行主函数。
1.function a(){
function b(){}
function c(){}
}
2.function a(){
function b(){
function c(){}
}
}
注意1,2的stack是不一样的。
1的顺序是:1.a入栈 2.b入栈 3.b出栈 4.c入栈 5.c出栈 6.a出栈
2的顺序是:1.a入栈 2.b入栈 3.c入栈 4.c出栈 5.b出栈 6.a出栈
![](https://img.haomeiwen.com/i15505523/038eed8944e85657.png)
判断语句也会入栈
上面同一时间压了5次栈,如果同意栈太多会不会不够呢?
![](https://img.haomeiwen.com/i15505523/1860a25b8a0d51d5.png)
会报错,叫做stack overflow是栈溢出的意思
有句话叫做声明的时候不加var就在声明全局变量,这句话是不完全正确的。
![](https://img.haomeiwen.com/i15505523/a90d27cb5ad3a0d1.png)
这种情况下,在f1里面a = 3,它会认为在给a赋值,然后在f1里面找a有没有声明。发现没有就去找全局发现有了,然后就给这个全局的a赋值。
![](https://img.haomeiwen.com/i15505523/7868df05d30aa4b1.png)
这种情况,如果a = 3找了f1发现没有,就在全局有没有声明。发现还是没有,那除了赋值就顺便声明了一下a然后作为全局变量。然后再赋值。
所以f2的a如果要想是局部变量,必须得加var,要不然会往上查,查到声明为止然后再赋值。
找声明不会往下找
浏览器拿到代码以后第一步就是变量提升,把全局,局部全部找好。文字好懂,实际容易错。
![](https://img.haomeiwen.com/i15505523/dd956cdbfafc97bf.png)
为啥console.log(a)打印出undefined呢?因为变量提升!!!!
![](https://img.haomeiwen.com/i15505523/f4619b8380314ac2.png)
变量提升以后就这个样子了,所以console.log(a)的时候a在f1的范围内只做了声明还没有赋值。只声明没赋值就是undefined
![](https://img.haomeiwen.com/i15505523/99864bc6ba7fc97d.png)
![](https://img.haomeiwen.com/i15505523/21c3158655bfe4a2.png)
![](https://img.haomeiwen.com/i15505523/864ad278387749eb.png)
a =2 在 f4.call()前面的话,f4.call()打印出来a是2,如果a = 2 在 f4.call()后面,那打印出来就是 a = 1
闭包
![](https://img.haomeiwen.com/i15505523/f2f63e9aa3359825.png)
想知道细节就搜:方应杭 闭包
课后题:
![](https://img.haomeiwen.com/i15505523/a801ace2bba5a032.png)
![](https://img.haomeiwen.com/i15505523/746e1a06345af74f.png)
![](https://img.haomeiwen.com/i15505523/2de4e8b14096aad1.png)
![](https://img.haomeiwen.com/i15505523/0d592c71f8601006.png)
![](https://img.haomeiwen.com/i15505523/988a4fc2484c296e.png)
![](https://img.haomeiwen.com/i15505523/982d13eaa270b7b7.png)
![](https://img.haomeiwen.com/i15505523/f0b189816cd4c36d.png)
![](https://img.haomeiwen.com/i15505523/25b269a3d12f1402.png)
![](https://img.haomeiwen.com/i15505523/e63a2f23ada28d8c.png)
![](https://img.haomeiwen.com/i15505523/7b7069f7c3bae203.png)
![](https://img.haomeiwen.com/i15505523/eab1b7cf0889a74f.png)
![](https://img.haomeiwen.com/i15505523/7a8dc1d0fbae5f41.png)
![](https://img.haomeiwen.com/i15505523/bd9c03ad19cb9cce.png)
![](https://img.haomeiwen.com/i15505523/326b91e207e809c2.png)
![](https://img.haomeiwen.com/i15505523/469081ba7709de51.png)
![](https://img.haomeiwen.com/i15505523/e6c06f173e635ee7.png)
![](https://img.haomeiwen.com/i15505523/062826e79e981796.png)
![](https://img.haomeiwen.com/i15505523/a9168be74dbde602.png)
![](https://img.haomeiwen.com/i15505523/6f3f7c18647ee3c8.png)
![](https://img.haomeiwen.com/i15505523/22e3c9966a909414.png)
网友评论