Javascript Custom Objects with prototype
That’s better: we are creating the method functions only once, and assigning references to them inside the constructor. Can we do any better than that? The answer is yes:
<span class="token keyword">function</span> <span class="token function">Person</span><span class="token punctuation">(</span>first<span class="token punctuation">,</span> last<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span><span class="token punctuation">.</span>first <span class="token operator">=</span> first<span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>last <span class="token operator">=</span> last<span class="token punctuation">;</span> <span class="token punctuation">}</span> Person<span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function-variable function">fullName</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>first <span class="token operator">+</span> <span class="token string">' '</span> <span class="token operator">+</span> <span class="token keyword">this</span><span class="token punctuation">.</span>last<span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> Person<span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function-variable function">fullNameReversed</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>last <span class="token operator">+</span> <span class="token string">', '</span> <span class="token operator">+</span> <span class="token keyword">this</span><span class="token punctuation">.</span>first<span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span>
<span style="color: #333333;">Person.prototype</span>
is an object shared by all instances of<span style="color: #333333;">Person</span>
. It forms part of a lookup chain (that has a special name, “prototype chain”): any time you attempt to access a property of<span style="color: #333333;">Person</span>
that isn’t set, JavaScript will check<span style="color: #333333;">Person.prototype</span>
to see if that property exists there instead. As a result, anything assigned to<span style="color: #333333;">Person.prototype</span>
becomes available to all instances of that constructor via the<span style="color: #333333;">this</span>
object.This is an incredibly powerful tool. JavaScript lets you modify something’s prototype at any time in your program, which means you can add extra methods to existing objects at runtime:
<span class="token keyword">var</span> s <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Person</span><span class="token punctuation">(</span><span class="token string">'Simon'</span><span class="token punctuation">,</span> <span class="token string">'Willison'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> s<span class="token punctuation">.</span><span class="token function">firstNameCaps</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// TypeError on line 1: s.firstNameCaps is not a function</span> Person<span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function-variable function">firstNameCaps</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>first<span class="token punctuation">.</span><span class="token function">toUpperCase</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> s<span class="token punctuation">.</span><span class="token function">firstNameCaps</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// "SIMON"</span>
Interestingly, you can also add things to the prototype of built-in JavaScript objects. Let’s add a method to
<span style="color: #333333;">String</span>
that returns that string in reverse:<span class="token keyword">var</span> s <span class="token operator">=</span> <span class="token string">'Simon'</span><span class="token punctuation">;</span> s<span class="token punctuation">.</span><span class="token function">reversed</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// TypeError on line 1: s.reversed is not a function</span> String<span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function-variable function">reversed</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">var</span> r <span class="token operator">=</span> <span class="token string">''</span><span class="token punctuation">;</span> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">var</span> i <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>length <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">;</span> i <span class="token operator">>=</span> <span class="token number">0</span><span class="token punctuation">;</span> i<span class="token operator">--</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> r <span class="token operator">+=</span> <span class="token keyword">this</span><span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> r<span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> s<span class="token punctuation">.</span><span class="token function">reversed</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// nomiS</span>
Our new method even works on string literals!
<span class="token string">'This can now be reversed'</span><span class="token punctuation">.</span><span class="token function">reversed</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// desrever eb won nac sihT</span>