## class expression: const Person = class { } ## class declaration: class Person { constructor(fName, bYear){ this.fName = fName; this.bYear = bYear; } calcAge(){ console.log(2024 - this.bYear); } } - constructor is a method of this class. Pass values for properties to have in objects created using this fn. - then set the properties of the object using this.xxx = xxx; - On using 'new' operator, this constructor will be called automatically and return a new object which will be stored in LHS variable as shown below. Ex. const ronald = new Person('ronald',1975); // Person { fName: 'ronald', bYear: 1975 } - Methods are written outside the constructor fn and will be added to the prototype property of the object which can be verified using devConsole. Ex. ronald.calcAge(); // 49 ronald.__proto__ === Person.prototype; // true - No commas need to be added while adding multiple methods below the constructor fn inside the class. ## Hence, the above syntax works same as constructor fn syntax but with a familiar syntax of strongly typed class based languages. ## Adding a fn explicitly to the prototype: Person.prototype.greet = function(){ console.log(`Hey ${this.fName}`); } ronald.greet(); // 'Hey ronald'
インプトポイント:
アクセサーのプロパティ: ゲッターとセッター、つまり値を取得および設定する関数。しかし、外見上は通常の物件のように見えます。
通常のプロパティはデータ プロパティと呼ばれます。
const account = { owner: 'jonas', movements: [200,300,100,500], get latest(){ // will return an array with last value. Hence, use pop to get the value. return this.movements.slice(-1).pop(); }, set latest(mov){ this.movements.push(mov); } } account.latest; // 500 account.latest = 50; account.latest; // 50 Just like above, classes also support the getter-setter methods but acccessed like using a property syntax. These are very useful for data validation.
例: Array.from() = 配列のような構造体を配列に変換します。
Array.from(document.querySelector('h1'));
Array.from(document.querySelectorAll('h1'));
例: .from は、コンストラクターのプロトタイプ プロパティではなく、配列コンストラクターにアタッチされます。したがって、すべての配列はこの fn を継承しません。
[1,2,3].from(); // .from は関数ではありません
例: Number.parseFloat(12) は Number コンストラクターの静的メソッドであり、number 変数では使用できません。
// Static methods are not inherited. They are not added to prototype. className.fnName = function(){ console.log(this); // Entire constructor() which is calling the method console.log("JS is awesome") }; className.fnName(); // Rule = whatever object is calling the method, 'this' points to that object inside the fn. Hence its simply the entire constructor() above. //Inside class, we need to use static keyword for adding a static method. static fnName = function(){ console.log(this); // can point to the entire class defn console.log("JS is awesome") }; // Static methods and instance methods will be different from each other. // instance methods will be prototype, hence all instances can have access to them
オブジェクトのプロトタイプを任意のオブジェクトに設定するために手動で使用されます。
継承双方向クラスを実装するために使用されます。
この fn を使用して実装されたプロトタイプの継承
Object.create は空のオブジェクトを返します。
コンストラクターの fns とクラスが動作するのとは異なる方法で動作します。
'prototype'、'constructor()'、'new' 演算子が関与しなくても、プロトタイプ継承のアイデアはまだ存在します。
const PersonProto = { // This method will be looked up using __proto__ link calcAge(){ console.log(2024 - this.bYear); } }; // baba will be created, with its prototype set to PersonProto object. const baba = Object.create(PersonProto); baba; baba.name = 'Roger'; baba.bYear = '2000'; baba.calcAge();
コンストラクター Fn --(.prototype)--> 人物.プロトタイプ
オブジェクト インスタンス --(proto)--> 人物.プロトタイプ
fn コンストラクターやクラスで動作したのと同じように動作します
この目標を達成するために、constructor() や .prototype プロパティは必要ありません。
const PersonProto = { // This method will be looked up using __proto__ link calcAge(){ console.log(2024 - this.bYear); }, // Noting special with init name, its a normal fn here. // This has nothing to with ES6 constructor() // Manual way of initialzing an object. init(fName, bYear){ this.fName = fName; this.bYear = bYear; } }; // baba will be created, with its prototype set to PersonProto object. const baba = Object.create(PersonProto); baba; baba.name = 'Roger'; baba.bYear = '2000'; baba.calcAge(); baba.__proto__; // { calcAge: [Function: calcAge] } baba.__proto__ === PersonProto; //true const alice = Object.create(PersonProto); alice.init("alice", 2000); alice; // { fName: 'alice', bYear: 2000 }
プロトタイプ継承を作成する方法:
コンストラクター Fn
ES6 クラス
Object.create
これらのテクニックはすべて、オブジェクトがそのプロトタイプ上のメソッドを検索できるようにします。
実際のクラスは JS には存在しません。
const Person = function(firstName, bYear){ this.firstName = firstName; this.bYear = bYear; }; Person.prototype.calcAge = function(){ console.log(2024 - this.bYear); }; const Student = function(firstName, bYear, course){ // This is the duplicate code, any change in Person won't be reflected here. this.firstName = firstName; this.bYear = bYear; this.course = course; }; Student.prototype.introduce = function(){ console.log(`My name is ${this.firstName} and I study ${this.course}`); } const matt = new Student("Matt", 2000, "CSE"); matt.introduce(); // 'My name is Matt and I study CSE'
const Person = function(firstName, bYear){ this.firstName = firstName; this.bYear = bYear; }; Person.prototype.calcAge = function(){ console.log(2024 - this.bYear); }; const Student = function(firstName, bYear, course){ // Person(firstName, bYear); -> This doesn't work because we are calling it as a regular fn call. 'new' has to be used to call this fn constructor. This fn call is simply a regular fn call, in which 'this' is set 'undefined'. Hence, an error as it cannot set firstName on undefined. // We want to set the 'this' inside this fn to be same as inside Person above. Person.call(this, firstName, bYear); this.course = course; }; Student.prototype.introduce = function(){ console.log(`My name is ${this.firstName} and I study ${this.course}`); } const matt = new Student("Matt", 2000, "CSE"); matt.introduce(); // 'My name is Matt and I study CSE'
'new' は、proto
を介してオブジェクト インスタンスとそのプロトタイプの間に自動的にリンクを作成します。
継承の全体的な考え方は、子クラスがプロトタイプ チェーンを通じて親クラスからの動作を共有できるということです。
プロトタイプ[オブジェクト.プロトタイプ] = null; // プロトタイプ チェーンの最上位に位置します。
const Person = function(firstName, bYear){ this.firstName = firstName; this.bYear = bYear; }; Person.prototype.calcAge = function(){ console.log(2024 - this.bYear); }; const Student = function(firstName, bYear, course){ Person.call(this, firstName, bYear); this.course = course; }; // Student.prototype = Person.prototype; => This doesn't work because we won't get the prototype chain, rather we will get // Constructor fn[i.e Person()] --------------> Person.prototype // Constructor fn[i.e Student()] --------------> Person.prototype // Object [Matt] __proto__: Student.prototype ---> Person.prototype // Student.prototype manually linked for lookup to Person.prototype. // This has to be done here and not after else Object.create will overwrite any of the existing methods like introduce() on it. Student.prototype = Object.create(Person.prototype); Student.prototype.introduce = function(){ console.log(`My name is ${this.firstName} and I study ${this.course}`); } const matt = new Student("Matt", 2000, "CSE"); matt.introduce(); // 'My name is Matt and I study CSE' matt.calcAge(); // 24 matt.__proto__; // Person { introduce: [Function (anonymous)] } matt.__proto__.__proto__; // { calcAge: [Function (anonymous)] } matt.__proto__.__proto__.__proto__; // [Object: null prototype] {} Student.prototype.constructor = Student; // [Function: Student] matt instanceof Student; // true matt instanceof Person; // true matt instanceof Object; // true
以上がJS の OOP -の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。