主要内容:回答问题
这一小册回到了两个问题:
this关键字的指向如何确定?- 对象原型系统实现的工作方式:行为委托 ,是什么?
下面的所有内容在回答剖析这些问题。
this关键字的指向如何确定?
为什么使用this?为什么要有this指向执行环境的机制?
在使用this时,this指向的是执行环境这个对象,在函数内部获取对象数据,也可以通过函数传参实现。两个demo实现的是一样功能:
首先使用this的机制更优雅更清晰,其次在之后探索了this指向机制之后,会感受到使用this的机制更智能(否则得手动确认context是什么)
this指向如何确定?
this指向的确定分规则、规则优先级、特例三方面揭示。
规则
独立函数调用(直白的、毫无修饰的函数引用调用),默认绑定,this指向全局对象
- 特例:如果函数内容在严格模式下,
this为undefined
调用点有一个环境对象/拥有者/容器,隐含绑定,this指向拥有者/容器
- 补充:这个环境对象/拥有者/容器不真正"拥有"/"包含"这个函数,只是函数引用;遇到形如
obj1.obj2.foo(),只有最后一层确定this指向 - 特例:隐含丢失,将形如
obj1.foo或赋值或作为参数传递(比如回调函数)导致隐含丢失,回到默认绑定规则
apply/call/bind,或者是某些API函数提供一个指向"环境"的可选参数,明确绑定,this指向明确对象。写了有意思的demo:
- 使用apply/call模拟bind
- 自定义实现apply/call/bind
call和apply自定义实现过程,第一个注意点是,context这个值不一定是对象,所以才有了在最开始对context的转换;第二个注意点是,利用隐含绑定去实现明确绑定,需要在函数调用后delete添加的属性(挂载了函数的)bind自定义实现过程,借用了calldiy/applydiy,但有个注意点是柯里化,即参数可以在bind阶段传部分,也可以在函数执行阶段传递,有个参数的拼接
new+函数的构造器调用,new 绑定。构造器调用自动发生四个步骤:
- 创建一个全新的对象
- 新创建的对象接入原型链
- 这个对象作为函数调用的
this指向 - 除非函数返回一个其他对象,否则这个对象作为构造器调用的返回结果
规则优先级
new绑定>明确绑定>隐含绑定>默认绑定
特例
- 传递
null/undefined作为call、apply或bind的this绑定参数,默认绑定works- 因为有时候不在意
this指向是什么,所以放了null/undefined,但是这样可能会导致全局对象的污染,所以建议使用Object.create(null)一个完全为空(没有指向Object.prototype的委托)的对象,这样更安全
- 因为有时候不在意
- 隐含丢失,默认绑定works
- 一个特别的demo:因为
(p.foo = o.foo)结果值是一个函数引用
- 一个特别的demo:因为
- 箭头函数中的
this:从封闭它的(函数或全局)作用域采用this绑定(回到词法作用域)
对象原型系统实现的工作方式:行为委托 ,是什么?
简述一下对象(js类型、对象子类型、属性等等)
(在确定this指向之后,自然而然目标集中到了对象,了解对象是了解行为委托的基础)
这一块以前写了一篇文章总结:YDKJS-对象那些事儿
以下几个要多加关注:
-
复制对象
-
for..of迭代值需要迭代器对象(数组、对象对应的情况) -
对象属性遍历的方法和对应出来的顺序:只有
for..in去查看原型链了
简述下[[Prototype]]机制
[[Prototype]]是对象的一个内部属性,它指向一个其他对象。当一个属性/方法引用在一个对象上发生,而这样的属性/方法又不存在时,[[Prototype]]链就会被使用,沿着原型链去寻找。链的最顶端是Object.prototype。
主要内容之外:委托与类/继承的比较
在JavaScript的软件体系结构中,类/继承、委托是可以选择的两种设计模式。结合实例介绍一下类理论和委托理论:
-
类理论:有一个泛化的父类,定义共享的行为,子类继承父类,子类添加特化的行为。类实例化,与实例交互。
-
委托理论:有一个工具对象(委托),定义工具方法,将特定任务对象(委托者)链接到
Task对象 -
思维模型的比较:学术派的代码用OO和OLOO两种方法实现:OO风格、OLOO风格,对应OO思维模型图、OLOO思维模型图
-
更具体的代码场景:建造UI部件
行为委托更加强大也更加简洁,总结OLOO风格的代码有以下三个注意点:
- 数据成员/状态,保持再委托者上,而不是委托
- 避免在
[[Prototype]]链不同层级给出相同命名,反而推荐针对对象具体行为给出更具描述性的方法名 - 委托更适合作为内部实现细节:委托作为内部实现细节