JavaScript 函数重中之重
- 函数的五种声明方式
- 如何调用函数
- 什么是call stack
- this 和 arguments
- 作用域
- 闭包
function 函数名(参数,参数2){执行代码,return 结果} 就像一个过滤器,放进参数,输出结果.
如何声明一个函数?
- 具名函数
function x(输入1,输入2){
return undefined
}
注意: 变量可以是7种(null undefined boolean string number symbol object)类
型,但是函数变量是变量的特例.
- console.log() 括号里面只接受字符串,如果不是将会调用对象的toString方法
- 因为函数永远有一个return返回值,所以即使是console.log()返回undefined因为console的源代码也是用一个函数来实现的,函数自带一个默认return undefined.
- console只是打印一个对象,并不是返回一个对象.undefined是来自于他的源代码函数自带的默认返回值
- 匿名函数 var a = function (){} //这是第二种声明方法 var a = function b(){}//这是第三种声明方法
- 具名函数function v(){ } 与 匿名函数 var a = function v(){} 的区别在于? 变态之的地方在于具名函数 console.log(v) 返回函数;匿名函数 报错. 同样的语法摆在不同的位置,意义不一样,这就是不一致,就是垃圾
- 函数的第四种声明是window.Function a = new Function('x','y','return + x+y')
函数第五种声明就是箭头函数
- sam = (x,y)=>{return x+y} 如果只有一个语句,可以去掉return和花括号,这是一起去掉的; 所以上面的函数等价于 sam= (x,y)=>x+y
- 如果参数只有一个,(括号)也可以省掉sam=x=>x*x
- 箭头函数是匿名函数,没有名字的
- 如果花括号里面要放多个语句,那么就用分号
函数的name属性
- 所有函数都有一个属性,如果是具名函数name就是名字;如果是匿名函数,name就是变量,如果两边都有的话:var f3 = function f4(){} ;f3的name是'f4'
- 如果是用new产生的,那么他的name就是匿名(anonymous)
数据是可以直接用的,但是函数是要调用的
函数到底是什么?
- 阮一峰说的 函数就是一堆代码的组合,说了等于没说.函数就是代码块,什么意思呢? 函数就是一段可以反复调用的代码块/函数还能接受输入不同的参数返回不同的值.
函数内存
- 函数代码块里面的内容是被当成字符串存在内存里面.
- 两种不同声明函数的方式,不同的内存方式:
- 具名函数: function f (x,y){return x+y} f 存一个地址,指向heap一块内存,这块内存存有2个东西.一个是params[x,y] 另外一个就是fbody{return x + y};这块内存又指向Function 函数对象,使用他的call方法
用内存实现一个函数是怎样的呢?//eval 这是一个把字符串当成代码执行的函数
利用内存原理,写出函数的代码.
var f = {}
f.name = 'f'
f.params= ['x','y']//这个是假设的的属性
f.functionBody='console.log('xxxx')'
f.call = function(){return window.eval(f.functionBody)}
//这里穿插一个知识点,为什么要用函数包装Window......这些代码给f.call而不是直接用? 个人认为应该是用函数有利于扩展,日后更改代码可以直接在函数内增删改查代码,而直接赋值就没有这个功能,而且直接赋值直接给一个值,而不是一个函数地址,两者的内存不一样.
// 这样就清楚了f 与f.call的区别了,f只是一个函数,f.call是执行这个函数体
那么函数的本质我们就知道了:可以执行代码的对象就是函数
- 那么f.call(硬核hardcore) 为什么不用f(糖sweet)? // 实际上f.call才是JavaScript真正的用法,f()是给小白用的,这对于领悟this有很大的意义
- f.call()怎么用???
什么是this? f.call(undefined,1,2) undefined就是this;[1,2]就是arguments
// call的第一个参数可以用this得到,call后面的参数可以用arguments得到
- 在普通模式下,f.call(undefined)这个undefined//也就是this,默认是Window
- 也就是说f.call(第一个参数就是this)// JavaScript中的this 就是因为当年JavaScript研发的时候,老板要求开发的语言像java,这个历史原因造成的
- arguments是一个伪数组: 伪数组就是具有数组键值对的形式,还有lengh,但是没有指向Array原型,也就是说一个对象的proto(甚至整个原型链)没有指向Array.prototype,所以它缺失了真正数组所具备的一些属性,比如push.
- 一句话总结,call的第一个属性就是this,其他后面的就是arguments,因为历史原因本来一个argument搞定,但是强行搞了一个this来.
JavaScript函数调用,stack内存与heap内存的过程
- 多层函数调用(穿越时空)就相当于有存档的走迷宫
- 递归函数的调用,就像有存档的楼梯探险
- 当stack内存被爆掉
JavaScript中的作用域就是树
-注意一句很错误的话:没有用var 声明的变量,a =3 声明的就是全局作用域的变量a,这是很错误的话. 首先a=3是一个赋值语句,他是赋值给a,但是当前作用域没有,就会沿着作用域链网上找,直到找到a赋值给他.如果没有a,也就是说整个作用域都没有,就会声明一个a并赋值给他,这时候才是叫 声明了一个全局作用域a,并赋值3给他.
- 穿越时空,就近原则.