技术问询:能否在constructor function内部声明prototype members?
在构造函数内部声明原型成员的可行性分析
问题背景
我看课程时发现讲师把原型成员写在构造函数外部,但这种写法有不少问题,想知道能不能把原型成员声明在构造函数内部——我试了下,功能好像正常。另外我查过很多网站,它们都是把原型成员写在外部的,我清楚这么折腾没实际优化意义,就是练手试试。
两种写法示例
外部声明原型成员的写法
function Stopwatch(){ let running, stop, start; } Stopwatch.prototype.start = function(){ if(running) throw new Error("This watch is already started! "); start = console.time("time")/1000; running = true; } Stopwatch.prototype.stop = function(){ if(!running) throw new Error("The watch hasn't started yet!"); stop = console.timeEnd("time")/1000; running = false; } const timer = new Stopwatch();
内部声明原型成员的写法
function Stopwatch(){ let running, stop, start; Stopwatch.prototype.start = function(){ if(running) throw new Error("This watch is already started! "); start = console.time("time")/1000; running = true; } Stopwatch.prototype.stop = function(){ if(!running) throw new Error("The watch hasn't started yet!"); stop = console.timeEnd("time")/1000; running = false; } } const timer = new Stopwatch();
解答
可以这么写,但存在两个关键问题:
- 重复赋值浪费性能:每实例化一次
Stopwatch,就会重新给Stopwatch.prototype.start和stop赋值一次。原型方法的设计初衷是让所有实例共享同一份方法,这么写完全违背了这个设计,每次实例化都做重复操作,纯纯浪费资源。 - 变量作用域逻辑错误:原型方法里的
running、start、stop是构造函数内部的局部变量,原型方法挂载在构造函数的prototype上,根本访问不到这些变量。你测试时觉得正常,只是因为只实例化了一次,闭包意外保留了变量,但如果实例化多个对象,所有实例会共享同一个running状态——比如第一个实例start后,第二个实例也会显示已启动,状态完全混乱。
网上都把原型成员写在外部,就是因为能避免这两个问题:只赋值一次,所有实例共享,而且原型方法可以通过this访问实例属性(如果把running等改成this.running的话)。
如果想保留私有变量的特性,正确的做法是把方法挂载在实例上(利用闭包),或者用ES6类的私有字段,而不是折腾原型方法的位置。
内容的提问来源于stack exchange,提问作者Lome G ner
相关产品推荐
相关产品推荐

