你不知道的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是动态绑定的。因为动态绑定开销很大,它是在声明时静态绑定的。

转发自::http://www.cnblogs.com/ssol/

时间: 2024-12-15 06:56:48

你不知道的This和Class的相关文章

你不知道的JavaScript--Item23 定时器的合理使用

1.定时器概述 window对象提供了两个方法来实现定时器的效果,分别是window.setTimeout()和window.setInterval.其中前者可以使一段代码在指定时间后运行:而后者则可以使一段代码每过指定时间就运行一次.它们的原型如下: window.setTimeout(expression,milliseconds); window.setInterval(expression,milliseconds); 其中,expression可以是用引号括起来的一段代码,也可以是一个

你不知道的Javascript(上卷)读书笔记之一 ---- 作用域

你不知道的Javascript(上卷)这本书在我看来是一本还不错的书籍,这本书用比较简洁的语言来描述Js的那些"坑",在这里写一些博客记录一下笔记以便消化吸收. 1 编译原理 在此书中,开始便提出:Javascript是一门编译型语言,我一开始以为这是国内翻译的锅,翻译的不够准确,后来我还专门去github看了,作者确实是将Js描述为一门编译型语言(compiled language).然而我认为作者更想表达的是Js也拥有和Java一般的特定的编译过程.而不是传统得认为只是单纯的进行&

Hadoop备战:hdfs常用命令(可能有你不知道的)

除介绍的命令外,还有许多bin/hadoop.dfs命令,以上介绍的只是帮助你开始使用HDFS,运行bin/hadoop dfs不带任何参数会列出所有FsShell系统提供的命令,当你遇到问题时执行bin/hadoop dfs –help commandName会显示这个命令的用法. 下面是所有命令的介绍,介绍之前先定义一下参数的意义: 1.    斜体:表示用户输入的变量. 2.  path:表示文件名或目录名. 3.    path-:表示一个或多个文件名或目录名. 4.    file:表

你不知道的javascript(上卷卷)笔记

<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>你不知道的javascript(上卷)</title> </head> <body> </body> </html>

你不知道的javascript(中卷)笔记

<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>你不知道的javascript(中卷)</title> </head> <body> <script type="text/javascript"> /* //封装对象包装 var a = new Boolean(false); if(!a)

你不知道的javascript--上卷--读书笔记1

作用域是什么? 答:在<你不知道的javascript>书中提到,作用域就是根据名称查找变量的一套规则.古语有"无规矩不成方圆",但是没有方圆,规矩又给谁用?所以个人理解作用域就是"规矩"+"方圆".作用域是在创建的时候就确定的. 谁有作用域? 答:全局,函数. 为什么要有作用域? 答:前面已经说了,作用域是"规矩"+"方圆".作用域的最大用处就是隔离变量,不同作用域下同名变量不会有冲突.举个例

屌炸天实战 MySQL 系列教程(二) 史上最屌、你不知道的数据库操作

此篇写MySQL中最基础,也是最重要的操作! 第一篇:屌炸天实战 MySQL 系列教程(一) 生产标准线上环境安装配置案例及棘手问题解决 第二篇:屌炸天实战 MySQL 系列教程(二) 史上最屌.你不知道的数据库操作 本章内容: 查看\创建\使用\删除 数据库 用户管理及授权实战 局域网远程连接法 查看\创建\使用\删除\清空\修改 数据库表(是否可空,默认值,主键,自增,外键) 表内容的增删改查 where条件.通配符_%.限制limit.排序desc\asc.连表join.组合union 查

你不知道的js学习日记随笔

这两天本小白在看一本书,书名<你不知道的js>听着很叼有木有.其实这已经是本人第二次看这本书,这本书全书不足200页,但是却真的是值得一读再读的好书,再次强烈推荐下,同推的还有<js忍者秘籍>是jQuery作者写的,也很好,需要一定的基础才能看!当然也不需要太深的基础否则本小白怎么看呵呵哒.闲话少述下面放一段书上的代码,就是这段代码让我今天有不小的收获(其实这个也是作者从mdn上copy的,所以说看文档真的重要!!!重要的话打三个感叹号!!!) 首先我相信大家如果一些书的话对js中

JavaScript arguments你不知道的秘密

(function test(x){ x=10; console.log(arguments[0], x); //undefined, 10 })(); (function test(x){ x=10; console.log(arguments[0]); // 10 })(1); (function test(x){ x=10; arguments[0]=2; console.log(x, arguments[0]); //10 ,2 })(); (function test(x){ x=10

string.Format之你不知道的事

1.格式化货币(跟系统的环境有关,中文系统默认格式化人民币,英文系统格式化美元) string.Format("{0:C}",0.2) 结果为:¥0.20 (英文操作系统结果:$0.20) 默认格式化小数点后面保留两位小数,如果需要保留一位或者更多,可以指定位数 string.Format("{0:C1}",23.15) 结果为:¥23.2 (截取会自动四舍五入) 格式化多个Object实例 string.Format("市场价:{0:C},优惠价{1:C