2

JavaScript函数

面试考点比较密集
参考阮一峰JavaScript函数
我的博客:关于作用域,变量提升,函数提升的个人理解笔记

1.函数的五种声明方式

1.1 具名函数

var 声明一个变量,七种数据类型
function 声明一个函数,是个特例
不写return自动加上return undefined

 function f(x,y){
     return x+y
 }
 f.name // 'f'

Cf4kWj.png

1.1.1 关于console.log()
  1. console.log()返回undefined
  2. console.log()会在传入的参数里首先调用toString()方法
    CfhjSA.png
  3. 但是当打印到控制台的时候,没有写双引号,是chrome浏览器的原因

Cf4iFg.png

  1. 比如可以在重写console.log()

Cf4QkF.png

1.2 匿名函数

 var f
 f = function(x,y){
     return x+y
 }
 f.name // 'f'

如果要声明匿名函数,就一定要把它赋给一个变量
Cf4gnP.png

1.3var x = function y(){}

var f
 f = function f2(x,y){ return x+y }
 f.name // 'f2'
 console.log(f2) // undefined

直接声明function y(){}var x = function y(){}的区别

Cf420f.png
然后刷新页面

Cf4fAS.png
直接报错,说y没有定义

区别:
Cf44hQ.md.png
第一种方式可以打印,第二种打印说不存在.
第一种整个外面的区域都可以访问y,第二种只有函数内部才可以访问到y.(可以访问的区域就是绿色圈起来的区域)
Cf4qBV.md.png

1.4 window.Function

window.Function

 var f = new Function('x','y','return x+y')
 f.name // "anonymous"

基本不会用

1.5 箭头函数

箭头函数都是匿名函数,没有名字,就像是匿名函数的简写形式
CfIBQA.md.png
三种

箭头函数

 var f = (x,y) => {
     return x+y
 }
 var sum = (x,y) => x+y//如果return只有一个,可以省略return和{}
 var n2 = n => n*n//如果参数只有一个,可以省略()

CfI2FS.png

五种方式总结

CfI4Qs.png

2.函数的name属性

所有的函数都有一个name属性,他是一个字符串


1具名函数
 function f(x,y){
     return x+y
 }
 f.name // 'f'
 
2匿名函数
 var f
 f = function(x,y){
     return x+y
 }
 f.name // 'f'
 
3具名函数赋值
 var f
 f = function f2(x,y){ return x+y }
 f.name // 'f2'
 console.log(f2) // undefined
 
4window.Function
 var f = new Function('x','y','return x+y')
 f.name // "anonymous"
 
5箭头函数
 var f = (x,y) => {
     return x+y
 }

f.name//"f"

3.函数的本质

3.1函数的调用

调用的英文单词call
函数在内存中为字符串

3.1.1函数在内存中:

Cf7edP.md.png
即函数也是一个对象,广义上

3.1.2 eval()函数

给一个字符串.返回的为:字符串转化成代码然后执行.'
Cf71Mj.png

3.1.3函数就是对象

模拟函数本质
Cf7Yd0.png
函数是一个对象,里面有参数,函数体,调用方法
f是函数,是对象,f.call()是一个执行函数体的方法

总结

js中有七种数据类型,

number string boolean null undefined
symbol **object**

前六种是简单类型,object是前6种的各种组合,所以是复杂类型
原型链
Cf72FK.md.png

3.1.4函数的调用:f(1,2)f.call(undefined,1,2)

f(1,2)是简单用法
f.call(undefined,1,2)才是真实的用法

Cf7xyj.md.png
用call 便于理解this,是硬核技术
call用法:
CfH9wq.png
参数从第二个开始

4.thisarguments

CfxSo9.md.png

arguments是参数数组
CfxKJI.png

4.1 this

特例:当call()的第一个参数是undefined的时候, thiswindow.
ChnJgO.png

Chn0UI.png

当启用严格模式的时候,call 里的第一个参数是什么,this 就是什么
ChnB5t.png
this的作用先不说

4.2 arguments是参数组成的伪数组

伪数组:里面有0123这些次序,也有length,长得像数组,但是.伪数组的__proto__没有指向的是 Array.prototype,或者说原型链中没有Array.prototype,即原型链中没有和Array.prototype有关的 ,也就是说只是一个像数组的对象而已.
ChnbMF.png
没有 push

5 call stack 调用栈

每进入一个函数,就在栈里记录一个记号,当调用完之后return的时候,就跳到做的记号哪里,弹出栈里的记号
ChuSG6.md.png
调用演示:
普通调用
嵌套调用
递归调用

5.1 Stack Overflow错误

堆栈溢出
ChuHYt.png
超出call stack调用栈

segment fault也是一种错误,c语言里面的

6. 作用域

什么情况下直接使用 a=1 会使a直接变成全局变量(window.a)?
当写a=1这个代码的时候,首先计算机会认为这是赋值,当发现当前作用域没有声明a的时候,就继续往上找,看看上一层的作用域有没有声明a,就这样,一直找到window层即全局作用域层,就直接给全局变量window自动声明一个a.
就近原则,哪一个scope离赋值最近,赋值的就是哪一个作用域
我的博客:关于作用域,变量提升,函数提升的个人理解笔记

这个f4里面的a只能是他自己本身的作用与和他的父作用域,跟f1里面的a没有关系
ChtJ2j.png
f4打印出来的a是1

Cht6z9.png
所有的代码解析完毕,这时候i已经是6.
所以当点击的时候,已经是解析完毕后的i,点击的时候就是执行最开始绑定过的函数,点击相当于在最后写下执行函数的代码,这时候i已经是6了,所以打印出来的是6.for循环结束之后就是6.

liTags[i].onclick = function(){
     console.log(i)
}//在这里只是声明函数,并没有调用,运行这段代码只会解析代码,不会运行函数
//当点击事件发生的时候,就相当于调用这个函数,当调用的时候,已经被解析成6了点击速度不可能超过解析速度

同理,下面代码打印出的是6
Cht4IO.png

闭包定义

ChNAe0.md.png

题目

ChNeFU.png

ChNmYF.png

ChNKSJ.png

ChNMl9.png

ChN3ex.png
ChN8w6.png

ChN0OI.png

ChNDmt.png
特例:当call()的第一个参数是undefined的时候, thiswindow.


风彻
1.5k 声望142 粉丝