জাভাস্ক্রিপ্টে ক্লাস এবং ইনস্ট্যান্স বাস্তবায়নের জন্য দুটি মডেল রয়েছে: প্রোটোটাইপিং উপায় এবং ক্লোজার ওয়ে। উভয়েরই সুবিধাগুলি এবং ত্রুটি রয়েছে এবং প্রচুর পরিমাণে বর্ধিত বৈচিত্র রয়েছে। অনেক প্রোগ্রামার এবং গ্রন্থাগারগুলির ভাষার কিছু কুরুচিপূর্ণ অংশের উপর কাগজপত্রের জন্য বিভিন্ন পদ্ধতি এবং শ্রেণি-পরিচালনার ইউটিলিটি ফাংশন রয়েছে।
ফলস্বরূপ যে মিশ্র সংস্থায় আপনার মেটাচ্লাসের একটি মিশমাস থাকবে, সকলেই কিছুটা আলাদাভাবে আচরণ করবে। সবচেয়ে খারাপ কী, বেশিরভাগ জাভাস্ক্রিপ্ট টিউটোরিয়াল উপাদানটি ভয়ানক এবং সমস্ত ঘাঁটিগুলি coverাকতে একরকম মধ্যে আপস করে যা আপনাকে খুব বিভ্রান্ত করে leaving (সম্ভবত লেখকও বিভ্রান্ত। জাভাস্ক্রিপ্টের অবজেক্টের মডেল বেশিরভাগ প্রোগ্রামিং ভাষার সাথে খুব আলাদা এবং অনেক জায়গায় সোজা-আপ খারাপভাবে নকশা করা হয়েছে))
প্রোটোটাইপ উপায় দিয়ে শুরু করা যাক । এটি আপনি পেতে পারেন এমন সর্বাধিক জাভাস্ক্রিপ্ট-নেটিভ: এখানে সর্বনিম্ন ওভারহেড কোড রয়েছে এবং উদাহরণস্বরূপ এই ধরণের অবজেক্টের উদাহরণ দিয়ে কাজ করবে।
function Shape(x, y) {
this.x= x;
this.y= y;
}
এই কন্সট্রাক্টর ফাংশনটির অনুসন্ধানে new Shapeতাদের লিখে লিখে তৈরি করা مثالগুলিতে আমরা পদ্ধতিগুলি যুক্ত করতে পারি prototype:
Shape.prototype.toString= function() {
return 'Shape at '+this.x+', '+this.y;
};
এখন এটি সাবক্লাস করার জন্য, যতটা আপনি জাভাস্ক্রিপ্ট সাবক্লাসিং করে কল করতে পারেন। আমরা সেই অদ্ভুত যাদু prototypeসম্পত্তিটি পুরোপুরি প্রতিস্থাপন করে তা করি :
function Circle(x, y, r) {
Shape.call(this, x, y); // invoke the base class's constructor function to take co-ords
this.r= r;
}
Circle.prototype= new Shape();
এটিতে পদ্ধতি যুক্ত করার আগে:
Circle.prototype.toString= function() {
return 'Circular '+Shape.prototype.toString.call(this)+' with radius '+this.r;
}
এই উদাহরণটি কাজ করবে এবং আপনি অনেক টিউটোরিয়ালে এটির মতো কোড দেখতে পাবেন। কিন্তু মানুষ, এটি new Shape()কুৎসিত: আমরা প্রকৃত শেপ তৈরি না করা সত্ত্বেও বেস ক্লাসটি ইনস্ট্যান্ট করছি। এটা এই সহজ ক্ষেত্রে কাজ ঘটবে কারণ জাভাস্ক্রিপ্ট তাই পঙ্কিল: এটি পারবেন শূন্য যুক্তি পাস করা যে ক্ষেত্রে xএবং yপরিণত undefinedএবং প্রোটোটাইপ এর হস্তান্তর করা হয়েছে this.xএবং this.y। যদি কনস্ট্রাক্টর ফাংশন আরও জটিল কিছু করে থাকে তবে এটি তার মুখের উপর ফ্ল্যাট পড়বে।
সুতরাং আমাদের যা করা দরকার তা হল একটি প্রোটোটাইপ অবজেক্ট তৈরির একটি উপায় সন্ধান করা যা বেস ক্লাসের কনস্ট্রাক্টর ফাংশনটিকে কল না করে ক্লাস পর্যায়ে আমাদের প্রয়োজনীয় পদ্ধতি এবং অন্যান্য সদস্য ধারণ করে want এটি করতে আমাদের হেল্পার কোড লেখা শুরু করতে হবে। এটি আমার জানা সবচেয়ে সহজ পন্থা:
function subclassOf(base) {
_subclassOf.prototype= base.prototype;
return new _subclassOf();
}
function _subclassOf() {};
এটি বেস শ্রেণীর সদস্যদের প্রোটোটাইপে একটি নতুন কনস্ট্রাক্টর ফাংশনে স্থানান্তর করে যা কিছুই করে না, তারপরে সেই কনস্ট্রাক্টর ব্যবহার করে। এখন আমরা সহজভাবে লিখতে পারি:
function Circle(x, y, r) {
Shape.call(this, x, y);
this.r= r;
}
Circle.prototype= subclassOf(Shape);
পরিবর্তে new Shape()অন্যায়ের। আমাদের কাছে এখন নির্মিত ক্লাসগুলিতে আদিমতার একটি গ্রহণযোগ্য সেট রয়েছে।
এই মডেলটির অধীনে আমরা কয়েকটি পরিমার্জন এবং এক্সটেনশন বিবেচনা করতে পারি। উদাহরণস্বরূপ এখানে একটি সিনট্যাক্টিকাল-চিনির সংস্করণ রয়েছে:
Function.prototype.subclass= function(base) {
var c= Function.prototype.subclass.nonconstructor;
c.prototype= base.prototype;
this.prototype= new c();
};
Function.prototype.subclass.nonconstructor= function() {};
...
function Circle(x, y, r) {
Shape.call(this, x, y);
this.r= r;
}
Circle.subclass(Shape);
উভয় সংস্করণেই এমন একটি অপূর্ণতা রয়েছে যা নির্মাণকারী ফাংশন উত্তরাধিকার সূত্রে প্রাপ্ত হতে পারে না, কারণ এটি অনেক ভাষায়। সুতরাং এমনকি যদি আপনার সাবক্লাসটি নির্মাণ প্রক্রিয়াতে কিছু না জুড়ে, তবে অবশ্যই বেসটি যা চায় তত যুক্তি দিয়ে বেস কনস্ট্রাক্টরকে কল করতে হবে। এটি ব্যবহার করে সামান্য স্বয়ংক্রিয় করা যেতে পারে apply, তবে তবুও আপনাকে লিখতে হবে:
function Point() {
Shape.apply(this, arguments);
}
Point.subclass(Shape);
সুতরাং একটি সাধারণ বর্ধিতাংশ হ'ল আরম্ভের সামগ্রীটি নির্মাণকারীর পরিবর্তে তার নিজের ফাংশনে ছড়িয়ে দেওয়া। এই ফাংশনটি তখন বেস থেকে উত্তম উত্তম হতে পারে:
function Shape() { this._init.apply(this, arguments); }
Shape.prototype._init= function(x, y) {
this.x= x;
this.y= y;
};
function Point() { this._init.apply(this, arguments); }
Point.subclass(Shape);
// no need to write new initialiser for Point!
এখন আমরা প্রতিটি ক্লাসের জন্য একই কনস্ট্রাক্টর ফাংশন বয়লারপ্লেট পেয়েছি। হতে পারে আমরা এটিকে তার নিজস্ব সহায়ক ফাংশনে স্থানান্তর করতে পারি সুতরাং এটি টাইপ করতে হবে না, উদাহরণস্বরূপ পরিবর্তে Function.prototype.subclass, এটি ঘুরিয়ে দেওয়া এবং বেস শ্রেণির ফাংশনটিকে উপক্লাসটি থুতু দেওয়া:
Function.prototype.makeSubclass= function() {
function Class() {
if ('_init' in this)
this._init.apply(this, arguments);
}
Function.prototype.makeSubclass.nonconstructor.prototype= this.prototype;
Class.prototype= new Function.prototype.makeSubclass.nonconstructor();
return Class;
};
Function.prototype.makeSubclass.nonconstructor= function() {};
...
Shape= Object.makeSubclass();
Shape.prototype._init= function(x, y) {
this.x= x;
this.y= y;
};
Point= Shape.makeSubclass();
Circle= Shape.makeSubclass();
Circle.prototype._init= function(x, y, r) {
Shape.prototype._init.call(this, x, y);
this.r= r;
};
... যা অন্য ভাষার মতো আরও কিছুটা দেখতে শুরু করেছে, যদিও সামান্য ক্লামিয়ার সিনট্যাক্স সহ। আপনি চাইলে কয়েকটি অতিরিক্ত বৈশিষ্ট্যগুলিতে ছিটিয়ে দিতে পারেন। হতে পারে আপনি makeSubclassকোনও শ্রেণীর নাম নিতে এবং মনে রাখতে এবং toStringএটি ব্যবহার করে একটি ডিফল্ট সরবরাহ করতে চান। সম্ভবত আপনি নির্মাতাকে দুর্ঘটনাক্রমে newঅপারেটর ছাড়া কল করা হলে এটি সনাক্ত করতে চান (যা অন্যথায় প্রায়শই খুব বিরক্তিকর ডিবাগ হওয়ার কারণ হয়ে থাকে):
Function.prototype.makeSubclass= function() {
function Class() {
if (!(this instanceof Class))
throw('Constructor called without "new"');
...
সম্ভবত আপনি সমস্ত নতুন সদস্যদের মধ্যে পাস করতে চান এবং makeSubclassএগুলি প্রোটোটাইপে যুক্ত করতে চান, Class.prototype...যাতে আপনাকে যথেষ্ট পরিমাণে লিখতে হয় । অনেকগুলি ক্লাস সিস্টেম এটি করে, যেমন:
Circle= Shape.makeSubclass({
_init: function(x, y, z) {
Shape.prototype._init.call(this, x, y);
this.r= r;
},
...
});
এমন কোনও সম্ভাব্য বৈশিষ্ট্য রয়েছে যা আপনি কোনও অবজেক্ট সিস্টেমে কাঙ্ক্ষিত বিবেচনা করতে পারেন এবং কেউই কোনও নির্দিষ্ট সূত্রে সত্যই সম্মত হয় না।
অবসান পথ , তারপর। এটি জাভাস্ক্রিপ্টের প্রোটোটাইপ-ভিত্তিক উত্তরাধিকারের সমস্যাগুলি এড়িয়ে চলে, উত্তরাধিকার একেবারেই ব্যবহার না করে। পরিবর্তে:
function Shape(x, y) {
var that= this;
this.x= x;
this.y= y;
this.toString= function() {
return 'Shape at '+that.x+', '+that.y;
};
}
function Circle(x, y, r) {
var that= this;
Shape.call(this, x, y);
this.r= r;
var _baseToString= this.toString;
this.toString= function() {
return 'Circular '+_baseToString(that)+' with radius '+that.r;
};
};
var mycircle= new Circle();
এখন প্রতিটি একক উদাহরণের Shapeনিজস্ব কপি থাকবে toStringপদ্ধতিটির (এবং কোনও অন্যান্য পদ্ধতি বা আমরা যুক্ত অন্যান্য শ্রেণীর সদস্যদের)।
প্রতিটি শ্রেণীর সদস্যের নিজস্ব অনুলিপি থাকা প্রতিটি ঘটনার সম্পর্কে খারাপ বিষয় হ'ল এটি কম দক্ষ। যদি আপনি বিপুল সংখ্যক উপ-শ্রেণীবদ্ধ উদাহরণগুলি নিয়ে কাজ করে থাকেন তবে প্রোটোটাইপিকাল উত্তরাধিকার আপনাকে আরও ভালভাবে পরিবেশন করতে পারে। বেস ক্লাসের একটি পদ্ধতি কল করা কিছুটা বিরক্তিকর যেমনটি আপনি দেখতে পাচ্ছেন: আমাদের মনে রাখতে হবে সাবক্লাস কনস্ট্রাক্টর ওভাররোট করার আগে পদ্ধতিটি কী ছিল বা এটি হারিয়ে যায় lost
[এছাড়াও এখানে কোনও উত্তরাধিকার instanceofনা থাকায় অপারেটর কাজ করবে না; আপনার যদি প্রয়োজন হয় তবে আপনাকে ক্লাস-স্নিফিংয়ের জন্য নিজস্ব ব্যবস্থা সরবরাহ করতে হবে। যদিও আপনি পারে প্রোটোটাইপ উত্তরাধিকার হিসেবে একই ভাবে প্রোটোটাইপ বস্তু বেহালা, এটি একটি বিট চতুর এবং সত্যিই মূল্য এটা ঠিক করতে না instanceofকাজ।]
প্রতিটি উদাহরণের নিজস্ব পদ্ধতি থাকা সম্পর্কে ভাল বিষয় হ'ল পদ্ধতিটি তারপরে নির্দিষ্ট নির্দিষ্ট উদাহরণের সাথে আবদ্ধ হতে পারে। এটি জাভাস্ক্রিপ্টের thisপদ্ধতি কলগুলিতে বাইন্ডিংয়ের অদ্ভুত পদ্ধতির কারণে দরকারী , যার ফলশ্রুতি রয়েছে যে আপনি যদি তার মালিকের কাছ থেকে কোনও পদ্ধতি আলাদা করে রাখেন:
var ts= mycircle.toString;
alert(ts());
তবে thisপদ্ধতির অভ্যন্তরে যেমন প্রত্যাশা করা হয়েছে তেমন বৃত্ত উদাহরণ হবে না (এটি আসলে বিশ্বব্যাপী windowবস্তু হয়ে উঠবে , যার ফলে ব্যাপক ডিবাগিংয়ের জন্য হ'ল সমস্যা সৃষ্টি হবে)। বাস্তবে এটি বিশেষভাবে যখন একটি পদ্ধতি গ্রহণ করা হয় এবং একটি নির্ধারিত ঘটবে setTimeout, onclickবা EventListenerসাধারণভাবে।
প্রোটোটাইপ উপায়ে, আপনাকে এই জাতীয় প্রতিটি কার্যক্রমে একটি ক্লোজার অন্তর্ভুক্ত করতে হবে:
setTimeout(function() {
mycircle.move(1, 1);
}, 1000);
অথবা, ভবিষ্যতে (বা এখন আপনি যদি ফাংশন.প্রোটোটাইপ হ্যাক করেন) আপনি এটি দিয়েও করতে পারেন function.bind():
setTimeout(mycircle.move.bind(mycircle, 1, 1), 1000);
যদি আপনার দৃষ্টান্তটি বন্ধের উপায়ে সম্পন্ন হয়, তবে বন্ধনটি দৃষ্টান্ত পরিবর্তনশীল (সাধারণত বলা হয় thatবা selfব্যক্তিগতভাবে আমি selfজাভাস্ক্রিপ্টের অন্যরকম অর্থ পেয়েছি যেহেতু ব্যক্তিগতভাবে আমি পরবর্তীটির বিরুদ্ধে পরামর্শ দেব) দ্বারা বন্ধ করে ফ্রি হয়ে যায় । 1, 1উপরের স্নিপেটে আপনি নিখরচায় আর্গুমেন্টগুলি পাবেন না , সুতরাং আপনার এখনও অন্য বন্ধ বা একটি bind()প্রয়োজন হয় যদি আপনার এটি করার প্রয়োজন হয়।
ক্লোজার পদ্ধতিতেও প্রচুর বৈকল্পিক রয়েছে। আপনি thisসম্পূর্ণরূপে বাদ দিতে পছন্দ করতে পারেন , একটি নতুন তৈরি thatকরে newঅপারেটর ব্যবহারের পরিবর্তে এটি ফিরিয়ে দিতে :
function Shape(x, y) {
var that= {};
that.x= x;
that.y= y;
that.toString= function() {
return 'Shape at '+that.x+', '+that.y;
};
return that;
}
function Circle(x, y, r) {
var that= Shape(x, y);
that.r= r;
var _baseToString= that.toString;
that.toString= function() {
return 'Circular '+_baseToString(that)+' with radius '+r;
};
return that;
};
var mycircle= Circle(); // you can include `new` if you want but it won't do anything
কোন উপায় "যথাযথ"? উভয়। কোনটি "সেরা"? এটি আপনার পরিস্থিতির উপর নির্ভর করে। এফডব্লিউআইডাব্লু যখন আমি দৃ strongly়ভাবে ওও স্টাফ করছি এবং রিয়েল থ্রোওয়ে পৃষ্ঠের প্রভাবগুলির জন্য বন্ধ করে দিচ্ছি তখন সত্যিকারের জাভাস্ক্রিপ্ট উত্তরাধিকারের জন্য প্রোটোটাইপিংয়ের দিকে ঝুঁকছি।
তবে উভয় উপায়ই বেশিরভাগ প্রোগ্রামারদের কাছে বেশ স্ব-স্বজ্ঞাত। উভয়েরই অনেকগুলি সম্ভাব্য অগোছালো বৈচিত্র রয়েছে। আপনি যদি অন্য ব্যক্তির কোড / লাইব্রেরি ব্যবহার করেন তবে আপনি উভয়ই (পাশাপাশি অনেকগুলি মধ্যবর্তী এবং সাধারণত ভাঙা স্কিমগুলি) পূরণ করতে পারেন। সাধারণভাবে গৃহীত উত্তর নেই। জাভাস্ক্রিপ্ট অবজেক্টের দুর্দান্ত পৃথিবীতে আপনাকে স্বাগতম।
[কেন জাভাস্ক্রিপ্টটি আমার প্রিয় প্রোগ্রামিং ভাষা নয়?] এর অংশ হয়েছে]