你不知道的This和Class

  • Oh no....我的This又丢失了???
  • 为什么我用Class'实例化'出来的对象会相互影响???

这些问题都是因为JS的运行机制造成的。在JS中所有的一切都是对象,而this是对象的一个属性。在对象被调用时,this动态的根据上下文环境进行绑定,因此this和词法作用域没有关系。

一、何谓this

  1. this是函数执行上下文对象的一个属性,存在于运行时,而不是定义时,所以它和词法作用域没有必然的关系。
  2. 要使用this,首先需要考虑的是函数的调用环境而不是编写定义环境。它不指向函数本身,也不指向词法作用域。它由函数调用时发生在上下文环境的绑定而决定。
  3. 使用this要找函数的调用位置,而不是函数的声明位置。调用栈记录了函数的调用位置和顺序。通过调试工具可以查看调用栈,找出函数的调用位置。调用时使用了谁的上下文,this就指向谁。特别要注意的是回调函数传递的是引用,所以会丢失this。真正执行回调函数的位置决定了this的指向。
  4. bind把用来硬绑定函数执行的上下文,用于硬绑定this。(在React组件构造函数中显示的绑定This,防止丢失上下文环境)。除此之外,赋值表达式会传递函数的引用,它的调用位置会变成函数声明的位置。
  5. JS中Class对象的构造函数不是其它面向对象语言的构造函数,它是对已有函数的构造调用,本质上也是This的绑定。new关键字看上去像实例化对象,其实只是根据已有函数生成新的函数对象,并通过new关键字将this绑定到新创建的对象的调用上下文环境中。比如,var test =new foo(),用 new 来 调用 foo(..) 时,我们会构造一个新对象并把它绑定到foo(..) 调用中的 this 上。
  6. 箭头函数本身没有this,它在执行时会捕获调用所在词法作用域父函数的this。捕获绑定之后无法再次被修改。()=>的this是和词法作用域有关系的。而function定义的函数是和词法作用域没有关系的,只和调用环境有关系。http://stackoverflow.com/questions/35813344/do-es6-arrow-functions-still-close-over-this-even-if-they-dont-use-it
  7. this和JS中的Class可以关联使用,通过this的重新绑定可以实现混入 '父类'属相和方法的功能,也就实现了隐士的类似Class的伪多态。
根据下面这四条规则来判断this的绑定对象。
  1. 由 new 调用? 绑 定 到 新 创建 的 对象。
  2. 由 call 或者 apply( 或者 bind) 调用? 绑 定 到 指定 的 对象。
  3. 由上下文对象调用? 绑定到那个下文对象。
  4. 默认: 在严格模式下绑定到undefined,否则 绑 定 到 全局 对象。

二、何谓对象

  1. 从数据结构的角度来看,对象就是键/ 值对的集合。不论是String、Number、Function还是Array、JSON,它们构成对象后都是键/值对的集合。
  2. 函数就是对象的 一个 子 类型( 从 技术 角度 来说 就是“ 可调 用的 对象”)。
  3. 对象和变量一样作为二进制编码存储。
  4. 对象的内容是由 一些 存储 在特定命名位置 的( 任意 类型 的) 值 组成 的, 我们 称之为属性。对象存储在内存中,组成它的属性存储在其它位置。
  5. 直接声明的字符串类型是字面量类型。只是引擎会自动将字面量转化为 String对象。
  6. 对象的每个属性都有属性描述符“writable( 可 写)、 enumerable( 可 枚举) 和 configurable( 可 配置)”等。实际上'.属性名'这样的操作是触发了Get操作。
getter/setter:用来自定义对象属性的取值和赋值操作,会覆盖掉对象默认的[[Get]]和[[PUT]]算法。
  • 不论直接访问函数,还是通过属性访问函数,都是访问的函数引用。
  • 遍历对象属性的每个迭代器都可以接收一个回调函数,这个回调函数会应用到对象的每个属性上。forEach会遍历数组中的每一个元素。every会一直遍历直到回调函数返回false,some会一直遍历直到回调函数返回true。for...of...,直接遍历对象的属性或者数组的值,而不是遍历数组下标。

