浅谈函数调用

本文是作者在重读 javascript 权威指南函数调用部分的时候的一个笔记, 算下来大概一半是书上的话, 一半是自己的理解再配上一些例子来加深印象, 分享给大家。

正文从这里开始。

函数调用

构成函数主体的 js 代码在定义的时候是不会执行的, 只有在调用该函数的时候它们才会执行。

一共有四种方式来调用 js 函数

  • 作为函数
  • 作为方法
  • 作为构造函数
  • 通过它们的 callapply 来进行间接调用

函数调用

使用调用表达式可以进行普通的函数调用也可以进行方法调用。

对于普通的函数调用, 函数的返回值就是调用表达式的值。如果该函数返回是因为解释器达到了结尾, 返回值就是 undefined。 如果函数返回是因为解释器执行到一条 return 语句, 则返回至就是 return 会后的表达式的值, 如果 return 语句没有值, 则返回 undefined

方法调用

一个方法无非就是个保存在一个对象的属性里的 js 函数。 如果有一个函数 func 和一个对象 obj, 我们就可以为 obj 定义一个名为 method 的方法 :

obj.method = func;

调用的时候就类似这样 :

obj.method();

在方法调用中, 函数表达是本身其实就是一个属性访问表达式, 只不过这个属性访问表达式最终取到的是函数的引用而非是一个具体的值。

对方法调用的参数和返回值的处理, 和上面描述的普通函数调用完全一致。

方法调用和函数调用有一个重要的区别, 就是调用上下文。在刚刚的 obj.method() 里面, 函数的 context 会变为 obj, 所以在函数内部可以通过 this 来取到 obj 的引用。

方法和 this 关键字是面向对象编程范例的核心。任何函数只要作为方法调用实际上都会传入一个隐式的实参, 这个实参实际上是一个对象, 方法调用的母体就是这个对象。

需要注意的就是, this 是一个关键字, 不是变量也不是属性名, 而且 js 的语法也不允许给 this 赋值, 但是可以预存 this, 比如我们在函数内部经常会这样 :

function Promise (func) {
  var resolve = function (val) {
    this.resolve(val);
  };
  var reject = function (val) {
    this.reject(val);
  };
}

Promise.prototype.resolve = function () {};
Promise.prototype.reject = function () {};

接下来我们使用 var pms = new Promise(func) 来搞一个实例, 会惊奇的发现报错了.. 因为此时的 this 会指向全局变量, 而全局变量上面是没有 resolvereject 方法的, 我们的本意是想要通过 this 来拿到实例 pms 的引用, 进而从 pms 上去找到 Promise.prototype.resolve, 这个时候我们就需要把 this 的值预存一下... 就类似这种 :

function Promise (func) {
  var me = this;
  var resolve = function (val) {
    me.resolve(val);
  };
  var reject = function (val) {
    me.reject(val);
  };
}

Promise.prototype.resolve = function () {};
Promise.prototype.reject = function () {};

这样就可以保证在实例化的时候, resolve 函数中的那个 me 指向了实例, 至于这个 Promise 的实现, 具体参考了这里 https://github.com/hanan198501/promise, 当然这不是本文要说的, 只是意在讲预存 this 的重要性

方法链

其实这里就涉及到原来有看过源码的 jQuery 的链式调用的核心了

当方法不需要返回值的时候, 最好直接返回 this, 如果在设计 API 的时候一直采用这个方式, 就可以构成一种链式调用。

构造函数调用

如果函数或者方法调用之前带有关键字 new, 它就构成了构造函数调用。这里其实说明一件事情就说明了整个过程了。

...所以下面就说一下 var person = new Person() 到底发生了什么...

  • 创建一个新的空对象
  • 完成内部 [[prototype]] 的指向绑定
  • Person 内部的 this 全部指向新生成的对象
  • 最后检测 Person 内部有没有 return 一个对象, 如果 return的是一个对象, 则调用表达式的值就是这个对象, 没有return或者return` 的是一个原始值的话, 则调用表达式的结果就是这个新生成的对象

这里会对第二条和第三条特殊的讲一下 :

首先是第二条 : 完成内部 [[prototype]] 的绑定

其实我们打开 chrome 控制台, 敲下 {} 按回车, 点开生成的那个东西, 会有一个 __proto__ 的东西, 这个东西就是内部 [[prototype]] 在浏览器里的实现, 在 es6 里虽然没有写入正文, 但也写入了附录, 所以可以认为是新的标准, 在所有浏览器(包括 IE11) 也都部署了这个属性(__proto__ 的描述来自于阮一峰 ECMAScript 6 入门, 传送门 :
http://es6.ruanyifeng.com/#docs/object#proto属性,Object-setPrototypeOf,Object-getPrototypeOf)。

而第二条就是做了这一个指向, 会把实例 person 内部的 [[prototype]] (我还是更喜欢叫 __proto__ 来着...) 来指向 Person.prototype, 其实也就是这条句子所表明的那样 :

person.__proto__ === person.constructor.prototype;

当然明眼人有看的出来... 其实 person.constructor 就是 Person, 当然 constructor 不是这里要讲的了, 只是用到了....

接下来是第三条 : 把 Person 内部的 this 全部指向新生成的对象

这里的意思其实是, 比如 Person 内部会有很多东西 :

function Person () {
  this.name = 'anning';
  this.age = 22;
}

在调用 var person = new Person() 的时候, 在 Person 内部的 this 指向了新生成的对象, 也就是执行了 :

person.name = 'anning';
person.age = 22;

这一点在很多地方其实都有使用, 比如 jQuery 中对 jQuery.fn.init 构造函数的实现, 就是在 init 函数里面大量使用了 this, 在 this 上挂非继承属性, 最后在生成 jQuery.fn.init 的实例的时候, 使实例的非继承属性, 如 context 属性, 整型属性 [0] 等挂在了每个实例上。

间接调用

间接调用中其实就只有两个方法, callapply

两个方法都允许显式的指定 this 的取值, 也就是说, 所有的函数都可以作为任何对象的方法阿莱调用, 哪怕这个函数不是那个对象的方法。

我们在看到一些库的 this 非常强大的时候, 可能就是在实现的时候, 用 callapply 强行指定的...

原文地址 : http://www.amnhh.xyz/2017/02/07/%E6%B5%85%E8%B0%88%E5%87%BD%E6%95%B0%E8%B0%83%E7%94%A8/

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

推荐阅读更多精彩内容

  • 普通创建对象和字面量创建对象不足之处:虽然 Object 构造函数或对象字面量都可以用来创建单个对象,但这些方式有...
    believedream阅读 2,356评论 2 18
  • 第5章 引用类型(返回首页) 本章内容 使用对象 创建并操作数组 理解基本的JavaScript类型 使用基本类型...
    大学一百阅读 3,212评论 0 4
  • 今天写?明天写? 我迟疑不决。 满腹欣慰提笔,又只好悻悻删除。 无力与绝望来得急促而又汹涌。 我记不得任何东西了。...
    与青云阅读 301评论 0 0
  • 当初我们上大学的时候,第一台电脑买的是15寸的CRT显示器,当时觉得挺不错的,在那个靠拨号上网的时期,能够简单的敲...
    豪哥的世界阅读 845评论 0 2
  • 9月28号,远在欧洲的老板突然在微信上说拿到了12个南山半马的名额。需要我在国庆之后,把具体名额发给他。这意味着我...
    多币阅读 291评论 2 1