ホームページ >ウェブフロントエンド >jsチュートリアル >Javascript オブジェクト指向プログラミング (クールシェル)_js オブジェクト指向

Javascript オブジェクト指向プログラミング (クールシェル)_js オブジェクト指向

WBOY
WBOYオリジナル
2016-05-16 17:55:081286ブラウズ

ここ 2 日間、元同僚から Javascript のオブジェクト指向プログラミングについて質問されてきたので、彼に読んでもらうための記事を書きたいと思います。この記事では主に Javascript のオブジェクト指向プログラミングについて全体的な観点から説明したいと思います。 。 (急いで書いたので、不正確な点や間違いがあるかもしれません。ご批判、修正をお願いします)
また、この記事は主に ECMAScript 5 に基づいており、新しい技術の紹介を目的としています。互換性については最後のセクションを参照してください。

予備学習
JavaScript における変数の定義は基本的に次のとおりであることがわかっています。

コードをコピー コードは次のとおりです:

var name = 'Chen Hao';;
var email = 'haoel(@)hotmail.com';
var website = 'http ://jb51.net ';

オブジェクトに書きたい場合は次のようになります:

コードをコピーします コードは次のとおりです:

var chenhao = {
name :'Chen Hao',
email : 'haoel(@) hotmail.com',
website : ' http://jb51.net'
};

次のようにアクセスできます:

コードをコピーします コードは次のとおりです:

//メンバーとして
chenhao.name; >chenhao.email;
chenhao.website;

// ハッシュマップの形式
chenhao["email"]; ["website"];


関数に関しては、JavaScript 関数は次のようなものであることがわかっています。




コードをコピー コードは次のとおりです。 var doSomething = function(){ alert('Hello World.')
; >
それで、これを行うことができます:




コードをコピー
コードは次のとおりです:var SayHello = function(){ var hello = "こんにちは、私は " this.name "、私のメールアドレスは " this.email
"、私のウェブサイトは " this. website;
alert(hello);
};

//これは C/C 関数ポインターに非常に似ています。 🎜>chenhao.Hello();


これらのことは比較的単純であり、誰もが理解していると思います。 JavaScript オブジェクト関数が直接宣言、直接割り当て、直接使用されていることがわかります。ランタイム用の動的言語。

より標準化された書き方もあります:




コードをコピーします


コードは次のとおりです。以下:this. SayHello = function(){
var hello = "こんにちは、私は " this.name ", n"
"私のメールアドレスは: " this.email ", n"
"私のウェブサイトは: " this.website;
alert(hello);
};
};

var chenhao = new person("Chen Hao", "haoel@hotmail.com",
"http://jb51.net");
chenhao.sayHello();


ところで、オブジェクトのプロパティを削除するのは非常に簡単です:

1 delete chenhao['email']

上記の例から、次の点がわかります:

JavaScript のデータとメンバーのカプセル化は非常に単純です。完全にオブジェクト操作であるクラスはありません。純粋なダイナミクス!
JavaScript 関数の this ポインターは重要です。そうでない場合は、ローカル変数またはローカル関数です。
JavaScript オブジェクトのメンバー関数は、使用時に一時的に宣言し、グローバル関数を直接割り当てることができます。
JavaScript のメンバー関数はインスタンス上で変更できます。つまり、異なるインスタンスにおける同じ関数名の動作は同じではない可能性があります。
プロパティ設定 – Object.defineProperty
まず次のコードを見てください:





コードをコピー


コードは次のとおりです:
//オブジェクトを作成します
var chenhao = Object.create(null);

//プロパティを設定します
Object.defineProperty( chenhao,
'name', { value : 'Chen Hao',
writable: true,
configurable: true,
enumerable: true });

//複数のプロパティを設定します
Object.defineProperties( chenhao,
{
'メール' : { 値: 'haoel@hotmail.com',
書き込み可能: true,
構成可能: true,
列挙可能: true },
'ウェブサイト': { 値: 'http://jb51.net',
書き込み可能: true,
構成可能: true,
列挙可能: true }
}
); 🎜>これらの属性設定が何を意味するかについて話しましょう。
writable: この属性の値を変更できるかどうか。
configurable: この属性の構成を変更できるかどうか。
enumerable: このプロパティを for...in ループで走査できるか、Object.keys で列挙できるかどうか。
value: 属性値。
get()/set(_value): アクセサーを取得および設定します。
Get/Set アクセサー
get/set アクセサーに関しては、get/set を使用して値を置き換えることを意味します (値と一緒に使用することはできません)。例は次のとおりです。




