javascript面向对象基于原型链而非类,实例通过[[prototype]]链接到构造函数的prototype,逐级向上查找属性直至object.prototype终止;es6 class仅为语法糖,底层仍依赖prototype、__proto__和constructor三者协作实现继承。

JavaScript面向对象不是靠“类”,而是靠“原型链”运转
很多人写过class Person {},就以为JS和Java一样有真正的类。其实ES6的class只是语法糖,背后仍是函数+prototype+[[Prototype]]这一套机制。对象之间不靠“类模板”关联,而靠一条隐式链接——原型链。访问一个属性时,引擎不会停在对象自身,而是顺着这条链一路向上找,直到null为止。
三个关键角色必须分清:prototype、__proto__、constructor
它们不是随意命名的别名,各自承担不可替代的职责:
-
prototype:只属于函数对象(非箭头函数),是它被用作构造函数时,所有实例共享的“方法仓库”。比如
Person.prototype.sayHi会被new Person()创建的所有实例共用。 -
__proto__:每个普通对象(包括函数)都有的内部链接,指向它的“原型对象”。例如
person1.__proto__ === Person.prototype为真,正是这个链接让实例能调用原型上的方法。 -
constructor:每个
prototype对象上默认带的属性,指向它的构造函数(如Person.prototype.constructor === Person)。它不是用来“新建对象”的,而是用于追溯类型来源,在重写prototype时容易丢失,需手动修复。
原型链查找不是“就近匹配”,而是“严格逐级向上”
引擎查属性时,遵循确定路径,不跳过、不猜测、不缓存中间结果(除非V8做了优化,但语义不变):
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 先查对象自身(own property),命中即返回;
- 未命中 → 查
__proto__指向的对象; - 再未命中 → 继续查那个对象的
__proto__,依此类推; - 最终抵达
Object.prototype,它的__proto__是null,查找终止,返回undefined。
例如:const arr = [1, 2]; arr.toString()会依次查找:arr自身 → Array.prototype(有toString)→ 执行。而arr.hasOwnProperty则要走到Object.prototype才找到。
继承实现的本质:让子构造函数的prototype连上父类型的实例或原型
真正决定“能不能继承”的,是Child.prototype的__proto__指向谁。常见方式有三种,核心逻辑一致:
-
组合继承(推荐):用
Parent.call(this)继承实例属性,再用Child.prototype = Object.create(Parent.prototype)继承原型方法,最后修正constructor; -
寄生组合式:在组合继承基础上,避免父构造函数被调用两次(一次在
Object.create,一次在call),改用空函数桥接; -
ES6 class extends:底层仍是上述逻辑,
super()等价于Parent.call(this),class Child extends Parent自动设置Child.prototype.__proto__ === Parent.prototype。
无论哪种,目标都是让子类实例既能访问自己的属性,又能沿原型链拿到父类定义的方法——这才是“继承”在JS里的真实含义。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










