一起来啃《JavaScript语言精粹》----函数

一、调用

  • <strong>方法调用模式</strong>
    当一个函数被保存为对象的一个属性时,我们称它为一个方法。如果调用表达式包含一个提取属性的动作,那么它就是被当做一个方法来调用。
Paste_Image.png

方法可以使用this访问自己所属的对象,通过this可取得它们所属对象的上下文的方法称为公共方法。

  • <strong>函数调用模式</strong>
    当一个函数并非一个对象的属性时,那么它就是被当做一个函数来调用:
    var sum = add(3, 4);//7
    以此模式调用函数时,this被绑定到全局对象。


    Paste_Image.png

    这事语言设计的一个错误,错误后果就是方法不能利用内部函数来帮助它工作,因为内部函数的this被绑定了错误的值,所以不能共享该方法对对象的访问权。
    <b>解决方案:</b>
    为该方法定义一个变量并给它赋值为this,那么内部函数就可以通过那个变量访问到this:


    Paste_Image.png
  • <strong>构造器调用模式</strong>
    如果在一个函数前面带上 new 来调用,那么背地里将会创建一个连接到该函数的prototype成员的新对象,同时 this 会被绑定到那个新对象上。
    //创建一个名为Quo的构造器函数。它构造一个带有status属性的对象。
    var Quo = function(string){
    this.status = string
    }
    //给Quo的所有实例提供一个名为get_status的公共方法。
    Quo.prototype.get_status = function(){
    return this.status;
    };
    //构造一个Quo实例。
    var myQuo = new Quo('confused');
    myQuo.get_status()//'confused'
  • <strong>Apply调用模式</strong>
    apply方法让我们构建一个参数数组传递给调用函数。它也允许我们选择this的值。apply方法接收两个参数,第一个是要绑定给this的值,第二个就是一个参数数组。
Paste_Image.png

二、扩充类型的功能

  • 我们可以通过给Function.prototype 增加方法来使得该方法对所有函数可用


    Paste_Image.png

    通过给Function.prototype 增加一个method方法,我们下次给对象增加方法的时候就不必键入prototype这几个字符,省掉了一点麻烦。

  • JavaScript没有专门的整数类型,但有时候确实只需要提取数字中的整数部分。JavaScript本身提供的取整方法有些丑陋。我们可以通过Number.prototype增加一个integer方法来改善它。它会根据数字的正负来判断是使用Math.ceiling还是Math.floor。


    Paste_Image.png
  • PS:这里需要指出的是Javascript的原型继承机制,可以形象的理解为Object是祖师爷爷,Function既当爹又当妈,剩下的Number,String,Array等都是儿女:
    Number,String,Array => Function => Object
Paste_Image.png
  • 另外,基本类型的原型是公用结构,所以在类库混用时务必小心。一个保险的做法是只在确定没有该方法时才添加它。
    //符合条件时才增加方法。
    Function.prototype.method = function(name,func){
    if(!this.prototype[name]){
    this.prototype[name] = func;
    }
    return this;
    }

三、闭包

  • 我们通过调用一个函数的形式去初始化myObject,该函数会返回一个对象字面量。函数里定义一个value变量。该变量对increment和getValue方法总是可用的,但是函数的作用域使得它对其他的程序来说是不可见的。


    Paste_Image.png

    这个例子我们并没有把一个函数赋值给myObject。我们是把调用该函数后返回的结果赋值给它。

Paste_Image.png

当我们调用quo时,它返回包含get_status方法的一个新对象。该对象的一个引用保存在myQuo中。即使quo已经返回了,但get_status方法仍然享有访问quo对象的status属性的特权。get_status方法并不是访问该参数的一个副本,它访问的就是该参数本身。这是可能的,因为该函数可以访问它被创建时所处的上下文环境,这被称为<b>闭包</b>。

  • 来看一个更有用的例子


    Paste_Image.png

    1.我们调用fade,把document.body作为参数传递给它,fade函数设置level为1.它定义一个step函数,接着调用setTimeout,并传递step函数和一个时间(100毫秒)给它。然后它返回,fade函数结束。
    2.在大约100毫秒后,step函数被调用。它把fade函数的level变量转换为16位字符。接着,它修改fade函数得到的节点的背景颜色。然后查看fade函数的level变量。如果背景色尚未变成白色,那么它增大fade函数的level变量,接着用setTimeout预定让它自己再次运行。
    3.step函数很快再次被调用。但这次,fade函数的level变量值变成2.fade函数在之前已经返回了,但只要fade的内部函数需要,它的变量就会持续保留。

  • <b>从一个经典的错误说起</b>
    构造六个div,当点击一个div时,按照预期,应该打出相应div的值,但是它总是会显示div的数量。因为事件处理器函数绑定了变量i本身,而不是函数在构造时的变量i的值,i始终无法被释放。
Paste_Image.png

避免在循环中创建函数,它可能只会带来无谓的计算,还会引起混淆,正如上面那个经典的错误。我们可以先在循环外创建一个辅助函数,让这个辅助函数再返回一个绑定了当前i值的函数,这样就不会导致混淆了。改良后的例子,用正确的方式给一个数组中的节点设置事件处理程序


Paste_Image.png

另一种解决办法,这里我们用一个立即执行函数给它包住,我们不再依赖i,而是用另外一个变量n把它保留下来。

Paste_Image.png

四、记忆

  • 函数可以将先前操作的结果记录在某个对象里,从而避免无谓的重复运算。这种优化被称为<b>记忆</b>。JavaScript的对象和数组要实现这种优化是非常方便的。
    比如说,我们想要一个递归函数来计算Fibonacci数列。一个Fibonacci数列是之前两个Fibonacci数字之和。最前面的两个数字是0和1。


    Paste_Image.png

    但是这样做了很多无谓的工作。fibonacci函数被调用了453次。如果我们让该函数具备<b>记忆</b>功能,就能显著地减少运算量。
    我们在一个名为memo的数组里保存我们的存储结果,存储结果可以隐藏在闭包中。当函数被调用时,这个函数首先检查结果是不是已经存在,如果存在,就立即返回这个结果。


    Paste_Image.png

    这个函数返回的结果相同,但是它只被调用了29次。
  • 我们可以编写一个函数来帮助我们构造带<b>记忆</b>功能的函数。memoizer函数取得一个初始的memo数组和formula函数。它返回一个管理meno存储和在需要时调用formula函数的recur函数。我们把这个recur函数和它的参数传递给formula函数:


    Paste_Image.png

    现在,我们可以使用memoizer函数来定义fibonacci函数,提供其初始的memo数组和formula函数:


    Paste_Image.png

    通过设计这种产生另一个函数的函数,极大地减少了我们的工作量。例如,要产生一个可以记忆的阶乘函数,我们只需提供基本的阶乘公式即可:
    Paste_Image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容