网站首页 > 技术文章 正文
技术
JavaScript 开发者绞尽脑汁想要模仿类的行为:
这段代码展示了另外两种“面向类”的技巧:
1. this.name = name 给每个对象(也就是 a 和 b,参见第 2 章中的 this 绑定)都添加 了 .name 属性,有点像类实例封装的数据值。
2. Foo.prototype.myName = ... 可能个更有趣的技巧,它会给 Foo.prototype 对象添加一 个属性(函数)。现在,a.myName() 可以正常工作,但是你可能会觉得很惊讶,这是什 么原理呢?
在这段代码中,看起来似乎创建 a 和 b 时会把 Foo.prototype 对象复制到这两个对象中, 然而事实并不是这样。
在本章开头介绍默认 [[Get]] 算法时我们介绍过 [[Prototype]] 链,以及当属性不直接存 在于对象中时如何通过它来进行查找。
因此,在创建的过程中,a 和 b 的内部 [[Prototype]] 都会关联到 Foo.prototype 上。当 a 和 b 中无法找到 myName 时,它会在 Foo.prototype 上找到。
回顾“构造函数”
之前讨论 .constructor 属性时我们说过,看起来 a.constructor === Foo 为真意味着 a 确 实有一个指向 Foo 的 .constructor 属性,但是事实不是这样。
这是一个很不幸的误解。实际上,.constructor 引用同样被委托给了 Foo.prototype,而 Foo.prototype.constructor 默认指向 Foo。
把 .constructor 属性指向 Foo 看作是 a 对象由 Foo“构造”非常容易理解,但这只不过 是一种虚假的安全感。a.constructor 只是通过默认的 [[Prototype]] 委托指向 Foo,这和“构造”毫无关系。相反,对于 .constructor 的错误理解很容易对你自己产生误导。
举例来说,Foo.prototype 的 .constructor 属性只是 Foo 函数在声明时的默认属性。如果 你创建了一个新对象并替换了函数默认的 .prototype 对象引用,那么新对象并不会自动获 得 .constructor 属性。
思考下面的代码:
Object(..) 并没有“构造”a1,对吧?看起来应该是 Foo()“构造”了它。大部分开发者 都认为是 Foo() 执行了构造工作,但是问题在于,如果你认为“constructor”表示“由…… 构造”的话,a1.constructor 应该是 Foo,但是它并不是 Foo !
到底怎么回事? a1 并没有 .constructor 属性,所以它会委托 [[Prototype]] 链上的 Foo. prototype。但是这个对象也没有 .constructor 属性(不过默认的 Foo.prototype 对象有这 个属性!),所以它会继续委托,这次会委托给委托链顶端的 Object.prototype。这个对象 有 .constructor 属性,指向内置的 Object(..) 函数
错误观点已被摧毁。
当然,你可以给 Foo.prototype 添加一个 .constructor 属性,不过这需要手动添加一个符 合正常行为的不可枚举属性。
举例来说:
修复 .constructor 需要很多手动操作。所有这些工作都是源于把“constructor”错误地理 解为“由……构造”,这个误解的代价实在太高了。
实际上,对象的 .constructor 会默认指向一个函数,这个函数可以通过对象的 .prototype 引用。“constructor”和“prototype”这两个词本身的含义可能适用也可能不适用。最好的 办法是记住这一点“constructor 并不表示被构造”。
.constructor 并不是一个不可变属性。它是不可枚举(参见上面的代码)的,但是它的值 是可写的(可以被修改)。此外,你可以给任意 [[Prototype]] 链中的任意对象添加一个名 为 constructor 的属性或者对其进行修改,你可以任意对其赋值。
和 [[Get]] 算法查找 [[Prototype]] 链的机制一样,.constructor 属性引用的目标可能和 你想的完全不同。
现在你应该明白这个属性多么随意了吧?
结论?一些随意的对象属性引用,比如 a1.constructor,实际上是不被信任的,它们不一 定会指向默认的函数引用。此外,很快我们就会看到,稍不留神 a1.constructor 就可能会 指向你意想不到的地方。
a1.constructor 是一个非常不可靠并且不安全的引用。通常来说要尽量避免使用这些引用。
猜你喜欢
- 2024-10-16 JS中(a==1 && a==2 && a==3)可以在JavaScript中计算为“true”吗?
- 2024-10-16 JavaScript 的这个难点,毁掉了多少程序员
- 2024-10-16 前端开发之彻底搞懂this指向(前端this指向问题)
- 2024-10-16 JavaScript中的变量声明和作用域(一)
- 2024-10-16 Top 26 JavaScript面试问题和答案
- 2024-10-16 JS 经典实例知识点整理汇总【实践】
- 2024-10-16 苦恼于JavaScript中的reduce函数?五分钟讲透彻
- 2024-10-16 前端基础:JavaScript(前端基础题)
- 2024-10-16 一句话彻底理解JS中的回调(Callback)函数
- 2024-10-16 面试中被问到最多的 19 个 JavaScript 问题
- 最近发表
- 标签列表
-
- cmd/c (57)
- c++中::是什么意思 (57)
- sqlset (59)
- ps可以打开pdf格式吗 (58)
- phprequire_once (61)
- localstorage.removeitem (74)
- routermode (59)
- vector线程安全吗 (70)
- & (66)
- java (73)
- org.redisson (64)
- log.warn (60)
- cannotinstantiatethetype (62)
- js数组插入 (83)
- resttemplateokhttp (59)
- gormwherein (64)
- linux删除一个文件夹 (65)
- mac安装java (72)
- reader.onload (61)
- outofmemoryerror是什么意思 (64)
- flask文件上传 (63)
- eacces (67)
- 查看mysql是否启动 (70)
- java是值传递还是引用传递 (58)
- 无效的列索引 (74)