Objective
JS based on the prototype of the ' class ', has been the front-end of the code to call surprise, but close to the traditional mode use class
keyword definitions appear, but make some front-end counterparts deeply regret and have a message: "Also my unique JS", "net do something no substance", "I do not have the class to other other class on the", Even "changed careers" and so on. There is a normal mood, after all, new knowledge means more time and energy costs, and not simply close your eyes to enjoy.
However, the history of the axis printing is still, for a class
certain point is that you can not say to the interviewer: "Please, not the younger brother does not understand, just do not want to know, you change a question Bai!" "On the one hand although it is class
only a grammatical sugar, but the extends
improvement of inheritance is good." On the other hand, the new feature that might appear on ' class ' In the future should be class
hosted by rather than a constructor, and no one is sure how beautiful it will be in the future. So come and drink this steaming bowl of brown sugar ginger soup slowly.
1 class
There is no concept of class in ECMAScript, our instance is based on prototypes generated by constructors with dynamic properties and methods of objects. But in order to conform with the international, the description of the more simple and tall, will still use the word ' class '. So the JS class is equivalent to the constructor. ES6 is class
just a syntactic sugar, and its definition of the resulting object is still a constructor. But to distinguish it from the constructor pattern, we call it class mode. Learning class
needs to have the structure function and the prototype object knowledge, the concrete can own Baidu.
// ---使用构造函数function C () { console.log(‘New someone.‘);}C.a = function () { return ‘a‘; }; // 静态方法C.prototype.b = function () { return ‘b‘; }; // 原型方法// ---使用classclass C { static a() { return ‘a‘; } // 静态方法 constructor() { console.log(‘New someone.‘); } // 构造方法 b() { return ‘b‘; } // 原型方法};
1.1 Comparison with variables
A keyword is class
similar to a keyword that defines a function function
, which is defined in two ways: declarative and expression (anonymous and named). The variables defined by the declaration are of a different nature and are function
more similar and do not let
parse in advance, const
do not have variable elevation, are not linked to global scopes, have temporary dead zones, and so on. class
defining a generated variable is a constructor, and therefore, a class can be written as a pattern of immediate execution.
// ---声明式class C {}function F() {}// ---匿名表达式let C = class {};let F = function () {};// ---命名表达式let C = class CC {};let F = function FF() {};// ---本质是个函数class C {}console.log(typeof C); // functionconsole.log(Object.prototype.toString.call(C)); // [object Function]console.log(C.hasOwnProperty(‘prototype‘)); // true// ---不存在变量提升C; // 报错,不存在C。class C {}// 存在提前解析和变量提升F; // 不报错,F已被声明和赋值。function F() {}// ---自执行模式let c = new (class {})();let f = new (function () {})();
1.2 Comparison with objects
The class content ( {}
inside) is similar in form to the object literal. However, the contents of the class can only be defined methods can not define the property, the form of the method can only be abbreviated function, the method can not be separated by commas. The method name can be an expression with parentheses, or it can be a Symbol
value. Methods are divided into three categories, the method of construction ( constructor
method), the prototype method (which exists on the property of the constructor prototype
), and the static method (which exists on the constructor itself)
class C { // 原型方法a a() { console.log(‘a‘); } // 构造方法,每次生成实例时都会被调用并返回新实例。 constructor() {} // 静态方法b,带static关键字。 static b() { console.log(‘b‘); } // 原型方法,带括号的表达式 [‘a‘ + ‘b‘]() { console.log(‘ab‘); } // 原型方法,使用Symbol值 [Symbol.for(‘s‘)]() { console.log(‘symbol s‘); }}C.b(); // blet c = new C();c.a(); // ac.ab(); // abc[Symbol.for(‘s‘)](); // symbol s
Attributes cannot be defined directly, and do not indicate that a class cannot have prototypes or static properties. Parsing class
forms a constructor, so you simply add the class as you would add a property to the constructor. It is also recommended to use only getter
functions to define read-only properties. Why can't I set properties directly? Is it technically immature? Is the official hoping to pass on some kind of thought? Or is it just a question that I throw at random?
// ---直接在C类(构造函数)上修改class C {}C.a = ‘a‘;C.b = function () { return ‘b‘; };C.prototype.c = ‘c‘;C.prototype.d = function () { return ‘d‘; };let c = new C();c.c; // cc.d(); // d// ---使用setter和getter// 定义只能获取不能修改的原型或静态属性class C { get a() { return ‘a‘; } static get b() { return ‘b‘; }}let c = new C();c.a; // ac.a = ‘1‘; // 赋值没用,只有get没有set无法修改。
1.3 Comparison with constructors
The following is code that uses constructors and classes to implement the same functionality. Intuitively, the class
code is simplified to make the content more aggregated. The constructor
method body equals the function body of the constructor, and if this method is not explicitly defined, an empty constructor
method is added by default to return the new instance. As with ES5, you can also customize the return of another object instead of a new instance.
// ---构造函数function C(a) { this.a = a;}// 静态属性和方法C.b = ‘b‘;C.c = function () { return ‘c‘; };// 原型属性和方法C.prototype.d = ‘d‘;C.prototype.e = function () { return ‘e‘; };Object.defineProperty(C.prototype, ‘f‘, { // 只读属性 get() { return ‘f‘; }});// ---类class C { static c() { return ‘c‘; } constructor(a) { this.a = a; } e() { return ‘e‘; } get f() { return ‘f‘; }}C.b = ‘b‘;C.prototype.d = ‘d‘;
A class is a function, but cannot be new
called directly by generating an instance. All methods defined inside the class are non-enumerable, and the properties and methods added on the constructor itself and prototype
above are enumerable. The methods defined internally by the class are strictly schema by default and do not require explicit declaration. The above three points increase the rigor of the class, but unfortunately, there is still no way to directly define the private properties and methods.
//---can directly call class C {}c ();//Error function C () {}c ();//CAN//---can enumerate class C {static A () {}//non-enumerable B () {}// Non-enumerable}c.c = function () {}; Enumerable C.PROTOTYPE.D = function () {}; Enumerable isenumerable (c, [' A ', ' C ']); A false, C trueisenumerable (C.prototype, [' B ', ' d ']); b false, D truefunction isenumerable (target, keys) {Let obj = object.getownpropertydescriptors (target); Keys.foreach (k => {Console.log (k, obj[k].enumerable); });} ---is strict mode class C {A () {let is = false; try {n = 1; } catch (e) {is = true; } console.log (is?) ' True ': ' false '); }}c.prototype.b = function () {Let is = false; try {n = 1; } catch (e) {is = true; } console.log (is?) ' True ': ' false ');}; Let C = new C (); C.A (); True, is strict mode. C.B (); False, not strict mode.
Adding a keyword before the method static
means that this method is a static method, which exists in the class itself and cannot be accessed directly by the instance. The static method points to the this
class itself. Static methods and prototype methods can have duplicate names because they are on different objects. ES6 has added a command new.target
that refers to the new
following constructor or class
that the use of the command has some limitations, see the example below.
// ---staticclass C { static a() { console.log(this === C); } a() { console.log(this instanceof C); }}let c = new C();C.a(); // truec.a(); // true// ---new.target// 构造函数function C() { console.log(new.target);}C.prototype.a = function () { console.log(new.target); };let c = new C(); // 打印出Cc.a(); // 在普通方法中为undefined。// ---类class C { constructor() { console.log(new.target); } a() { console.log(new.target); }}let c = new C(); // 打印出Cc.a(); // 在普通方法中为undefined。// ---在函数外部使用会报错new.target; // 报错
2 extends
The classic inheritance method in ES5 is parasitic combined inheritance, which inherits the attributes and methods on the parent class instance and the prototype, respectively. The same is true of the nature of inheritance in ES6, but the way it is implemented has changed, as in the code below. As you can see, the inheritance on the prototype is in the form of using the extends
keyword, which is closer to the traditional language, and the inheritance on the instance is done by invoking the super
subclass this
shape. On the surface, the way is more unified and concise.
class C1 { constructor(a) { this.a = a; } b() { console.log(‘b‘); }}class C extends C1 { // 继承原型数据 constructor() { super(‘a‘); // 继承实例数据 }}
2.1 Comparison with constructors
Using extends
inheritance not only prototype
sets the prototype object () of the subclass's properties __proto__
to the parent class prototype
, but also sets the prototype object () of the subclass itself to the __proto__
parent class itself. This means that the subclass inherits not only the prototype data of the parent class, but also the static properties and methods owned by the parent class itself. The classic inheritance of ES5 inherits only the prototype data of the parent class. Not only is wealth, even Dad's fame to obtain, good good.
class C1 { static get a() { console.log(‘a‘); } static b() { console.log(‘b‘); }}class C extends C1 {}// 等价,没有构造方法会默认添加。class C extends C1 { constructor(...args) { super(...args); }}let c = new C();C.a; // a,继承了父类的静态属性。C.b(); // b,继承了父类的静态方法。console.log(Object.getPrototypeOf(C) === C1); // true,C的原型对象为C1console.log(Object.getPrototypeOf(C.prototype) === C1.prototype); // true,C的prototype属性的原型对象为C1的prototype
The instance inheritance in ES5 is to create an instance object of the subclass, and this
then call
apply
Add the this
instance properties and methods of the parent class on the or method. Of course, you can choose not to inherit the instance data of the parent class. And ES6 is different, its design makes instance inheritance more excellent and rigorous.
In ES6 instance inheritance, the method is called first to super
create the parent class this
(which still points to the child class) and to add the instance data of the parent class, which is then decorated with the constructor of the subclass, which is the this
opposite of ES5. ES6 specifies that in the subclass constructor
method, the method must be called before it is used to this
super
get the subclass this
. The method is not called super
, which means that the subclass cannot get the this
object.
class C1 { constructor() { console.log(‘C1‘, this instanceof C); }}class C extends C1 { constructor() { super(); // 在super()之前不能使用this,否则报错。 console.log(‘C‘); }}new C(); // 先打印出C1 true,再打印C。
2.2 Super
Keywords are super
more wonderful, in different environments and use the way, it will refer to different things (the total can refer to the object or method two). And when not explicitly indicated is used as an object or method, for example console.log(super)
, will be directly error.
When used as a function. super
can exist only in the constructor of a subclass, when it refers to the parent class constructor.
When you are an object. super
in a static method, the parent class itself, in the constructor method and the prototype method, is the property of the parent class prototype
. However super
, by calling the parent class method, the method this
still points to the child class. That is, by super
invoking the static method of the parent class, the method points to the this
subclass itself, and the method this
points to the instance of the (subclass) when it calls the parent class's prototype method. and by super
Assigning a value to a property, in the subclass of the prototype method to refer to the instance, in the subclass of the static method refers to the subclass itself, after all, directly in the subclass by super
Modifying the parent class is very dangerous.
Very confused, right, crazy, or the combination of code to see it!
class C1 { static a() { console.log(this === C); } b() { console.log(this instanceof C); }}class C extends C1 { static c() { console.log(super.a); // 此时super指向C1,打印出function a。 this.x = 2; // this等于C。 super.x = 3; // 此时super等于this,即C。 console.log(super.x); // 此时super指向C1,打印出undefined。 console.log(this.x); // 值已改为3。 super.a(); // 打印出true,a方法的this指向C。 } constructor() { super(); // 指代父类的构造函数 console.log(super.c); // 此时super指向C1.prototype,打印出function c。 this.x = 2; // this等于新实例。 super.x = 3; // 此时super等于this,即实例本身。 console.log(super.x); // 此时super指向C1.prototype,打印出undefined。 console.log(this.x); // 值已改为3。 super.b(); // 打印出true,b方法的this指向实例本身。 }}
2.3 Inheriting native constructors
Using the constructor pattern, building a subclass that inherits the native data structure (for example Array
) has many drawbacks. On the one hand, it is known from the above that primitive inheritance is the first to create a subclass this
and then be decorated by the parent class constructor, so that the internal properties of the parent class (hidden property) cannot be obtained. On the other hand, the native constructor is ignored directly call
or apply
passed in by the method this
, causing the subclass to not get the instance properties and methods of the parent class at all.
function MyArray(...args) { Array.apply(this, args);}MyArray.prototype = Array.prototype;// MyArray.prototype.constructor = MyArray;let arr = new MyArray(1, 2, 3); // arr为对象,没有储存值。arr.push(4, 5); // 在arr上新增了0,1和length属性。arr.map(d => d); // 返回数组[4, 5]arr.length = 1; // arr并没有更新,依旧有0,1属性,且arr[1]为5。
The process of creating a class is to first construct a parent class that points to a subclass this
(a bypass) and then decorate it with the constructor of the parent class and subclass. Therefore, you can circumvent the problem of constructors, get the instance properties and methods of the parent class, including the internal properties. In turn, a subclass of the native data structure is actually created, thus simply extending the native type. You can also set Symbol.species
properties so that the derived object is a native class instead of a custom subclass instance.
class MyArray extends Array { // 实现是如此的简单 static get [Symbol.species]() { return Array; }}let arr = new MyArray(1, 2, 3); // arr为数组,储存有1,2,3。arr.map(d => d); // 返回数组[1, 2, 3]arr.length = 1; // arr正常更新,已包含必要的内部属性。
It is important to note that the subclass of the inheritance Object
. ES6 changes the Object
behavior of the constructor, and once it is found that it is not new Object()
called in this form, the constructor ignores the arguments passed in. This causes Object
subclasses to not initialize properly, but this is not a big problem.
class MyObject extends Object { static get [Symbol.species]() { return Object; }}let o = new MyObject({ id: 1 });console.log(o.hasOwnPropoty(‘id‘)); // false,没有被正确初始化
Recommended
ES6 Essence: Symbol
ES6 Essence: Promise
Async: A simple and elegant way to Async
True operator of the GENERATOR:JS executive right
Class: A constructor that transforms to a traditional class pattern