你不知道的this和class

不动如山岳难如知阴阳 不动如山岳难如知阴阳     2022-08-15     657

关键词:

 

  • 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/

《你不知道的javascript》——this和对象原型

 《你不知道的javascript》【3】——this和对象原型https://www.bilibili.com/video/BV1iE411P7UP 浅显的总结《你不知道的js》this指向          右查找的副作用:查找到顶层都找不到,就会抛出 查看详情

你不知道的javascript(this)

 对this的常见误解  this指向函数本身;  this指向函数的词法作用域;this是在运行时进行绑定的,并不是在编写时,它的上下文取决于函数调用时的条件。this的绑定和函数声明的位置没有任何关系,只取决于函数的调用... 查看详情

《你不知道的javascript》整理——this

最近在读一本进阶的JavaScript的书《你不知道的JavaScript(上卷)》,这次研究了一下“this”。当一个函数被调用时,会创建一个活动记录(执行上下文)。这个记录会包含函数在哪里被调用(调用栈)、函数的调用方法、... 查看详情

你不知道的javascript(上卷)小结

上卷主要讲了作用域、闭包、this以及原型方面的内容。整体在github上瞥了一眼了原版的ydkjs,到目前修改篇幅有点大了,this和原型部分的目录已经不见了,应该是改动不少。说说本书的小缺点,一是,有些东西已经和实际不一... 查看详情

javascript中的this—你不知道的javascript上卷读书笔记

this是什么?this是在运行时进行绑定的,并不是在编写时绑定,它的上下文取决于函数调用时的各种条件。this的绑定和函数声明的位置没有任何关系,只取决于函数的调用方式。当一个函数被调用时,会创建一个活动记录(有时... 查看详情

你不知道的javascript笔记

this和对象原型this是一个很特别的关键字,被自动定义在所有函数的作用域中//foo.count是0,字面理解是错误的    functionfoo(num){        console.log("foo:"+num);    &n 查看详情

你不知道的js来聊聊this(代码片段)

为什么要使用this?什么是this?来看一段代码functionidentify()returnthis.name.toUpperCase();functionspeak()vargreeting="Hello,I‘m"+identify.call(this);console.log(greeting);varme=name:"Kyle";varyou=name:"Reader" 查看详情

《你不知道的js(中卷)》关于this(代码片段)

一、关于this:一)、为什么要用this?functionidentity() returnthis.name.toUpperCase();varme= name:"Kyle";varyou= name:"Reader";identity.call(me);//Kyleidentity.call(you);//Reader? 观察上面的代码,使 查看详情

你不知道的js系列(23)-this绑定优先级(代码片段)

我们首先来看下隐式绑定和显示绑定哪个优先级更高functionfoo()  console.log(this.a)varobj1=  a:2,  foo:foovarobj2=  a:3,  foo:fooobj1.foo();//2obj2.foo();//3obj1.foo.call(obj2);//3obj2.foo.call(obj1);//2这个例子可以看到,显示绑定优先级比 查看详情

你不知道的js-行为委托

1、面向委托的设计2、委托理论Task={setID:function(ID){this.id=ID;},outputID:function(){console.log(this.id)};};//让XYZ委托TaskXYZ=object.create(Task);XYZ.prepareTask=function(ID,Label){this.setID(ID);this.label=Label; 查看详情

《你不知道的js》——this全面解析(代码片段)

默认绑定//全局对象用于默认绑定functionfoo()console.log(this.a)vara=2;foo();//2//严格模式下,不能将全局对象用于默认绑定functionfoo()‘usestrict‘;console.log(this.a)vara=2;foo();//TypeError:thisisundefined//在严格模式下调用foo()则不影响默认绑定func 查看详情

你不知道的js系列(19)-this调用位置(代码片段)

我们排除了一些对于this对错误理解并且明白了每个函数的this是在调用时被绑定的,完全取决于函数的调用位置。寻找调用位置就是寻找“函数被调用的位置”,但是做起来并没有这么简单,因为某些编程模式可能会隐藏... 查看详情

js局部变量和全局变量·你不知道的事

...明就可以使用变量;第二,js有隐含的全局概念,意味着你不声明的任何变量都会成为一个全局对象属性。650)this.width=650;"src="https://s 查看详情

你不知道的js系列上(45)-隐式混入(代码片段)

varSomething=  cool:function()    this.greeting=‘HelloWorld‘;    this.count=this.count?this.count+1:1;  Something.cool();Something.greeting;//‘HelloWorld‘Something.count;//1varAnother=  cool:func 查看详情

js你不知道的javascript笔记-this-四种绑定规则-绑定优先级-绑定例外-箭头函数(代码片段)

文章目录1.为什么要用`this`2.关于`this`的误解2.1`this`不是指向函数自身2.2`this`不指向函数的词法作用域3.什么是调用栈与调用位置4.`this`的绑定规则4.1默认绑定`fun()`4.2隐式绑定`obj.fun()`隐... 查看详情

webstorm你不知道的秘密

相信你们用webstorm肯定都会用上下面介绍的Emmet插件这个可以自带的哦Emmet语法子代:>兄弟:+父代:^重复:*成组:()ID:#class:.属性:[]编号:$?//给重复的**编号从1开始.div$$$*5???//001开始?@-:降序@N:改变编号的基数[email protected]*3从3开始... 查看详情

java反射原理

...件来进行操作的。.class文件中包含java类的所有信息,当你不知道某个类具体信息时,可以使用反射获取class,然后进行各种操作。在运行状态中,对于任意一个类,通过反射都能够知道这个类的所有属性和方法;对于任意一个对 查看详情

你不知道的js(代码片段)

1、作用域 块级作用域let只在函数内部自己的作用域内有效 全局作用域var 函数作用域 找不到作用域抛出ReferenceError变量有了则抛出TypeError 先声明后赋值 函数提升变量提升函数优先,函数声明提升在普通变量之前 函数表达... 查看详情