ホームページ ウェブフロントエンド フロントエンドQ&A JavaScriptの継承はどのような用途に使われるのでしょうか?

JavaScriptの継承はどのような用途に使われるのでしょうか?

Jan 18, 2022 pm 01:48 PM
javascript 継承する

JavaScript 継承の機能: 1. 「親クラス」のコンストラクターを呼び出さずに新しいインスタンスを作成できます; 2. 「親クラス」のプロトタイプを変更することで、作成されたすべてのインスタンスを動的に変更できます; 3.オブジェクトのプロトタイプを動的に変更できます。

JavaScriptの継承はどのような用途に使われるのでしょうか?

このチュートリアルの動作環境: Windows7 システム、JavaScript バージョン 1.8.5、Dell G3 コンピューター。

JavaScript は、オブジェクト、モデルとしての関数、および継承としてのプロトタイプに基づくオブジェクト指向開発モデルです。

#JavaScript 継承の役割: #1. 「親クラス」のコンストラクターを呼び出さずに新しいインスタンスを作成できます

2、「親クラス」のプロトタイプを変更して、作成されたすべてのインスタンスを動的に変更します

3. オブジェクトのプロトタイプを動的に変更できます。つまり、親は変更できます

次のJavaScript の型メソッドの定義と、継承を実装するための一般的なパターンを紹介します。

プロトタイプの構築

プロトタイプのプロトタイプを直接使用してクラス継承を設計する場合には、2 つの問題があります。

コンストラクタは事前に宣言され、クラス構造の宣言後にプロトタイプの属性が定義されるため、コンストラクタを介してプロトタイプに動的にパラメータを渡すことはできません。このように、インスタンス化されたオブジェクトはすべて同じように見え、個性がありません。プロトタイプのプロパティ値を変更すると、すべてのインスタンスが影響を受けます。

プロトタイプ属性の値が参照型データの場合、1 つのオブジェクト インスタンスで属性値を変更すると、すべてのインスタンスに影響します。

例 1

Book タイプを定義してインスタンス化するだけです。

function Book () {};  //声明构造函数
Book.prototype.o = {x : 1, y : 2};  //构造函数的原型属性o是一个对象
var book1 = new Book ();  //实例化对象book1
var book2 = new Book ();  //实例化对象book2
console.log(book1.o.x);  //返回1
console.log(book2.o.x);  //返回1
book2.o.x = 3;  //修改实例化对象book2中的属性x的值
console.log(book1.o.x);  //返回3
console.log(book2.o.x);  //返回3
ログイン後にコピー

プロトタイプ属性 o は参照値であるため、すべてのインスタンスの属性 o の値は同じオブジェクトへの参照になります。o の値が変更されると、すべてのインスタンスに影響します。

コンストラクション プロトタイプは、プロトタイプ パターンを解決するために生まれたハイブリッド デザイン パターンであり、上記の問題を回避するために、コンストラクター パターンとプロトタイプ パターンを混合します。

実装方法: 相互に影響を与える可能性のあるプロトタイププロパティや動的にパラメータを渡したいプロパティは、コンストラクタパターンを使用して独立して設計できます。個別に設計する必要がなく、共通の特性を持つメソッドや属性については、プロトタイプパターンを使用して設計できます。

例 2

上記の設計原則に従い、2 つのプロパティをコンストラクター パターンに設計します。この設計メソッドはプロトタイプ パターンです。

function Book (title, pages) {  //构造函数模式设计
    this.title = title;
    this.pages = pages;
}
Book.prototype.what = function () {  //原型模式设计
    console.log(this.title + this.pages);
};
var book1 = new Book("JavaScript 程序设计", 160);
var book2 = new Book("C语言程序设计", 240);
console.log(book1.title);
console.log(book2.title);
ログイン後にコピー

構築されたプロトタイプ パターンは、ECMAScript でクラスを定義するための推奨標準です。一般に、コンストラクター パターンを使用してすべてのプロパティを定義し、プロトタイプ パターンを使用してすべてのメソッドを定義することをお勧めします。この方法では、すべてのメソッドが 1 回だけ作成され、各インスタンスは必要に応じてプロパティ値を設定できます。これは最も広く使用されているデザイン パターンでもあります。

動的プロトタイプ

オブジェクト指向設計原則によれば、型のすべてのメンバーはクラス構造にカプセル化される必要があります。例:

function Book (title, pages) {  //构造函数模式设计
    this.title = title;
    this.pages = pages;
    Book.prototype.what = function () {  //原型模式设计,位于类的内部
        console.log(this.title + this.pages);
    };
}
ログイン後にコピー

しかし、インスタンス化されるたびに、クラス Book に含まれるプロトタイプ メソッドが繰り返し作成され、大量のプロトタイプ メソッドが生成され、システム リソースが無駄に消費されます。 if を使用して、プロトタイプ メソッドが存在するかどうかを判断できます。存在する場合、メソッドは作成されません。存在しない場合、メソッドは作成されます。

function Book (title, pages) {
    this.title = title;
    this.pages = pages;
    if (typeof Book.isLock == "undefined") {  //创建原型方法的锁,如果不存在则创建
        Book.prototype.what = function () {
            console.log(this.title + this.pages);
        };
        Book.isLock = true;  //创建原型方法后,把锁锁上,避免重复创建
    }
}
var book1 = new Book("JavaScript 程序设计", 160);
var book2 = new Book("C语言程序设计", 240);
console.log(book1.title);
console.log(book2.title);
ログイン後にコピー

typeof Book.isLock 式は属性値の型を検出できます。未定義の文字列が返された場合、属性値は存在せず、プロトタイプ メソッドが作成されていないことを示し、この属性を設定するには、プロトタイプ メソッドを使用します。値は true なので、プロトタイプ メソッドを繰り返し作成する必要はありません。プロトタイプはオブジェクト インスタンスではなくクラス自体に属しているため、ここではクラス名 Book が使用されています。

動的プロトタイプ モードと構築プロトタイプ モードはパフォーマンスが同等であり、ユーザーは自由に選択できますが、構築プロトタイプ モードの方が広く使用されています。

ファクトリ パターン

ファクトリ パターンは型を定義する最も基本的な方法であり、JavaScript で最も一般的に使用される開発パターンでもあります。オブジェクトのインスタンス化を関数にカプセル化し、その関数を呼び出して、インスタンス オブジェクトの迅速なバッチ生成を実現します。

例 1

次の例では、車のタイプを設計します。これには、車の色、駆動輪の数、100 キロメートルごとの燃料消費量の 3 つの属性が含まれており、また、車の色。

function Car (color, drive, oil) {  //汽车类
    var _car =  new Object();  //临时对象
        _car.color = color;  //初始化颜色
        _car.drive = drive;  //初始化驱动轮数
        _car.oil = oil;  //初始化百公里油耗
        _car.showColor = function () {  //方法,提示汽车颜色
            console.log(this.color);
        };
        return _car;  //返回实例
}
var car1 = Car("red", 4, 8);
var car2 = Car("blue", 2, 6);
car1.showColor();  //输出“red”
car2.showColor();  //输出“blue”
ログイン後にコピー

上記のコードは、単純なファクトリ パターン タイプです。Car クラスを使用すると、複数の車のインスタンスをすばやく作成できます。それらの構造は同じですが、属性が異なります。異なる色、数を初期化できます。駆動輪と100kmあたりの燃料消費量。

例 2

型において、メソッドは、初期化パラメータに基づいて特定のタスクを完了できる動作または操作であり、共通の特性を持っています。したがって、メソッドを Car() 関数の外側に配置して、インスタンス化されるたびに関数を作成することを避け、各インスタンスが同じ関数を共有できるようにすることを検討できます。

function showColor () {  //公共方法,提示汽车颜色
    console.log(this.color);
};
function Car (color, drive, oil) {  //汽车类
    var _car = new Object();  //临时对象
        _car.color = color;  //初始化颜色
        _car.drive = drive;  //初始化驱动轮数
        _car.oil = oil;  //初始化百公里油耗
        _car.showColor = showColor;  //引用外部函数
    return _car;  //返回实例
}
ログイン後にコピー

上記の書き換えられたコードでは、関数 showColor() が関数 Car() の前に定義されています。 Car() 内で外部の showColor() 関数を参照することにより、インスタンス化されるたびに新しい関数を作成する必要がなくなります。機能的には、これにより関数を繰り返し作成する問題は解決されますが、意味的には、この関数はオブジェクト メソッドとは異なります。

#クラス継承

クラス継承の設計方法: サブクラスで親クラスのコンストラクターを呼び出します。

在 JavaScript 中实现类继承,需要注意以下 3 个技术问题。

在子类中,使用 apply 调用父类,把子类构造函数的参数传递给父类父类构造函数。让子类继承父类的私有属性,即 Parent.apply(this, arguments); 代码行。

在父类和子类之间建立原型链,即 Sub.prototype = new Parent(); 代码行。通过这种方式保证父类和子类是原型链上的上下级关系,即子类的 prototype 指向父类的一个实例。

