JS 继承之 Prototype Chain 的意义
1. Objects are values in Javascript#
{}
就是个空对象,{}
在 Python 里是个 dictionary, 当然 dictionary 也是个对象,
在说继承之前还要提一下 JS 对象与其它语言不同的地方, 举个例子,
在其它面向对象语言里, 如果我们尝试赋值或者访问对象不存在的 field就会报错, 在 JS 里并不会, 当你尝试读取不存在的 feild 的时候 (包括 prototype chain, 下面会讨论) 才会报错,
原因是, JS 的对象与其它语言如 Java, Python不同, Java里对象的 fields 是有类决定的, 类似所有对象的蓝图, JS并不是, JS里的对象不是由类创建的, 更像一个 map,
我们知道 JS 的值分为两类, Primitive values: immutable, object values: mutable, 这里的 mutable 其实就是指 你可以随意给对象增加属性, 一个对象就是一个value,
当尝试读取对象的属性时, 会触发 prototype chain, 看下面代码:
2. Prototype#
2.1. Ways to access prototype#
Every object value in JavaScript has a built-in property, which is called its prototype
. The prototype
is itself an object value, so the prototype
will have its own prototype
, making what’s called a prototype chain. The chain ends when we reach a prototype that has null
for its own prototype.
关于prototype有一个迷惑的地方, 通过obj.prototype
访问到的并不是上面我们讨论的prototype, 只能通过obj.__proto__
和全局函数Object.getPrototypeOf()
来获取一个对象的prototype
属性:
根据打印可以看出 person.prototype
跟person.__proto__
压根就不是一个东西,
2.2. Prototype 的获取与赋值#
obj.__proto__
不是访问对象 prototype 属性的标准方法, 因为有的browser可能没实现, 所以访问(只读)一般用Object.getPrototypeOf(student)
, 通过创建该对象的时候为其 __proto__
属性赋值的方法给一个对象的 prototype 赋值, 如下:
3. Prototype Chain 的意义#
Javascript is an object-based language, not a class-based language.
If you know Java or C++, you should be familiar with the inheritance concept. In this programming paradigm, a class is a blueprint for creating objects. If you want a new class to reuse the functionality of an existing class, you can create a new class that extends the existing class. This is called classical inheritance.
JavaScript doesn’t use classical inheritance. Instead, it uses prototypal inheritance. In prototypal inheritance, an object “inherits” properties from another object via the prototype
linkage.
Prototype chain 的意义正是代替了传统语言中的继承机制, 只不过是对象之间的继承, 而不是类之间,
4. Javascript 不存在真正的类#
JS 不存在真正的类, 即使是ES6之后的类也不过是个语法糖 (syntactic sugar) 而已,
Unlike other programming languages such as Java and C#, JavaScript classes are syntactic sugar over the prototypal inheritance. In other words, ES6 classes are just special functions. But class declarations are not hoisted like function declarations.
上面提到 obj.prototype
和 obj.__proto__
不是一个东西, 当创建对象后 (除函数对象) 它们的 obj.prototype
是 undefined
, 而创建函数对象后, 这个函数的func.prototype
会被自动创建, 并且值为一个空对象{}
:
思考下面代码发生了什么:
第一步发生在定义函数Person时:
-
Person.prototype
被创建, 并被赋值为一个空对象{}
-
Person.prototype
对象增加一个函数getName()
此时 Person.prototype
不再是个空对象, 而是有一个名为getName
函数的对象{ getName: [Function (anonymous)] }
之后三步发生在调用new Person("John Doe")
时:
- 新创建空对象
{}
并赋值给john - 执行
john.__proto__ = Person.prototype
- 执行函数Person, 函数体里的
this.name = name
变为john.name = name
综上: The
john
object is an instance of thePerson
through prototypal inheritance.
参考: