ES6提供了更接近传统语言的写法,引入了Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。基本上,ES6的class可以看作 只是一个语法糖,它的绝大部分功能,ES5都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
<span class="pl-k">function</span> <span class="pl-v">Point</span><span class="pl-kos">(</span><span class="pl-s1">x</span><span class="pl-kos">,</span> <span class="pl-s1">y</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">x</span> <span class="pl-c1">=</span> <span class="pl-s1">x</span><span class="pl-kos">;</span> <span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">y</span> <span class="pl-c1">=</span> <span class="pl-s1">y</span><span class="pl-kos">;</span> <span class="pl-kos">}</span> <span class="pl-v">Point</span><span class="pl-kos">.</span><span class="pl-c1">prototype</span><span class="pl-kos">.</span><span class="pl-en">toString</span> <span class="pl-c1">=</span> <span class="pl-k">function</span> <span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-k">return</span> <span class="pl-s">'('</span> <span class="pl-c1">+</span> <span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">x</span> <span class="pl-c1">+</span> <span class="pl-s">', '</span> <span class="pl-c1">+</span> <span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">y</span> <span class="pl-c1">+</span> <span class="pl-s">')'</span><span class="pl-kos">;</span> <span class="pl-kos">}</span> <span class="pl-c">//定义类 </span> <span class="pl-k">class</span> <span class="pl-v">Point</span> <span class="pl-kos">{</span> <span class="pl-en">constructor</span><span class="pl-kos">(</span><span class="pl-s1">x</span><span class="pl-kos">,</span> <span class="pl-s1">y</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">x</span> <span class="pl-c1">=</span> <span class="pl-s1">x</span><span class="pl-kos">;</span> <span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">y</span> <span class="pl-c1">=</span> <span class="pl-s1">y</span><span class="pl-kos">;</span> <span class="pl-kos">}</span> <span class="pl-en">toString</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-k">return</span> <span class="pl-s">'('</span> <span class="pl-c1">+</span> <span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">x</span> <span class="pl-c1">+</span> <span class="pl-s">', '</span> <span class="pl-c1">+</span> <span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">y</span> <span class="pl-c1">+</span> <span class="pl-s">')'</span><span class="pl-kos">;</span> <span class="pl-kos">}</span> <span class="pl-kos">}</span> <span class="pl-c">// 类实际上就是方法</span> <span class="pl-k">typeof</span> <span class="pl-v">Point</span> <span class="pl-c">// function</span> <span class="pl-c">// 构造函数的prototype属性,在ES6的“类”上面继续存在。事实上,类的所有方法都定义在类的prototype属性上面。</span> <span class="pl-k">class</span> <span class="pl-v">B</span> <span class="pl-kos">{</span><span class="pl-kos">}</span> <span class="pl-k">let</span> <span class="pl-s1">b</span> <span class="pl-c1">=</span> <span class="pl-k">new</span> <span class="pl-v">B</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-s1">b</span><span class="pl-kos">.</span><span class="pl-c1">constructor</span> <span class="pl-c1">===</span> <span class="pl-v">B</span><span class="pl-kos">.</span><span class="pl-c1">prototype</span><span class="pl-kos">.</span><span class="pl-c1">constructor</span> <span class="pl-c">// true</span> <span class="pl-c">// prototype对象的constructor属性,直接指向“类”的本身,这与ES5的行为是一致的。</span> <span class="pl-s1">b</span><span class="pl-kos">.</span><span class="pl-c1">prototype</span><span class="pl-kos">.</span><span class="pl-c1">constructor</span> <span class="pl-c1">===</span> <span class="pl-v">B</span> <span class="pl-c">// true</span> |
另外,类的内部所有定义的方法,都是不可枚举的(non-enumerable)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
<span class="pl-k">class</span> <span class="pl-v">Point</span> <span class="pl-kos">{</span> <span class="pl-en">constructor</span><span class="pl-kos">(</span><span class="pl-s1">x</span><span class="pl-kos">,</span> <span class="pl-s1">y</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">x</span> <span class="pl-c1">=</span> <span class="pl-s1">x</span><span class="pl-kos">;</span> <span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">y</span> <span class="pl-c1">=</span> <span class="pl-s1">y</span><span class="pl-kos">;</span> <span class="pl-kos">}</span> <span class="pl-en">toString</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-c">// ... </span> <span class="pl-kos">}</span> <span class="pl-kos">}</span> <span class="pl-v">Object</span><span class="pl-kos">.</span><span class="pl-en">keys</span><span class="pl-kos">(</span><span class="pl-v">Point</span><span class="pl-kos">.</span><span class="pl-c1">prototype</span><span class="pl-kos">)</span> <span class="pl-c">// [] </span> <span class="pl-v">Object</span><span class="pl-kos">.</span><span class="pl-en">getOwnPropertyNames</span><span class="pl-kos">(</span><span class="pl-v">Point</span><span class="pl-kos">.</span><span class="pl-c1">prototype</span><span class="pl-kos">)</span> <span class="pl-c">// ["constructor","toString"]</span> <span class="pl-c">// 与ES5一样,实例的属性除非显式定义在其本身(即定义在this对象上),否则都是定义在原型上(即定义在class上)。</span> <span class="pl-k">var</span> <span class="pl-s1">point</span> <span class="pl-c1">=</span> <span class="pl-k">new</span> <span class="pl-v">Point</span><span class="pl-kos">(</span><span class="pl-c1">2</span><span class="pl-kos">,</span> <span class="pl-c1">3</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-s1">point</span><span class="pl-kos">.</span><span class="pl-en">toString</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-c">// (2, 3)</span> <span class="pl-s1">point</span><span class="pl-kos">.</span><span class="pl-en">hasOwnProperty</span><span class="pl-kos">(</span><span class="pl-s">'x'</span><span class="pl-kos">)</span> <span class="pl-c">// true </span> <span class="pl-s1">point</span><span class="pl-kos">.</span><span class="pl-en">hasOwnProperty</span><span class="pl-kos">(</span><span class="pl-s">'y'</span><span class="pl-kos">)</span> <span class="pl-c">// true </span> <span class="pl-s1">point</span><span class="pl-kos">.</span><span class="pl-en">hasOwnProperty</span><span class="pl-kos">(</span><span class="pl-s">'toString'</span><span class="pl-kos">)</span> <span class="pl-c">// false </span> <span class="pl-s1">point</span><span class="pl-kos">.</span><span class="pl-c1">__proto__</span><span class="pl-kos">.</span><span class="pl-en">hasOwnProperty</span><span class="pl-kos">(</span><span class="pl-s">'toString'</span><span class="pl-kos">)</span> <span class="pl-c">// true</span> <span class="pl-c">// toString方法是Point类内部定义的方法,它是不可枚举的。这一点与ES5的行为不一致。</span> <span class="pl-k">var</span> <span class="pl-v">Point</span> <span class="pl-c1">=</span> <span class="pl-k">function</span> <span class="pl-kos">(</span><span class="pl-s1">x</span><span class="pl-kos">,</span> <span class="pl-s1">y</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-kos">}</span><span class="pl-kos">;</span> <span class="pl-v">Point</span><span class="pl-kos">.</span><span class="pl-c1">prototype</span><span class="pl-kos">.</span><span class="pl-en">toString</span> <span class="pl-c1">=</span> <span class="pl-k">function</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-kos">}</span><span class="pl-kos">;</span> <span class="pl-v">Object</span><span class="pl-kos">.</span><span class="pl-en">keys</span><span class="pl-kos">(</span><span class="pl-v">Point</span><span class="pl-kos">.</span><span class="pl-c1">prototype</span><span class="pl-kos">)</span> <span class="pl-c">// ["toString"] </span> <span class="pl-v">Object</span><span class="pl-kos">.</span><span class="pl-en">getOwnPropertyNames</span><span class="pl-kos">(</span><span class="pl-v">Point</span><span class="pl-kos">.</span><span class="pl-c1">prototype</span><span class="pl-kos">)</span> <span class="pl-c">// ["constructor","toString"]</span> <span class="pl-s1">point</span><span class="pl-kos">.</span><span class="pl-en">hasOwnProperty</span><span class="pl-kos">(</span><span class="pl-s">'x'</span><span class="pl-kos">)</span> <span class="pl-c">// true </span> <span class="pl-s1">point</span><span class="pl-kos">.</span><span class="pl-en">hasOwnProperty</span><span class="pl-kos">(</span><span class="pl-s">'y'</span><span class="pl-kos">)</span> <span class="pl-c">// true </span> <span class="pl-s1">point</span><span class="pl-kos">.</span><span class="pl-en">hasOwnProperty</span><span class="pl-kos">(</span><span class="pl-s">'toString'</span><span class="pl-kos">)</span> <span class="pl-c">// false </span> |
constructor方法
constructor方法是类的默认方法,通过new命令生成对象实例时,自动调用该方法。一个类必须有constructor方法,如果没有显式定义,一个空 的constructor方法会被默认添加。 constructor方法默认返回实例对象(即this),完全可以指定返回另外一个对象。
1 2 |
<span class="pl-k">class</span> <span class="pl-v">Foo</span> <span class="pl-kos">{</span> <span class="pl-en">constructor</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-k">return</span> <span class="pl-v">Object</span><span class="pl-kos">.</span><span class="pl-en">create</span><span class="pl-kos">(</span><span class="pl-c1">null</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-kos">}</span> <span class="pl-kos">}</span> <span class="pl-k">new</span> <span class="pl-v">Foo</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-k">instanceof</span> <span class="pl-v">Foo</span> <span class="pl-c">// false</span> |
上面代码中,constructor函数返回一个全新的对象,结果导致实例对象不是Foo类的实例。
类的构造函数,不使用new是没法调用的,会报错。这是它跟普通构造函数的一个主要区别,后者不用new也可以执行。
1 2 |
<span class="pl-k">class</span> <span class="pl-v">Foo</span> <span class="pl-kos">{</span> <span class="pl-en">constructor</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-k">return</span> <span class="pl-v">Object</span><span class="pl-kos">.</span><span class="pl-en">create</span><span class="pl-kos">(</span><span class="pl-c1">null</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-kos">}</span> <span class="pl-kos">}</span> <span class="pl-v">Foo</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-c">// TypeError: Class constructor Foo cannot be invoked without 'new'</span> |
静态方法
类相当于实例的原型,所有在类中定义的方法,都会被实例继承。如果在一个方法前,加上static关键字,就表示该方法不会被实例继承,而是直接 通过类来调用,这就称为“静态方法”。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<span class="pl-k">class</span> <span class="pl-v">Foo</span> <span class="pl-kos">{</span> <span class="pl-k">static</span> <span class="pl-en">classMethod</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-k">return</span> <span class="pl-s">'hello'</span><span class="pl-kos">;</span> <span class="pl-kos">}</span> <span class="pl-kos">}</span> <span class="pl-v">Foo</span><span class="pl-kos">.</span><span class="pl-en">classMethod</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-c">// 'hello'</span> <span class="pl-k">var</span> <span class="pl-s1">foo</span> <span class="pl-c1">=</span> <span class="pl-k">new</span> <span class="pl-v">Foo</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-s1">foo</span><span class="pl-kos">.</span><span class="pl-en">classMethod</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-c">// TypeError: foo.classMethod is not a function</span> <span class="pl-c">// 父类的静态方法,可以被子类继承。</span> <span class="pl-k">class</span> <span class="pl-v">Bar</span> <span class="pl-k">extends</span> <span class="pl-v">Foo</span> <span class="pl-kos">{</span> <span class="pl-kos">}</span> <span class="pl-v">Bar</span><span class="pl-kos">.</span><span class="pl-en">classMethod</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-c">// 'hello'</span> <span class="pl-c">// 静态方法也是可以从super对象上调用的。</span> <span class="pl-k">class</span> <span class="pl-v">Bar</span> <span class="pl-k">extends</span> <span class="pl-v">Foo</span> <span class="pl-kos">{</span> <span class="pl-k">static</span> <span class="pl-en">classMethod</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-k">return</span> <span class="pl-smi">super</span><span class="pl-kos">.</span><span class="pl-en">classMethod</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-c1">+</span> <span class="pl-s">', too'</span><span class="pl-kos">;</span> <span class="pl-kos">}</span> <span class="pl-kos">}</span> <span class="pl-v">Bar</span><span class="pl-kos">.</span><span class="pl-en">classMethod</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span> |
静态方法的实现其实跟下面类似
1 2 3 4 5 6 7 8 9 10 11 |
<span class="pl-k">class</span> <span class="pl-v">Foo</span> <span class="pl-kos">{</span> <span class="pl-k">static</span> <span class="pl-en">classMethod</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-k">return</span> <span class="pl-s">'hello'</span><span class="pl-kos">;</span> <span class="pl-kos">}</span> <span class="pl-kos">}</span> <span class="pl-c">// 等同于</span> <span class="pl-k">function</span> <span class="pl-v">Foo</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">{</span><span class="pl-kos">}</span> <span class="pl-v">Foo</span><span class="pl-kos">.</span><span class="pl-en">classMethod</span> <span class="pl-c1">=</span> <span class="pl-k">function</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">{</span> <span class="pl-k">return</span> <span class="pl-s">'hello'</span><span class="pl-kos">;</span> <span class="pl-kos">}</span> |
静态属性
静态属性指的是Class本身的属性,即Class.propname,而不是定义在实例对象(this)上的属性。
1 2 3 4 5 6 7 |
<span class="pl-k">class</span> <span class="pl-v">Foo</span> <span class="pl-kos">{</span> <span class="pl-kos">}</span> <span class="pl-v">Foo</span><span class="pl-kos">.</span><span class="pl-c1">prop</span> <span class="pl-c1">=</span> <span class="pl-c1">1</span><span class="pl-kos">;</span> <span class="pl-v">Foo</span><span class="pl-kos">.</span><span class="pl-c1">prop</span> <span class="pl-c">// 1</span> <span class="pl-c">// 语法等同于</span> <span class="pl-k">function</span> <span class="pl-v">Foo</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">{</span><span class="pl-kos">}</span> <span class="pl-v">Foo</span><span class="pl-kos">.</span><span class="pl-c1">prop</span> <span class="pl-c1">=</span> <span class="pl-c1">1</span> |
目前,只有这种写法可行,因为ES6明确规定,Class内部只有静态方法,没有静态属性。
1 2 3 4 5 6 7 8 |
<span class="pl-c">// 以下两种写法都无效 </span> <span class="pl-k">class</span> <span class="pl-v">Foo</span> <span class="pl-kos">{</span> <span class="pl-c">// 写法一 </span> <span class="pl-c1">prop</span>: <span class="pl-c1">2</span> <span class="pl-c">// 写法二 </span> <span class="pl-k">static</span> <span class="pl-c1">prop</span>: <span class="pl-c1">2</span> <span class="pl-kos">}</span> <span class="pl-v">Foo</span><span class="pl-kos">.</span><span class="pl-c1">prop</span> <span class="pl-c">// undefined</span> |
继承
Class之间可以通过extends关键字实现继承,这比ES5的通过修改原型链实现继承,要清晰和方便很多。
子类必须在constructor方法中调用super方法,否则新建实例时会报错。这是因为子类没有自己的this对象,而是继承父类的this对象,然后对其进行加工。如果不调用super方法,子类就得不到this对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<span class="pl-k">class</span> <span class="pl-v">ColorPoint</span> <span class="pl-k">extends</span> <span class="pl-v">Point</span> <span class="pl-kos">{</span> <span class="pl-en">constructor</span><span class="pl-kos">(</span><span class="pl-s1">x</span><span class="pl-kos">,</span> <span class="pl-s1">y</span><span class="pl-kos">,</span> <span class="pl-s1">color</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-smi">super</span><span class="pl-kos">(</span><span class="pl-s1">x</span><span class="pl-kos">,</span> <span class="pl-s1">y</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-c">// 调用父类的constructor(x, y)</span> <span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">color</span> <span class="pl-c1">=</span> <span class="pl-s1">color</span><span class="pl-kos">;</span> <span class="pl-kos">}</span> <span class="pl-en">toString</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-k">return</span> <span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">color</span> <span class="pl-c1">+</span> <span class="pl-s">' '</span> <span class="pl-c1">+</span> <span class="pl-smi">super</span><span class="pl-kos">.</span><span class="pl-en">toString</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-c">// 调用父类的toString() </span> <span class="pl-kos">}</span> <span class="pl-kos">}</span> <span class="pl-k">class</span> <span class="pl-v">Point</span> <span class="pl-kos">{</span> <span class="pl-c">/* ... */</span> <span class="pl-kos">}</span> <span class="pl-k">class</span> <span class="pl-v">ColorPoint</span> <span class="pl-k">extends</span> <span class="pl-v">Point</span> <span class="pl-kos">{</span> <span class="pl-en">constructor</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-kos">}</span> <span class="pl-kos">}</span> <span class="pl-k">let</span> <span class="pl-s1">cp</span> <span class="pl-c1">=</span> <span class="pl-k">new</span> <span class="pl-v">ColorPoint</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-c">// ReferenceError</span> |
如果子类没有定义constructor方法,这个方法会被默认添加,代码如下。也就是说,不管有没有显式定义,任何一个子类都有constructor方法。
1 |
<span class="pl-en">constructor</span><span class="pl-kos">(</span>...<span class="pl-s1">args</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-smi">super</span><span class="pl-kos">(</span>...<span class="pl-s1">args</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-kos">}</span> |
另一个需要注意的地方是,在子类的构造函数中,只有调用super之后,才可以使用this关键字,否则会报错。这是因为子类实例的构建,是基于对父 类实例加工,只有super方法才能返回父类实例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<span class="pl-k">class</span> <span class="pl-v">Point</span> <span class="pl-kos">{</span> <span class="pl-en">constructor</span><span class="pl-kos">(</span><span class="pl-s1">x</span><span class="pl-kos">,</span> <span class="pl-s1">y</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">x</span> <span class="pl-c1">=</span> <span class="pl-s1">x</span><span class="pl-kos">;</span> <span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">y</span> <span class="pl-c1">=</span> <span class="pl-s1">y</span><span class="pl-kos">;</span> <span class="pl-kos">}</span> <span class="pl-kos">}</span> <span class="pl-k">class</span> <span class="pl-v">ColorPoint</span> <span class="pl-k">extends</span> <span class="pl-v">Point</span> <span class="pl-kos">{</span> <span class="pl-en">constructor</span><span class="pl-kos">(</span><span class="pl-s1">x</span><span class="pl-kos">,</span> <span class="pl-s1">y</span><span class="pl-kos">,</span> <span class="pl-s1">color</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">color</span> <span class="pl-c1">=</span> <span class="pl-s1">color</span><span class="pl-kos">;</span> <span class="pl-c">// ReferenceError </span> <span class="pl-smi">super</span><span class="pl-kos">(</span><span class="pl-s1">x</span><span class="pl-kos">,</span> <span class="pl-s1">y</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">color</span> <span class="pl-c1">=</span> <span class="pl-s1">color</span><span class="pl-kos">;</span> <span class="pl-c">// 正确 </span> <span class="pl-kos">}</span> <span class="pl-kos">}</span> |
Class 与 function 的区别
Class不存在变量提升(hoist),这一点与ES5完全不同。
1 2 |
<span class="pl-k">new</span> <span class="pl-v">Foo</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-c">// ReferenceError </span> <span class="pl-k">class</span> <span class="pl-v">Foo</span> <span class="pl-kos">{</span><span class="pl-kos">}</span> |
ES5的继承,实质是先创造子类的实例对象this,然后再将父类的方法添加到this上面(Parent.apply(this))。ES6的继承机制完全不同,实质是 先创造父类的实例对象this(所以必须先调用super方法),然后再用子类的构造函数修改this。
常见疑问
私有方法是常见需求,但ES6不提供,只能通过变通方法模拟实现。
类和模块的内部,默认就是严格模式,所以不需要使用use strict指定运行模式。只要你的代码写在类或模块之中,就只有严格模式可用。 考虑到未来所有的代码,其实都是运行在模块之中,所以ES6实际上把整个语言升级到了严格模式。
Object.getPrototypeOf方法可以用来从子类上获取父类。因此,可以使用这个方法判断,一个类是否继承了另一个类。
1 |
<span class="pl-v">Object</span><span class="pl-kos">.</span><span class="pl-en">getPrototypeOf</span><span class="pl-kos">(</span><span class="pl-v">ColorPoint</span><span class="pl-kos">)</span> <span class="pl-c1">===</span> <span class="pl-v">Point</span> <span class="pl-c">// true</span> |
new.target属性
new是从构造函数生成实例的命令。ES6为new命令引入了一个new.target属性,(在构造函数中)返回new命令作用于的那个构造函数。如果构造函数 不是通过new命令调用的,new.target会返回undefined,因此这个属性可以用来确定构造函数是怎么调用的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<span class="pl-k">function</span> <span class="pl-v">Person</span><span class="pl-kos">(</span><span class="pl-s1">name</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-k">if</span> <span class="pl-kos">(</span><span class="pl-k">new</span><span class="pl-kos">.</span><span class="pl-k">target</span> !== <span class="pl-c1">undefined</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">name</span> <span class="pl-c1">=</span> <span class="pl-s1">name</span><span class="pl-kos">;</span> <span class="pl-kos">}</span> <span class="pl-k">else</span> <span class="pl-kos">{</span> <span class="pl-k">throw</span> <span class="pl-k">new</span> <span class="pl-v">Error</span><span class="pl-kos">(</span><span class="pl-s">'必须使用new生成实例'</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-kos">}</span> <span class="pl-kos">}</span> <span class="pl-c">// 另一种写法 </span> <span class="pl-k">function</span> <span class="pl-v">Person</span><span class="pl-kos">(</span><span class="pl-s1">name</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-k">if</span> <span class="pl-kos">(</span><span class="pl-k">new</span><span class="pl-kos">.</span><span class="pl-k">target</span> <span class="pl-c1">===</span> <span class="pl-v">Person</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">name</span> <span class="pl-c1">=</span> <span class="pl-s1">name</span><span class="pl-kos">;</span> <span class="pl-kos">}</span> <span class="pl-k">else</span> <span class="pl-kos">{</span> <span class="pl-k">throw</span> <span class="pl-k">new</span> <span class="pl-v">Error</span><span class="pl-kos">(</span><span class="pl-s">'必须使用new生成实例'</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-kos">}</span> <span class="pl-kos">}</span> <span class="pl-k">var</span> <span class="pl-s1">person</span> <span class="pl-c1">=</span> <span class="pl-k">new</span> <span class="pl-v">Person</span><span class="pl-kos">(</span><span class="pl-s">'张三'</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-c">// 正确 </span> <span class="pl-k">var</span> <span class="pl-s1">notAPerson</span> <span class="pl-c1">=</span> <span class="pl-v">Person</span><span class="pl-kos">.</span><span class="pl-en">call</span><span class="pl-kos">(</span><span class="pl-s1">person</span><span class="pl-kos">,</span> <span class="pl-s">'张三'</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-c">// 报错</span> |
需要注意的是,子类继承父类时,new.target会返回子类。
1 2 3 4 5 6 7 8 |
<span class="pl-k">class</span> <span class="pl-v">Rectangle</span> <span class="pl-kos">{</span> <span class="pl-en">constructor</span><span class="pl-kos">(</span><span class="pl-s1">length</span><span class="pl-kos">,</span> <span class="pl-s1">width</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-smi">console</span><span class="pl-kos">.</span><span class="pl-en">log</span><span class="pl-kos">(</span><span class="pl-k">new</span><span class="pl-kos">.</span><span class="pl-k">target</span> <span class="pl-c1">===</span> <span class="pl-v">Rectangle</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-c">// ... </span> <span class="pl-kos">}</span> <span class="pl-kos">}</span> <span class="pl-k">class</span> <span class="pl-v">Square</span> <span class="pl-k">extends</span> <span class="pl-v">Rectangle</span> <span class="pl-kos">{</span> <span class="pl-en">constructor</span><span class="pl-kos">(</span><span class="pl-s1">length</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-smi">super</span><span class="pl-kos">(</span><span class="pl-s1">length</span><span class="pl-kos">,</span> <span class="pl-s1">length</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-kos">}</span> <span class="pl-kos">}</span> <span class="pl-k">var</span> <span class="pl-s1">obj</span> <span class="pl-c1">=</span> <span class="pl-k">new</span> <span class="pl-v">Square</span><span class="pl-kos">(</span><span class="pl-c1">3</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-c">// 输出 false</span> |
利用这个特点,可以写出不能独立使用、必须继承后才能使用的类。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<span class="pl-k">class</span> <span class="pl-v">Shape</span> <span class="pl-kos">{</span> <span class="pl-en">constructor</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-k">if</span> <span class="pl-kos">(</span><span class="pl-k">new</span><span class="pl-kos">.</span><span class="pl-k">target</span> <span class="pl-c1">===</span> <span class="pl-v">Shape</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-k">throw</span> <span class="pl-k">new</span> <span class="pl-v">Error</span><span class="pl-kos">(</span><span class="pl-s">'本类不能实例化'</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-kos">}</span> <span class="pl-kos">}</span> <span class="pl-kos">}</span> <span class="pl-k">class</span> <span class="pl-v">Rectangle</span> <span class="pl-k">extends</span> <span class="pl-v">Shape</span> <span class="pl-kos">{</span> <span class="pl-en">constructor</span><span class="pl-kos">(</span><span class="pl-s1">length</span><span class="pl-kos">,</span> <span class="pl-s1">width</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-smi">super</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-c">// ... </span> <span class="pl-kos">}</span> <span class="pl-kos">}</span> <span class="pl-k">var</span> <span class="pl-s1">x</span> <span class="pl-c1">=</span> <span class="pl-k">new</span> <span class="pl-v">Shape</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-c">// 报错 var y = new Rectangle(3, 4); // 正确</span> |
多继承的实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<span class="pl-k">function</span> <span class="pl-en">mix</span><span class="pl-kos">(</span>...<span class="pl-s1">mixins</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-k">class</span> <span class="pl-v">Mix</span> <span class="pl-kos">{</span><span class="pl-kos">}</span> <span class="pl-k">for</span> <span class="pl-kos">(</span><span class="pl-k">let</span> <span class="pl-s1">mixin</span> <span class="pl-k">of</span> <span class="pl-s1">mixins</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-en">copyProperties</span><span class="pl-kos">(</span><span class="pl-v">Mix</span><span class="pl-kos">,</span> <span class="pl-s1">mixin</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-en">copyProperties</span><span class="pl-kos">(</span><span class="pl-v">Mix</span><span class="pl-kos">.</span><span class="pl-c1">prototype</span><span class="pl-kos">,</span> <span class="pl-s1">mixin</span><span class="pl-kos">.</span><span class="pl-c1">prototype</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-kos">}</span> <span class="pl-k">return</span> <span class="pl-v">Mix</span><span class="pl-kos">;</span> <span class="pl-kos">}</span> <span class="pl-k">function</span> <span class="pl-en">copyProperties</span><span class="pl-kos">(</span><span class="pl-s1">target</span><span class="pl-kos">,</span> <span class="pl-s1">source</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-k">for</span> <span class="pl-kos">(</span><span class="pl-k">let</span> <span class="pl-s1">key</span> <span class="pl-k">of</span> <span class="pl-v">Reflect</span><span class="pl-kos">.</span><span class="pl-en">ownKeys</span><span class="pl-kos">(</span><span class="pl-s1">source</span><span class="pl-kos">)</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-k">if</span> <span class="pl-kos">(</span> <span class="pl-s1">key</span> !== <span class="pl-s">"constructor"</span> <span class="pl-c1">&&</span> <span class="pl-s1">key</span> !== <span class="pl-s">"prototype"</span> <span class="pl-c1">&&</span> <span class="pl-s1">key</span> !== <span class="pl-s">"name"</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-k">let</span> <span class="pl-s1">desc</span> <span class="pl-c1">=</span> <span class="pl-v">Object</span><span class="pl-kos">.</span><span class="pl-en">getOwnPropertyDescriptor</span><span class="pl-kos">(</span><span class="pl-s1">source</span><span class="pl-kos">,</span> <span class="pl-s1">key</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-v">Object</span><span class="pl-kos">.</span><span class="pl-en">defineProperty</span><span class="pl-kos">(</span><span class="pl-s1">target</span><span class="pl-kos">,</span> <span class="pl-s1">key</span><span class="pl-kos">,</span> <span class="pl-s1">desc</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-kos">}</span> <span class="pl-kos">}</span> <span class="pl-kos">}</span> |
发表评论