恢复子类的原型对象的构造函数,即 Sub.prototype.constructor=Sub;语句行。当改动 prototype 原型时,就会破坏原来的 constructor 指针,所以必须重置 constructor。

示例1

下面示例演示了一个三重继承的案例,包括基类、父类和子类,它们逐级继承。

//基类Base
function Base (x) {  //构造函数Base
    this.get = function () {  //私有方法,获取参数值
        return x;
    }
}
Base.prototype.has = function () {  //原型方法,判断get()方法返回值是否为0
    return ! (this.get() == 0);
}
//父类Parent
function Parent () {  //构造函数Parent
    var a = [];  //私有数组a
    a = Array.apply(a, arguments);  //把参数转换为数组
    Base.call(this, a.length);  //调用Base类,并把参数数组长度传递给它
    this.add = function () {  //私有方法,把参数数组补加到数组a中并返回
        return a.push.apply(a, arguments)
    }
    this.geta = function () {  //私有方法,返回数组a
        return a;
    }
}
Parent.prototype = new Base();  //设置Parent原型为Base的实例,建立原型链
Parent.prototype.constructor = Parent;  //恢复Parent类原型对象的构造器
Parent.prototype.str = function (){  //原型方法,把数组转换为字符串并返回
    return this.geta().toString();
}
//子类Sub
function Sub () {  //构造函数
    Parent.apply(this, arguments);  //调用Parent类,并把参数数组长度传递给它
    this.sort = function () {  //私有方法,以字符顺序对数组进行排序
        var a = this.geta();  //获取数组的值
        a.sort.apply(a, arguments);  //调用数组排序方法 sort()对数组进行排序
    }
}
Sub.prototype = new Parent();  //设置Sub原型为Parent实例,建立原型链
Sub.prototype.constructor = Sub;  //恢复Sub类原型对象的构造器
//父类Parent的实例继承类Base的成员
var parent = new Parent (1, 2, 3, 4);  //实例化Parent类
console.log(parent.get());  //返回4,调用Base类的方法get()
console.log(parent.has());  //返回true,调用Base类的方法has()
//子类Sub的实例继承类Parent和类Base的成员
var sub = new Sub (30, 10, 20, 40);  //实例化Sub类
sub.add(6, 5);  //调用Parent类方法add(),补加数组
console.log(sub.geta());  //返回数组30,10,20,40,6,5
sub.sort();  //排序数组
console.log(sub.geta());  //返回数组10,20,30,40,5,6
console.log(sub.get());  //返回4,调用Base类的方法get()
console.log(sub.has());  //返回true,调用Base类的方法has()
console.log(sub.str());  //返回10,20,30,40,5,6
ログイン後にコピー

【设计思路】

设计子类 Sub 继承父类 Parent,而父类 Parent 又继承基类 Base。Base、Parent、Sub 三个类之间的继承关系是通过在子类中调用的构造函数来维护的。

例如,在 Sub 类中,Parent.apply(this, arguments); 能够在子类中调用父类,并把子类的参数传递给父类,从而使子类拥有父类的所有属性。

同理,在父类中,Base.call(this, a.length); 把父类的参数长度作为值传递给基类,并进行调用,从而实现父类拥有基类的所有成员。

从继承关系上看,父类继承了基类的私有方法 get(),为了确保能够继承基类的原型方法,还需要为它们建立原型链,从而实现原型对象的继承关系,方法是添加语句行 Parent.prototype=new Base();。

同理,在子类中添加语句 Sub.prototype=new Parent();,这样通过原型链就可以把基类、父类和子类串连在一起,从而实现子类能够继承父类属性,还可以继承基类的属性。

示例2

下面尝试把类继承模式封装起来,以便规范代码应用。

function extend (Sub, Sup) {  //类继承封装函数
    var F = function () {};  //定义一个空函数
    F.prototype = Sup.prototype;  //设置空函数的原型为父类的原型
    Sub.prototype = new F ();  //实例化空函数,并把父类原型引用传给给子类
    Sub.prototype.constructor = Sub;  //恢复子类原型的构造器为子类自身
    Sub.sup = Sup.prototype;  //在子类定义一个私有属性存储父类原型
    //检测父类原型构造器是否为自身
    if (Sup.prototype.constructor == Object.prototype.constructor) {
        Sup.prototype.constructor = Sup;  //类继承封装函数
    }
}
ログイン後にコピー

【操作步骤】

1) 定义一个封装函数。设计入口为子类和父类对象,函数功能是子类能够继承父类的所有原型成员,不涉及出口。

