JavaScript构造函数与prototype定义方法的正确性及实例访问疑问
构造函数内部定义方法 vs 挂载到prototype的区别与解惑
嘿,这问题问得特别好,很多刚接触JS构造函数的开发者都会有这个困惑,我来给你掰扯清楚~
两种写法都合法,只是适用场景不同
首先明确:构造函数内部定义方法和挂载到.prototype上都是正确的写法,但它们的工作机制和适用场景有很大区别:
1. 构造函数内部定义方法
就像你示例里的写法:
function Person(first, last, age, gender, interests) { this.name = { first, last }; this.bio = function() { alert(this.name.first + ' ' + this.name.last + ' is ' + this.age + ' years old.'+ ' He likes ' + this.interests[0] + ' and ' + this.interests[1] + '.'); }; }
- 每次用
new Person()创建实例时,这些方法都会重新生成一份副本——每个实例都拥有属于自己的独立方法。 - 优势:方法内部可以直接访问构造函数里的局部变量(如果有的话),而且单个实例的方法可以被独立修改,不会影响其他实例。
- 劣势:如果创建大量实例,会浪费内存,因为每个实例都重复持有逻辑完全相同的方法。
2. 挂载到.prototype上定义方法
这也是MDN更推荐的写法:
function Person(first, last, age, gender, interests) { this.name = { first, last }; this.age = age; this.gender = gender; this.interests = interests; } Person.prototype.bio = function() { alert(this.name.first + ' ' + this.name.last + ' is ' + this.age + ' years old.'+ ' He likes ' + this.interests[0] + ' and ' + this.interests[1] + '.'); }; Person.prototype.greeting = function() { alert('Hi! I\'m ' + this.name.first + '.'); };
- 所有通过
new Person()创建的实例,都会共享prototype上的方法——方法只在内存中存在一份,所有实例都指向同一个方法引用。 - 优势:极大节省内存,而且修改prototype上的方法后,所有已存在的实例都会立刻获取到更新后的方法。
- 劣势:方法无法直接访问构造函数内部的局部变量(只能通过
this访问实例的属性),如果某个实例重写了该方法,会覆盖prototype上的版本,但不会影响其他实例。
为什么你的示例没用到prototype,实例却能访问方法?
你对MDN教程的描述可能产生了小误解——其实构造函数内部通过this.xxx = function(){}定义的方法,是直接挂载到每个实例对象上的“自有属性”,不属于prototype链的继承范畴,但实例本身确实能直接访问这些成员。
MDN所说的“只有prototype上的属性和方法对实例可用”,准确表述应该是:实例会继承prototype上的属性和方法,但实例自己的自有属性(包括构造函数里通过this定义的)优先级更高,会覆盖prototype上的同名成员。
举个例子帮你理解优先级:
function Person(first) { this.name = first; // 实例的自有方法 this.greeting = function() { alert('Hi from instance!'); }; } // prototype上的继承方法 Person.prototype.greeting = function() { alert('Hi from prototype!'); }; const p1 = new Person('Bob'); p1.greeting(); // 弹出"Hi from instance!",因为自有属性优先级更高
简单总结:
- 构造函数里用
this定义的属性/方法:每个实例独有的自有属性 - prototype上定义的属性/方法:所有实例共享的继承属性
- 实例访问成员时,先找自有属性,找不到再去prototype链上依次查找
内容的提问来源于stack exchange,提问作者JMay
相关产品推荐
相关产品推荐

