ホームページ >ウェブフロントエンド >jsチュートリアル >JavaScript オブジェクト指向のチュートリアル

JavaScript オブジェクト指向のチュートリアル

黄舟
黄舟オリジナル
2016-12-20 15:23:47781ブラウズ

JavaScript は C に似た言語です。そのオブジェクト指向機能は C++/Java と比べると奇妙ですが、確かに非常に強力です。ここ 2 日間、元同僚から Javascript のオブジェクト指向プログラミングについて質問されてきたので、彼に読んでもらうための記事を書きたいと思います。この記事では主に Javascript のオブジェクト指向プログラミングについて全体的な観点から説明したいと思います。 。 Cool Shell の記事からの転載ですが、非常によく書かれています...

なお、この記事は主に ECMAScript 5 に基づいており、新しいテクノロジーを紹介することを目的としています。互換性については最後のセクションを参照してください。

予備調査

Javascript における変数の定義は基本的に次のとおりであることがわかっています:

var name = 'Chen Hao';;

var email = 'haoel(@)hotmail.com';

var website = 'http:///coolshell.cn';

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

var chenhao = {

name :'Chen Hao',

email : 'haoel( @)hotmail.com',

website: 'http://coolshell.cn'

}

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

//メンバーとして

chenhao.name;

chenhao. email;

chenhao. website;

//ハッシュマップの形式で

chenhao["name"];

chenhao["email"];

chenhao["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 =sayHello;

chenhao.Hello();

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

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

//関数をクラスとして使用していることがわかります。

var person = function(name, email, website){

this.name = 名前;

this.email = email;

this.website = website;

this.sayHello = function(){

var hello = "こんにちは、私は "+ this.name + ", n" +

"私のメールアドレスは: " + this.email + ", n" +

"私のウェブサイトは: " + this.website ;

alert(hello);

};

};

var chenhao = 新しい人("Chen Hao", "haoel@hotmail.com",

"http://coolshell.cn");

chenhao.sayHello();

ちなみに、オブジェクトの属性を削除するのは非常に簡単です:

delete chenhao['email']

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

◆ Javascript のデータとメンバーのカプセル化は非常に簡単です。完全にオブジェクト操作であるクラスはありません。純粋に動的です!

◆ Javascript 関数の this ポインターは重要です。そうでない場合は、ローカル変数またはローカル関数です。

◆ Javascriptオブジェクトのメンバー関数は使用時に一時的に宣言し、グローバル関数を直接代入することができます。

◆ Javascript のメンバー関数はインスタンス上で変更できます。つまり、異なるインスタンスにおける同じ関数名の動作は同じではない可能性があります。

プロパティ設定 – Object.defineProperty

まず次のコードを見てください:

//オブジェクトを作成します

var chenhao = Object.create(null);

//プロパティを設定します

Object.defineProperty( chenhao ,

'name', { value: 'チェンハオ',

writable: true,

configurable: true,

enumerable: true });

//複数のプロパティを設定します

Object.defineProperties(chenhao,

{

'email' : { value: 'haoel@hotmail.com',

writable: true,

configurable: true,

enumerable: true },

'website': { value: 'http : //coolshell.cn',

writable: true,

configurable: true,

enumerable: true }

}

);

これらの属性設定が何を意味するかについて話しましょう。

writable: この属性の値を変更できるかどうか。

configurable: この属性の構成を変更できるかどうか。

enumerable: このプロパティを for...in ループで走査できるか、Object.keys で列挙できるかどうか。

value: 属性値。

get()/set(_value): アクセサーを取得および設定します。

Get/Set アクセサー

get/set アクセサーについては、get/set を使用して value を置き換えることを意味します (value では使用できません)。 例は次のとおりです:

var age = 0;

Object。 .defineProperty( chenhao,

'年齢', {

get: function() {return age+1;},

set: function(value) {age = value;}

enumerable : true,

configurable : true

}

);

chenhao.age = 100; // set

alert(chenhao.age) を呼び出します // get を呼び出して 101 を出力します (get で +1);

別の例を見てみましょうupdate 実際の例として - 既存の属性 (age) を使用して、get と set を通じて新しい属性 (birth_year) を構築します:

Object.defineProperty(chenhao,

'birth_year',

{

get: function() {

var d = new Date();

var y = d.getFull Year();

return ( y – this.age );

},

set: function(year) {

var d = new Date();

var y = d.getFull Year();

this.age = y – year;

}

}

);

alert(chenhao.birth_year);

chenhao.birth_year = 2000;

alert(chenhao.age);

これを行うのは少し面倒ですが、次のように書いてみてはいかがでしょうか:

var chenhao = {

名前: "Chen Hao"、

メール: "haoel@hotmail.com"、

ウェブサイト: "http://coolshell.cn"、

年齢: 100、

誕生年() {

var d = new Date();

var y = d.getFull Year();

return ( y – this.age );

},

set Birth_year(year) {

var d = 新しい日付( );

var y = d.getFull Year();

this.age = y – year;

}

};

alert(chenhao.birth_year);

chenhao.birth_year = 2000;

alert (chenhao.age);

はい、実際にこれを実行できますが、defineProperty() を使用すると次のことができます:

1) 書き込み可能、​​構成可能、列挙可能などのプロパティ構成を設定します。

2) オブジェクトに属性を動的に追加します。例: 一部の HTML DOM オブジェクト。

オブジェクトのプロパティ設定を表示する

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

// オブジェクトのプロパティを一覧表示します

function listProperties( obj)

{

var newLine = ”
”;

var names = Object.getOwnPropertyNames(obj);

for (var i = 0; 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とC++のthisポインタについて/ Java は非常によく似ています。 例を見てみましょう: (この例は非常に単純なので、これ以上は言いません)

function print(text){

document.write(this.value + ' – ' + text+ '
');

}

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

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

print('hello');// this =>出力 " unknown – hello"

a.print('a');// this => a, 出力 "10 – a"

b.print('b'); // this => b, output “ 20 – b”

a['print']('a'); // this => a、output “10 – a”

これら 2 つの関数の違いをもう一度見てみましょう。パラメータの外観が異なります。もう 1 つは、適用のパフォーマンスが大幅に低下することです。 (パフォーマンスについては、JSPerf にアクセスして確認してください)

print.call(a, 'a') // this => a, 出力「10 – a」

print.call(b, 'b '); // this => b、出力「20 – b」

print.apply(a, ['a']); // this => a、出力「10 – a」

print. b, ['b']); // this => b, 出力 "20 – b"

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

var p = print.bind(a);

p('a'); // this => a, 出力「10 – a」

p.call(b, 'b' ); // this => a、出力「10 – b」

p.apply(b, ['b']) // this => a、出力「10 – b」

;

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

var Person = Object.create(null);

Object.defineProperties

(
person,
{
'name' : { value: 'Chen Hao'},
'email' : { value : 'haoel@hotmail .com'},
'website': { value: 'http://coolshell.cn'}
}
);

person.sayHello = function () {

var hello = “

こんにちは。 am "+ this.name + ",
" +
"私のメールアドレスは: " + this.email + ",
" 私のウェブサイトは: " + this.website;
ドキュメントです。 write(hello + “
”);
}

var Student = Object.create(person);

Student.no = “1234567″ //学生番号

Student.dept = “コンピュータサイエンス”; /Department

//Person の属性を使用する

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. ;br>” +
「私の担当者は: 」 + this. dept;
document.write(hello + '
');
}
//もう一度電話してください
Student.sayHello();

// Student のプロパティを表示します (no、dept、オーバーロードされたsayHello のみ)
document.write('

' + Object.keys(Student) + '
');

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

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

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

Student.name = 'aaa';
//Output aaa
document.write('

' + Student.name + '< ;/p>');
//出力 Chen Hao
document.write('

' +Object.getPrototypeOf(Student).name + '

');

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

//オーバーロードされた SayHello メソッドの新しいバージョン
Student.sayHello = function (person) {
Object.getPrototypeOf(this ).sayHello .call(this);
var hello = “私の生徒の番号は: ” + this. no + “,
” +
“私の部門は: ” + this. hello + '
');
}

これは非常に強力です。

構成

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

まず、コンポジション関数を定義する必要があります: (ターゲットはそれに作用するオブジェクト、ソースはソースオブジェクトです)。これは、ソース内の属性を 1 つずつ取り出して定義するだけです。それらをターゲットにします。 Fulling 構成 (ターゲット、ソース) {

var desc = object.get.getownpropertydescriptor; opt = object.defineProperty; Foreach (

function(key) {

def_prop(target, key, desc(source, key))

}

)

return target;

}

この関数を使用すると、ここで再生できます:

//Artist

var Artist = Object.create(null);

Artist .sing = function() {

return this.name + ' 歌い始めます…';

}

Artist.paint = function() {

return this.name + ' 絵を描き始めます…';

}

//アスリート

var Sporter = Object.create(null);

Sporter.run = function() {
return this.name + ' 実行開始…';
}
Sporter.swim = function() {
return this.name + ' 開始水泳…';
}

Composition(人, アーティスト);

document.write(person.sing() + '
' );

document.write(person.paint() + '
');

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

//実際に何があるか見てみましょう? (出力:sayHello,sing,paint,swim,run)
document.write('

' + Object.keys(person) + '
');

プロトタイプと継承

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

var plus = function(x,y){
document.write( x + ' + ' + y + ' = ' + (x+y) + '
');
return x + y;

};


varminus = function(x,y){

document.write(x + ' – ' + y + ' = ' + (x-y) + '
');

return x – y;

};

var 演算 = {

'+': プラス,
'-': マイナス
};

var 計算 = function(x, y, 演算){

戻り演算[演算](x, y);
};

calculate(12, 4, '+');

calculate(24, 3, '-');


それでは、これらをプロトタイプを使用してカプセル化する必要があるでしょうか。以下の例を見てください:

var Cal = function(x, y){

this.x = x;

this.y = y;

}

Cal.prototype.operations = {

'+': function(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);

c.calculate('+');

c.calculate('-');

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

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

function person(名前, メール, ウェブサイト){
this.name = 名前;
this.email = メール;
this.website = ウェブサイト;
};

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

function Student(name, email, website, no, dept){

var proto = Object.getPrototypeOf;
proto(Student.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) + '
';
こんにちは += 「私の生徒は: 」 + これはいいえ + ",
" +
「私の部門は: 」 + これを返します ;
} ;

var me = new Student(

"gtfx",

"gtfx0209@gmail.com",
"http://dyygtfx.com",
"12345678″,
"Computer Science"
);
ドキュメント。 write(me.sayHello());

互換性

上記のコードは ECMAScript 5 の仕様に従っているため、すべてのブラウザで実行できるわけではありません。 ECMAScript 5 について ブラウザの互換性リストについては、「ES5」を参照してください。ブラウザ互換性リスト」を参照してください。

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

ES5非対応ブラウザで利用できる関数は以下のとおりです:

Object.create() function

function clone(proto) {

function Dummy() { }

Dummy.prototype = proto ;

Dummy.prototype.constructor = Dummy;

return new Dummy(); // Object.create(person);

}

var me = clone(person);

defineProperty() 関数

function defineProperty(target, key, descriptor) {

if (descriptor.value){

target[key] = descriptor.value;

}else {

descriptor.get && target.__defineGetter__(key, descriptor. get);

descriptor.set && target.__defineSetter__(key, descriptor.set);

}

return target

}

keys() function

function key(object) { var result, key

result = [];

for (オブジェクト内のキー){

if (object.hasOwnProperty(key)) result.push(key)

}

return result;

}

Object.getPrototypeOf() 関数

function proto(object) {

return !object? null

: '__proto__' in object?__proto__

: /* object.constructor.prototype

}

bind function

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) }

}


上記は JavaScript オブジェクト指向チュートリアルの内容です。さらに関連する内容については、PHP に注目してください。中国語のウェブサイト (www.php.cn)!

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