原型和原型链
JavaScript 通过原型链实现继承。
构造函数
1 2 3 4 5
| function Person(name) { this.name = name }
const person = new Person('Alice')
|
原型对象
1 2 3 4 5
| Person.prototype.sayHello = function() { console.log(`Hello, ${this.name}`) }
person.sayHello()
|
proto
实例的 __proto__ 指向构造函数的 prototype。
1
| person.__proto__ === Person.prototype
|
原型链
1 2 3
| person.__proto__ === Person.prototype Person.prototype.__proto__ === Object.prototype Object.prototype.__proto__ === null
|
继承
原型继承
1 2 3 4 5 6 7
| function Student(name, grade) { Person.call(this, name) this.grade = grade }
Student.prototype = Object.create(Person.prototype) Student.prototype.constructor = Student
|
ES6 class
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class Person { constructor(name) { this.name = name } sayHello() { console.log(`Hello, ${this.name}`) } }
class Student extends Person { constructor(name, grade) { super(name) this.grade = grade } }
|
总结
理解原型链对掌握 JavaScript 很重要。ES6 class 简化了继承,但底层仍是原型。
示例:手动实现继承函数
1 2 3 4
| function extend(sub, sup) { sub.prototype = Object.create(sup.prototype); sub.prototype.constructor = sub; }
|
原型链深度与性能
浏览器查找属性沿着原型链向上,如果链条过长会增加查找时间。尽量避免在关键路径上频繁访问深层属性。
ES6 class 实际编译
Babel 将 class 转换为如下形式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var Person = function Person(name) { _classCallCheck(this, Person); this.name = name; };
Person.prototype.sayHello = function sayHello() { console.log("Hello, " + this.name); };
|
这些代码仍然使用原型机制。
原型链的用途
面试题
如何判断一个对象是某个构�> 如何判断一个对象是某个构�> 如何判断一个对象�链:
1 2 3 4 5
| function isInstanceOfunction nstrufunction isInstanceOfunctectfunction isInstanceOfunction nstrufunction isI (function isInstanceOfunction ns) return true; proto = Object.getPrototypeOf(proto); } return false; }
|
注意事项
- 修改原型会影响所有实例
- 不要在运行时频繁修改
prototype,�- 不要在运行时频�## - 不要在运行时频繁修改 proto��底层设计,- 不要在运行时频繁修改 prototype`,�也有助于理解框架如 Vue、React 的对象模型。
附加内容补充1
附加内容补充2
附加内容补充3
附加内容补充4
附加内容补充5
附加内容补充6