function extend (Sub, Sup) {  //类继承封装函数
    //其中参数Sub表示子类,Sup表示父类
}
ログイン後にコピー

2) 在函数体内,首先定义一个空函数 F,用来实现功能中转。设计它的原型为父类的原型,然后把空函数的实例传递给子类的原型,这样就避免了直接实例化父类可能带来的系统负荷。因为在实际开发中,父类的规模可能会很大,如果实例化,会占用大量内存。

3) 恢复子类原型的构造器为子类自己。同时,检测父类原型构造器是否与 Object 的原型构造器发生耦合。如果是,则恢复它的构造器为父类自身。

下面定义两个类,尝试把它们绑定为继承关系。

function A (x) {  //构造函数A
    this.x = x;  //私有属性x
    this.get = function () {  //私有方法get()
        return this.x;
    }
}
A.prototype.add = function () {  //原型方法add()
    return this.x + this.x;
}
A.prototype.mul = function () {  //原型方法mul()
    return this.x * this.x;
}
function B (x) {  //构造函数B
    A.call (this.x);  //在函数体内调用构造函数A,实现内部数据绑定
}
extend (B, A);  //调用封装函数,把A和B的原型捆绑在一起
var f = new B (5);  //实例化类B
console.log(f.get());  //继承类A的方法get(),返回5
console.log(f.add());  //继承类A的方法add(),返回10
console.log(f.mul());  //继承类A的方法mul(),返回25
ログイン後にコピー

在函数类封装函数中,有这么一句 Sub.sup=Sup.prototype;,在上面代码中没有被利用,那么它有什么作用呢?为了解答这个问题,先看下面的代码。

extend (B, A);
B.prototype.add = function () {  //为B类定义一个原型方法
    return this.x + "" + this.x;
}
ログイン後にコピー

上面的代码是在调用封装函数之后,再为 B 类定义了一个原型方法,该方法名与基类中原型方法 add() 同名,但是功能不同。如果此时测试程序,会发现子类 B 定义的原型方法 add() 将会覆盖父类 A 的原型方法 add()。

console.log(f.add());  //返回字符串55,而不是数值10
ログイン後にコピー

如果在 B 类的原型方法 add() 中调用父类的原型方法 add(),避免代码耦合现象发生。

B.prototype.add = function () {  //定义子类B的原型方法add()
    return B.sup.add.call(this);  //在函数内部调用父类方法add()
}
ログイン後にコピー

【相关推荐:javascript学习教程

以上がJavaScriptの継承はどのような用途に使われるのでしょうか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

C++関数継承の詳しい解説:継承で「基底クラスポインタ」と「派生クラスポインタ」を使うには? C++関数継承の詳しい解説:継承で「基底クラスポインタ」と「派生クラスポインタ」を使うには? May 01, 2024 pm 10:27 PM

関数の継承では、「基底クラス ポインター」と「派生クラス ポインター」を使用して継承メカニズムを理解します。基底クラス ポインターが派生クラス オブジェクトを指す場合、上方変換が実行され、基底クラスのメンバーのみにアクセスされます。派生クラス ポインターが基本クラス オブジェクトを指す場合、下向きキャストが実行される (安全ではない) ため、注意して使用する必要があります。

簡単な JavaScript チュートリアル: HTTP ステータス コードを取得する方法 簡単な JavaScript チュートリアル: HTTP ステータス コードを取得する方法 Jan 05, 2024 pm 06:08 PM

JavaScript チュートリアル: HTTP ステータス コードを取得する方法、特定のコード例が必要です 序文: Web 開発では、サーバーとのデータ対話が頻繁に発生します。サーバーと通信するとき、多くの場合、返された HTTP ステータス コードを取得して操作が成功したかどうかを判断し、さまざまなステータス コードに基づいて対応する処理を実行する必要があります。この記事では、JavaScript を使用して HTTP ステータス コードを取得する方法を説明し、いくつかの実用的なコード例を示します。 XMLHttpRequestの使用

C++ 関数の継承の詳細な説明: 継承のエラーをデバッグするには? C++ 関数の継承の詳細な説明: 継承のエラーをデバッグするには? May 02, 2024 am 09:54 AM

継承エラーのデバッグのヒント: 正しい継承関係を確認します。デバッガーを使用してコードをステップ実行し、変数値を調べます。仮想修飾子を正しく使用してください。隠れた相続によって引き起こされる相続ダイアモンド問題を調べてください。抽象クラスに実装されていない純粋仮想関数がないか確認します。

