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>