优秀的编程知识分享平台

网站首页 > 技术文章 正文

js中的“类”(js中的类型转换)

nanyue 2024-10-16 11:04:04 技术文章 4 ℃

技术

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 是一个非常不可靠并且不安全的引用。通常来说要尽量避免使用这些引用。

最近发表
标签列表