三、Class的本质

  1. 首先特别注意,JS没有类(对象的抽象模式/蓝图),只有对象,因此继承只能通过原型链来实现。JS中只有对象,可以粗俗的理解为所有的一切都是对象,它是真正面向对象。new关键词的作用就是将新产生的对象的原型链指向定义的函数对象本身。继承的含义是其它语言的复制机制,而在JS中不存在真正的继承机制,而是关联机制。在JS中是创建两个对象的关联。constructor并不是构造,只是指向了一个函数,把自己要做的事情委托给了自己原型链上关联的对象的方法。
  2. 类/ 继承描述 了一种代码的组织结构形式—— 一种 在 软件 中 对 真实 世界 中 问题 领域 的 建模 方法。面向 对象 编程 强调 的 是 数据 和 操作 数据 的 行为 本质上 是 互相 关联 的( 当然, 不同 的 数据 有 不同 的 行为), 因此 好的 设计 就是 把 数据 以及 和 它 相关 的 行为 打包( 或者说 封装) 起来。“类"也是一种设计模式,设计思想。面向 对象 设计 模式, 比如 迭代 器 模式、 观察者 模式、 工厂 模式、 单例模式。建筑师提前设计好房屋,但是不关心建在哪里和建造多少个。建筑 和 蓝图 之间 的 关系 是 间接 的。 你 可以 通过 蓝图 了解 建筑 的 结构, 只 观察 建筑 本身 是 无法 获得 这些 信息 的。 但是 如果 你想 打开 一 扇 门, 那就 必须 接触 真实 的 建筑 才行—— 蓝图 只能 表示 门 应该 在哪, 但 并不是 真正 的 门。一个 类 就是 一张 蓝图。 为了 获得 真正 可以 交互 的 对象, 我们 必须 按照 类 来 建造( 也 可以说 实例 化) 一个 东西,这个东西就是对象,所以对象就是 类 中 描述 的 所有 特性 的 一份 副本。JS中的类的继承和实例化并不会发生复制行为,所以它不是真正的类。它不会创建副本,而只是对象之间被关联起来了。
  3. 标准面向对象语言中构造函数是属于类的,而在JS中类是属于构造函数的。JS中父类和子类的关系只存在于构造函数对应的.prototype中,所以构造函数只是一个委托关系函数,不能生成对象的副本。继承:实质上复制父类的副本,不会改变父类的方法,但在JS中不是这样的。所以说JS中是伪多态,js本身不提供多重继承机制。JS中的类继承是通过mixin或者prototype来实现的。
  4. 每一个JS对象都有一个内置的Prototype属性,它保存了对其它对象的引用。所有普通的原型链的尽头都是Object.prototype,它有很多通用的功能。对函数原型链的修改有时候会产生隐形属性屏蔽,并没有修改到原型链上。ES6的Class是显示伪多态的语法糖,是通过原型链来实现的,原型链委托的一种语法糖。
  5. 因为JS的原型链机制,所以JS可以使用两种设计思想,面向对象和委托关联(不同于.Net中的委托,不要误解)。
  6. 面向对象:是通过new来调用对象函数,并把新生成的对象的行为封装在new 调用对象中。对象关联(委托):根据父对象创建子对象对齐的关联,然后逐步调用父对象的中的方法。
  7. 这是两种设计思想。Class只是把动态语法降低难度写上去像静态语法,虽然书写难度降低了,但是对理解底部真是的引擎运行机制形成了误导。委托调用的设计思想比面向对象的设计思想更加接近JS的真实运行机制。
super不像this是动态绑定的。因为动态绑定开销很大,它是在声明时静态绑定的。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,723评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,485评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,998评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,323评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,355评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,079评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,389评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,019评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,519评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,971评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,100评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,738评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,293评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,289评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,517评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,547评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,834评论 2 345

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,600评论 18 139
  • 特别说明,为便于查阅,文章转自https://github.com/getify/You-Dont-Know-JS...
    杀破狼real阅读 689评论 0 1
  • 1,javascript 基础知识 Array对象 Array对象属性 Arrray对象方法 Date对象 Dat...
    Yuann阅读 891评论 0 1
  • 1. this之谜 在JavaScript中,this是当前执行函数的上下文。因为JavaScript有4种不同的...
    百里少龙阅读 988评论 0 3
  • 为什么我每次都是自己一个人,每次都是我自己,我为什么总是孤独的,对我来说为什么爱这么难,我是犯过什么罪吗。
    旧事酒浓sad阅读 212评论 0 0