コードをコピーします コードは次のとおりです:var age = 0; Object.defineProperty( chenhao,
' age', {
get: function() {return age 1;},
set: function(value) {age = value;}
enumerable : true,
configurable : true
}
);
chenhao.age = 100; // set
alert(chenhao.age) を呼び出して 101 を呼び出します (ヒット 1 を取得します); >もっと実用的な例を見てみましょう - 既存の属性 (age) を使用して、get と set を通じて新しい属性 (birth_year) を構築します。




Copy code

コードは次のとおりです: Object.defineProperty( chenhao, 'birth_year', { get: function() {
var d = new Date();
var y = d.getFullyear();
return ( y - this.age );
set: function(year); {
var d = new Date();
var y = d.getFullyear();
this.age = y - 年
}
); >
alert (chenhao.birth_year);
chenhao.birth_year = 2000;


これはちょっと面倒ですね。次のように書きますか? :




コードをコピー


コードは次のとおりです:

var chenhao = {
名前: "Chen Hao",
メール: "haoel@hotmail.com",
ウェブサイト: "http://jb51.net", 年齢: 100, getbirth_year() { var d = new Date(); return ( y - this.age ); setbirth_year(year) { var d = new Date(); this.age = y - year;
};
alert(chenhao.birth_year) ;
chenhao.birth_year = 2000;


はい、できます。これらのことは、defineProperty() を通じて実行します。
1) 書き込み可能、​​構成可能、列挙可能などの属性構成を設定します。
2) オブジェクトに属性を動的に追加します。例: 一部の HTML DOM オブジェクト。

オブジェクトの属性構成の表示
オブジェクトのこれらの構成を表示および管理する場合、オブジェクトの属性と構成を出力できる以下のプログラムがあります:





コードをコピー


コードは次のとおりです。
//オブジェクトのプロパティをリストします。
function listProperties(obj)
{
var newLine = "
";
var names = Object.getOwnPropertyNames(obj);
for (var i = 0; i < names.length; i ) {
var prop = names[ i];
document.write(prop newLine);
// getOwnPropertyDescriptor 関数を使用して、オブジェクトのプロパティ設定 (記述子) をリストします。 var descriptor = Object.getOwnPropertyDescriptor(obj, prop); for (var attr in descriptor) { document.write("..." attr ': ' descriptor[attr]); >document.write(newLine); document.write(newLine); listProperties(chenhao); call、apply、bind、そして this
Javascript の this ポインタに関しては、C/Java と非常によく似ています。 例を見てみましょう: (この例は非常に単純なので、これ以上は言いません)





コードをコピー


次のようなコード:
function print(text){
document.write(this.value ' - ' text '
');
}

var a = {value: 10, print : print};
var b = {value: 20, print : print};

print('hello');// this => グローバル、出力 "未定義 - hello"

a.print('a');// this => a、出力 "10 - a"
b.print('b'); // this => b、出力 "20 - b" "

a['print']('a'); // this => a、出力 "10 - a"

もう一度呼び出しと適用を見てみましょう。これら 2 つの関数の違いは、パラメーターの見た目が異なること、もう 1 つは、apply のパフォーマンスがはるかに低いことです。 (パフォーマンスを向上させるために、JSPerf に移動して実行して確認できます)

コードをコピーします コードは次のとおりです
print.call(a, 'a'); // this => a, 出力 "10 - a"
print.call(b, 'b'); => b, 出力 " 20 - b"

print.apply(a, ['a']); // this => a, 出力 "10 - a"
print.apply( b, ['b' ]); // this => b, 出力 "20 - b"

ただし、JavaScript は動的であるため、バインド後は this ポインタが異なる場合があります。次の例のように

コードをコピー コードは次のとおりです。
var p = print .bind(a );
p('a'); // this =>a, 出力 "10 - a"
p.call(b, 'b'); a, 出力 " 10 - b"
p.apply(b, ['b']); // this => a, 出力 "10 - b"

継承とオーバーロード
上記の例を通じて、実際に Object.create() を介して継承することができます。次のコードを参照してください。

コードをコピー コードは次のとおりです。
var Person = Object.create(null) ;

Object.defineProperties
(
人物,
{
'名前' : { 値: 'チェンハオ'},
'メール' : { 値 : ' haoel@hotmail .com'},
'ウェブサイト': { value: 'http://jb51.net'}
}
);

person.sayHello = function () {
var hello = "

こんにちは、私は " this.name "、
"
"私のメールアドレスは " this.email "、
"私のウェブサイトは : " this.website;
document.write(hello "
");
}

var Student = Object.create(person);
Student. no = " 1234567"; //学生 ID
Student.dept = "コンピュータ サイエンス"; //学部

//人物
document.write(Student.name ' ') の属性を使用します。 Student.email ' ' Student.website '
');

// Person メソッドを使用します
Student.sayHello();

// SayHello メソッドをオーバーロードします
Student.sayHello = function (person) {
var hello = "

こんにちは、私は " this.name "、
"私のメールアドレスは次のとおりです: " this.email " , "私のウェブサイトは: " this.website ",
"
"私の生徒番号は: " this.no ",
"
"my部門は: " this.dept;
document.write(hello '
');
}
//再度呼び出します
Student.sayHello();

// 生徒の属性を表示します (no、dept、およびオーバーロードされたsayHello のみ)
document.write('

' Object.keys(Student) '
');上記の例を使用すると、Personal の属性が実際には Student にコピーされていないものの、アクセスできることがわかります。これは、JavaScript がデリゲートを使用してこのメ​​カニズムを実装しているためです。実際、これはプロトタイプであり、person は Student のプロトタイプです。

コードに属性が必要な場合、JavaScript エンジンはまず現在のオブジェクトにこの属性があるかどうかを確認し、そうでない場合は Prototype オブジェクトにこの属性があるかどうかを確認し、見つかるまで処理を続行します。または、Prototype オブジェクトがなくなるまで。

これを証明するには、Object.getPrototypeOf() を使用して次のことを確認します。




コードをコピーコードは次のとおりです。 Student.name = 'aaa';
//Output aaa
document.write('

' Student.name '
//チェン・ハオ
document.write('

' Object.getPrototypeOf(Student).name '

'); 🎜 >
つまり、C の Base::func() のように、子オブジェクトの関数の中で親オブジェクトの関数を呼び出すこともできます。したがって、hello メソッドをオーバーライドするときは、以下に示すように、親クラスのコードを使用できます。

Copy code コードは次のとおりです:
//オーバーロードされた SayHello メソッドの新しいバージョン
Student.sayHello = function (person) {
Object.getPrototypeOf(this).sayHello.call(this) );
var hello = "私の生徒は次のとおりです。
私の担当部署は次のとおりです。
document.write(hello '
;');
}

これは非常に強力です。

構成
上記のものは私たちの要件を満たすことができません。これらのオブジェクトを実際に組み合わせることができることを期待するかもしれません。なぜ組み合わせるのか?それは、OO デザインにおいて最も重要なことであることを誰もが知っているからです。ただし、これは Javascript をあまり適切にサポートしていないため、それでも実行できます。

まず、Composition 関数を定義する必要があります (target はそれに作用するオブジェクト、source はソース オブジェクトです)。次のコードは、単に属性を取り出すだけです。ソースを 1 つずつ定義し、ターゲットとして定義します。

コードをコピー コードは次のとおりです。
関数 構成(ターゲット、ソース)
{
var desc = Object.getOwnPropertyDescriptor;
var prop = Object.getOwnPropertyNames;
var def_prop = Object.defineProperty(
function( key) {
def_prop(target, key, desc(source, key))
}
)
return target;
}


この関数では、ここでプレイできます:



コードをコピー コードは次のとおりです: //アーティスト
var Artist = Object.create(null);
Artist.sing = function() {
return this.name ' 歌い始めます...'
}
Artist.paint = function( ) {
return this.name ' ペイントを開始します...';

//Sportsman
var Sporter = Object.create(null); run = function() {
return this.name ' が実行を開始します...';
}
Sporter.swim = function() {
return this.name ' が水泳を開始します...' ;
}

Composition(人、アーティスト)
document.write(person.sing() '
');
document.write() '
');

Composition(人, Sporter)
document.write(person.run() '
'); swim( ) '
');

//実際に見てみましょう? (出力:sayHello、sing、paint、swim、run)
document.write('

' Object.keys(person) '
');


プロトタイプと継承
最初にプロトタイプについて話しましょう。まず次のルーチンを見てみましょう。このルーチンは C 言語の関数ポインタとよく似ています。



コードをコピー
コードは次のとおりです。 var plus = function(x,y){ document.write(x ' y ' = ' (x y) '
');
var マイナス = function(x,y);
document.write(x ' - ' y ' = ' (x-y) '
');
return x - y>};

var 操作 = {
' ': プラス、
'-': マイナス
};

var計算 = function(x, y, 演算){
return 演算[演算](x, y );
};

calculate(12, 4, ' ');


これらを入れます。 カプセル化するには、プロトタイプを使用する必要があります。以下の例を見てください:





コードをコピーします

コードは次のとおりです:

var Cal = function(x, y){
this.x = x; this.y = y; } Cal.prototype.operations = { ' ': 関数(x, y) { return x y;}, '-': function(x, y) { return x-y;}
};

Cal.prototype.calculate = function(operation); {
return this.operations[operation](this.x, this.y);

var c = new Cal(4, 5); .calculate(' ' );
c.calculate('-');
プロトタイプの使い方です。プロトタイプはJavaScript言語において最も重要な内容です。インターネット上にはこの件に関する記事が多すぎます。端的に言えば、プロトタイプはオブジェクトを拡張するもので、新しいインスタンスを作成するのではなく、既存のインスタンスを「コピー」することで新しいインスタンスを返すのが特徴です。コピーされたインスタンスは「プロトタイプ」と呼ばれるもので、このプロトタイプはカスタマイズ可能です (もちろん、ここには実際のコピーはなく、委任されているだけです)。上の例では、インスタンス Cal を拡張して、操作属性と計算メソッドを持たせました。

このようにして、この機能を通じて継承を実装できます。最初の Person を思い出してください。次の例は、People を継承する Student を作成する例です。

コードをコピー コードは次のとおりです:
function person(name, email, website) {
this.name = 名前;
this.website = ウェブサイト
};

person.prototype.sayHello = function() 🎜>var hello = "こんにちは、私は " this.name ",
"
"私のメールアドレスは: " this.email ",
"私のウェブサイトは: " .website;
return hello;
};

関数 Student(名前、電子メール、ウェブサイト、いいえ、部門){
var proto = Object.getPrototypeOf; .prototype) .constructor.call(this, name, email, website);
this.no = no;
this.dept = dept;

// プロトタイプを継承する🎜>Student .prototype = Object.create(person.prototype);

//コンストラクターをリセット
Student.prototype.constructor = Student;

//オーバーロード SayHello()
Student.prototype.sayHello = function(){
var proto = Object.getPrototypeOf;
var hello = proto(Student.prototype).sayHello.call(this) '
'; hello = "私の生徒は「いいえ」です、
「こんにちは。」

var;私 = 新入生(
"Chen Hao",
"haoel@hotmail.com",
"http://jb51.net",
"12345678",
"コンピューター サイエンス" "
);
document.write(me.sayHello());


互換性
上記のコードはすべてのブラウザーで動作するとは限りません。 ECMAScript 5 の仕様については、ECMAScript 5 のブラウザ互換性リストについては、こちらの「ES5 ブラウザ互換性リスト」をご覧ください。

この記事のすべてのコードは、最新バージョンの Chrome でテストされています。

ES5 と互換性がないブラウザで使用できる関数の一部を次に示します。
Object.create() 関数




コードをコピー


コードは次のとおりです。
function clone(proto) { function Dummy() { } Dummy.prototype = proto; Dummy .prototype.constructor = Dummy; return new Dummy(); //
}

var me = clone(person) );


defineProperty() 関数




コードをコピー

コードは次のとおりです。
function defineProperty( target, key, descriptor) { ターゲットを返す
}


keys() function




コードをコピー

コードは次のとおりです。

function key(object) { var result, key
result = []; for (オブジェクト内のキー){ if (object.hasOwnProperty(key)) result.push(key) } 結果を返す; }

Object.getPrototypeOf() 関数




コードをコピー



function proto (object) {
return !object? null : '__proto__' in object? object.__proto__ : /* 公開されていませんか? constructor.prototype } バインド関数



コードをコピー

コードは次のとおりです。

var slide = [].slice
function binding(fn,bound_this) { varbound_args bound_args = slide.call(arguments, 2) return function() { var args args =bound_args.concat(slice.call(arguments)) return fn.apply(bound_this, args) } }

参考
W3CSchool
MDN (Mozilla Developer Network)
MSDN (Microsoft Software Development Network)
JavaScript OOP について。
声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。