継承とポリモーフィズムは C++ のクラス結合にどのような影響を与えますか? 継承とポリモーフィズムは C++ のクラス結合にどのような影響を与えますか? Jun 05, 2024 pm 02:33 PM

継承とポリモーフィズムはクラスの結合に影響します。派生クラスは基本クラスに依存するため、継承により結合が増加します。ポリモーフィズムにより、オブジェクトは仮想関数と基本クラス ポインターを通じて一貫した方法でメッセージに応答できるため、結合が軽減されます。ベスト プラクティスには、継承を控えめに使用すること、パブリック インターフェイスを定義すること、基本クラスへのデータ メンバーの追加を回避すること、依存関係の注入を通じてクラスを分離することが含まれます。ポリモーフィズムと依存性注入を使用して銀行口座アプリケーションの結合を軽減する方法を示す実践的な例。

C++ 関数の継承の詳細な説明: 継承における 'is-a' と 'has-a' の関係を理解するには? C++ 関数の継承の詳細な説明: 継承における 'is-a' と 'has-a' の関係を理解するには? May 02, 2024 am 08:18 AM

C++の関数継承を詳しく解説:「is-a」と「has-a」の関係をマスターしよう 関数継承とは?関数の継承は、派生クラスで定義されたメソッドを基本クラスで定義されたメソッドに関連付ける C++ の手法です。これにより、派生クラスが基本クラスのメソッドにアクセスしてオーバーライドできるようになり、基本クラスの機能が拡張されます。 「is-a」および「has-a」関係 関数継承では、「is-a」関係は、派生クラスが基本クラスのサブタイプであること、つまり、派生クラスが基本クラスの特性と動作を「継承」することを意味します。基本クラス。 「has-a」関係は、派生クラスに基本クラス オブジェクトへの参照またはポインターが含まれていること、つまり、派生クラスが基本クラス オブジェクトを「所有」していることを意味します。構文関数継承を実装する方法の構文は次のとおりです: classDerivedClass:pu

JavaScript で HTTP ステータス コードを簡単に取得する方法 JavaScript で HTTP ステータス コードを簡単に取得する方法 Jan 05, 2024 pm 01:37 PM

JavaScript で HTTP ステータス コードを取得する方法の紹介: フロントエンド開発では、バックエンド インターフェイスとの対話を処理する必要があることが多く、HTTP ステータス コードはその非常に重要な部分です。 HTTP ステータス コードを理解して取得すると、インターフェイスから返されたデータをより適切に処理できるようになります。この記事では、JavaScript を使用して HTTP ステータス コードを取得する方法と、具体的なコード例を紹介します。 1. HTTP ステータス コードとは何ですか? HTTP ステータス コードとは、ブラウザがサーバーへのリクエストを開始したときに、サービスが

「PHP によるオブジェクト指向プログラミング入門: 概念から実践まで」 「PHP によるオブジェクト指向プログラミング入門: 概念から実践まで」 Feb 25, 2024 pm 09:04 PM

オブジェクト指向プログラミングとは何ですか?オブジェクト指向プログラミング (OOP) は、現実世界のエンティティをクラスに抽象化し、オブジェクトを使用してこれらのエンティティを表すプログラミング パラダイムです。クラスはオブジェクトのプロパティと動作を定義し、オブジェクトはクラスをインスタンス化します。 OOP の主な利点は、コードの理解、保守、再利用が容易になることです。 OOP の基本概念 OOP の主な概念には、クラス、オブジェクト、プロパティ、メソッドが含まれます。クラスはオブジェクトの設計図であり、オブジェクトのプロパティと動作を定義します。オブジェクトはクラスのインスタンスであり、クラスのすべてのプロパティと動作を備えています。プロパティは、データを保存できるオブジェクトの特性です。メソッドは、オブジェクトのデータを操作できるオブジェクトの関数です。 OOP の利点 OOP の主な利点は次のとおりです。 再利用性: OOP はコードをより高度なものにすることができます。

C++ 関数の継承の説明: 継承を使用すべきでないのはどのような場合ですか? C++ 関数の継承の説明: 継承を使用すべきでないのはどのような場合ですか? May 04, 2024 pm 12:18 PM

C++ 関数の継承は、次の状況では使用しないでください。 派生クラスが異なる実装を必要とする場合、異なる実装を持つ新しい関数を作成する必要があります。派生クラスが関数を必要としない場合は、空のクラスとして宣言するか、プライベートの未実装の基本クラス メンバー関数を使用して関数の継承を無効にする必要があります。関数が継承を必要としない場合は、コードの再利用を実現するために他のメカニズム (テンプレートなど) を使用する必要があります。

See all articles