说到funciton,也是我对js很是吐槽的一点,封装的让我眼瞎,马蛋的,哥只能大眼睁着去黑盒的使用,简直只有完彻底全的听各种图书对数组
function的道听图说,彻底没有作到一点点的眼见为实。app
一:function是什么函数
在好久好久之前,咱们只知道function是一个函数,用C#的话来讲就是一个方法,既然是方法嘛,确定就是挂在类下面的,可是其实呢?spa
在js中函数就是对象,并非咱们惯性思惟中的方法。何觉得证呢?看代码。prototype
从图中能够看到我声明了一个say函数,可是我很奇怪的看到,为何say函数会有一些属性和方法呢?好比本该属于Object的toString,valueOf,日志
constructor等等?而后比较好奇的去看看constructor究竟是什么,能够看到实际上是个Function构造函数,那这样我就很是清楚了,然来say只不过orm
是Function对象的一个实例引用,知道了这个我就能够很轻松的把代码恢复以下:对象
二:看看function中一些属性和方法继承
如今咱们知道了function其实就是一个对象,咱们知道全部的引用类型都是继承自object,那为了好作比较,我定义了一个object的实例,内存
接下来看看function中到底都有那些专属属性和方法。
能够看到,子类function确实仍是有点本身的东西,那接下来就简单探讨下经常使用的属性和方法。
1. arguments属性
说到这个属性就特么的来气,就眼瞎,眼瞎的地方在于这个arguments属性里面其实作了不少不少的东西,以致于下面的一些奇怪现象
可能会让你目瞪口呆!!!
<1>奇怪现象一:个人function中都没有形参,竟然还能接受到实参的值。。。
<2>奇怪现象2:形参和实参传递并不统一,能够多传递,能够少传递,js都不会报错。
。
<3>奇怪现象3:形参和arguments竟然能够作到同步,太神奇了。
上面的三个现象是否是让你以为很奇怪???这些奇怪的现象是否是让你以为Function中封装的太狠,由于他们作了不少操做,而你却只能大眼
瞪小眼,啥也看不到。。。是否是很是遗憾呢???因为看不到源代码我也无能为力,只能根据书中的讲解以及本身的理解来领悟了。“高程3”中
是这么说的,当调用function中传递的实参实际上是给了Function构造函数中的一个”内部数组“,而arguments实际上是对”内部数组“的高层封装,
封装后的arguments再也不是数组了,而是一个假装的数组,之因此这么说是由于arguments还须要一个本身的独有属性callee,而这个callee
保存的就是当前的对象say,因此只能把arguments作成对象,我可让你眼见为实。
而后最诡异的一个问题就是形参可以和arguments实现数据同步,既然可以作到同步,个人第一个反应就是使用同一块内存地址,可是仔细想一想
他们怎么可能作到共享内存地址呢?可是再想一想的话,arguments是对”内部数组“的封装,我就想这个name应该也是被作过手脚的,也就是说
name其实也是对”内部数组“的封装,就像ECMA5中对字段提供get/set访问器同样,固然这是个人一种猜想,解释代码以下:
从上图中咱们看到,当我对name进行赋值的时候,其实改变的是args这个数组的值,同理当我改变arguments的值时,其实也是修改”内部数组“
的值,经过相似这种方法来达到咱们上层看到的同步机制,画个简图以下:
2. length属性
若是你知道了上面的原理,那这个也好猜想,要么取得是正真的“内部数组”的length,要么就是取伪类arguments的length,反正最终都是
”内部数组”的length,对不对,比较经常使用可是又没什么好说的。
3.prototype属性
这个也是Function内部作出来的一个属性,颇有意思,我想你们也有耳闻,也不是三言两语能说得清楚的,准备放在下篇详细的讲讲。
4.caller属性
看这个名字大概也知道个一二,就是用来获取当前的父函数,不要小看这个caller哦,你有没有想过它能够实现C#中的stacktrace的功能
呢?有时候咱们记js日志就靠这玩意了,好比下面这样。
5:call,apply方法
由于这两个函数的功能都同样,只不过call方法必须逐一参数赋值,而apply必须传递数组,若是想眼见为实,能够看看它们在vs里面的代码
提示,一切都明白了,因此我就放在一块说了,不过这鸟东西有什么好处呢?它最大的好处就是能够随便绑定对象,而后就能够实现对绑定对象
动态新增方法和属性,可能说的有点抽象,看个例子就OK啦。
咱们发现,原本个人obj只是一个空对象,经过apply以后,个人obj对象具备name和age属性了,是否是很神奇呢?