প্রোটোটাইপ-সংজ্ঞায়িত ফাংশন থেকে ব্যক্তিগত সদস্য ভেরিয়েবল অ্যাক্সেস করা


187

প্রোটোটাইপ-সংজ্ঞায়িত পদ্ধতিতে উপলব্ধ "ব্যক্তিগত" ভেরিয়েবলগুলি (কনস্ট্রাক্টারে সংজ্ঞায়িত) কী কী আছে?

TestClass = function(){
    var privateField = "hello";
    this.nonProtoHello = function(){alert(privateField)};
};
TestClass.prototype.prototypeHello = function(){alert(privateField)};

এইটা কাজ করে:

t.nonProtoHello()

তবে এটি হয় না:

t.prototypeHello()

আমি কনস্ট্রাক্টরের ভিতরে আমার পদ্ধতিগুলি সংজ্ঞায়িত করতে অভ্যস্ত, তবে বেশ কয়েকটি কারণে এটি থেকে সরে যাচ্ছি।



14
@ ক্যাম্পভার, এটি বাদ দিয়ে ২ বছর আগে জিজ্ঞাসা করা হয়েছিল ....
পেসারিয়ার

উত্তর:


191

না, এটি করার কোনও উপায় নেই। এটি মূলত বিপরীতে স্কোপিং হবে।

কনস্ট্রাক্টরের অভ্যন্তরে সংজ্ঞায়িত পদ্ধতিগুলির ব্যক্তিগত ভেরিয়েবলগুলিতে অ্যাক্সেস রয়েছে কারণ সমস্ত ফাংশনগুলিতে সেগুলি সংজ্ঞায়িত করার সুযোগটিতে অ্যাক্সেস রয়েছে।

প্রোটোটাইপে সংজ্ঞায়িত পদ্ধতিগুলি কনস্ট্রাক্টরের স্কোপের মধ্যে সংজ্ঞায়িত করা হয় না এবং কনস্ট্রাক্টরের স্থানীয় ভেরিয়েবলগুলি অ্যাক্সেস করতে পারে না।

আপনি এখনও বেসরকারী ভেরিয়েবল থাকতে পারে, কিন্তু যদি আপনি প্রোটোটাইপ সংজ্ঞাসমূহ পদ্ধতি চান সেগুলির অ্যাক্সেস দেওয়া জন্য, আপনাকে উপর getters এবং setters সংজ্ঞায়িত করা উচিত thisবস্তু, যার প্রোটোটাইপ পদ্ধতি (অন্য সব কিছুর সহ) হবে এক্সেস আছে। উদাহরণ স্বরূপ:

function Person(name, secret) {
    // public
    this.name = name;

    // private
    var secret = secret;

    // public methods have access to private members
    this.setSecret = function(s) {
        secret = s;
    }

    this.getSecret = function() {
        return secret;
    }
}

// Must use getters/setters 
Person.prototype.spillSecret = function() { alert(this.getSecret()); };

14
"বিপরীতে স্কুপিং" "বন্ধু" কীওয়ার্ড সহ একটি সি ++ বৈশিষ্ট্য। মূলত যে কোনও ফাংশনটির প্রোটোটাইপটিকে বন্ধু হিসাবে সংজ্ঞায়িত করা উচিত। দুঃখজনকভাবে এই ধারণা সি ++ এবং জাতীয় হল :(
TWiStErRob

1
আমি এই পোস্টটি আমার পছন্দসই তালিকার শীর্ষে যুক্ত করতে এবং এটি সেখানে রাখতে চাই।
ডোনাতো

2
আমি এর বিন্দুটি দেখতে পাচ্ছি না - আপনি কেবল বিমূর্ততার একটি স্তর যুক্ত করছেন যা কিছুই করে না। আপনি পাশাপাশি secretএকটি সম্পত্তি করতে পারেন this। জাভাস্ক্রিপ্ট প্রোটোটাইপগুলির সাথে প্রাইভেট ভেরিয়েবলগুলি সমর্থন করে না কারণ প্রোটোটাইপগুলি 'সৃজন-সাইট' প্রসঙ্গে নয়, কল-সাইট প্রসঙ্গে আবদ্ধ।
নিকোডেমাস 13

1
ঠিক person.getSecret()তখনই কেন করবেন না ?
ফাহমি

1
এটি কেন এত উপার্জন করে? এটি ভেরিয়েবলটিকে ব্যক্তিগত করে না। উপরের হিসাবে person.getSecret () ব্যবহার করে উল্লিখিত হিসাবে আপনাকে যে কোনও জায়গা থেকে যে ব্যক্তিগত ভেরিয়েবল অ্যাক্সেস করতে পারবেন।
alexr101

63

আপডেট: ES6 এর সাথে আরও ভাল উপায় আছে:

দীর্ঘ গল্প সংক্ষিপ্ত, আপনি Symbolব্যক্তিগত ক্ষেত্র তৈরি করতে নতুনটি ব্যবহার করতে পারেন ।
এখানে একটি দুর্দান্ত বিবরণ দেওয়া হয়েছে: https://curiosity-driven.org/private-properties-in- জাভাস্ক্রিপ্ট

উদাহরণ:

var Person = (function() {
    // Only Person can access nameSymbol
    var nameSymbol = Symbol('name');

    function Person(name) {
        this[nameSymbol] = name;
    }

    Person.prototype.getName = function() {
        return this[nameSymbol];
    };

    return Person;
}());

ES5 সহ সমস্ত আধুনিক ব্রাউজারের জন্য:

আপনি কেবল ক্লোজার ব্যবহার করতে পারেন

অবজেক্ট তৈরির সহজ উপায় হ'ল প্রোটোটাইপাল উত্তরাধিকার পুরোপুরি এড়ানো। বন্ধের মধ্যে কেবল প্রাইভেট ভেরিয়েবল এবং পাবলিক ফাংশনগুলি সংজ্ঞায়িত করুন এবং সমস্ত পাবলিক পদ্ধতিতে ভেরিয়েবলগুলিতে ব্যক্তিগত অ্যাক্সেস থাকবে।

অথবা আপনি কেবল প্রোটোটাইপ ব্যবহার করতে পারেন

জাভাস্ক্রিপ্টে, প্রোটোটাইপাল উত্তরাধিকার প্রাথমিকভাবে একটি অপ্টিমাইজেশন । এটি প্রতিটি উদাহরণের নিজস্ব পদ্ধতি না করে একাধিক উদাহরণকে প্রোটোটাইপ পদ্ধতি ভাগ করতে দেয়।
অপূর্ণতা যে thisহয় শুধুমাত্র জিনিস যে প্রতিটি সময় একটি প্রটোটাইপ ফাংশন বলা হয় আলাদা।
অতএব, যে কোনও ব্যক্তিগত ক্ষেত্র অবশ্যই অ্যাক্সেসযোগ্য হবে thisযার অর্থ তারা সর্বজনীন হতে চলেছে। সুতরাং আমরা কেবল _privateক্ষেত্রগুলির জন্য নামকরণের সম্মেলনে আটকে থাকি ।

প্রোটোটাইপগুলির সাথে ক্লোজারগুলিকে মেশানো বিরক্ত করবেন না

আমি মনে করি আপনার প্রোটোটাইপ পদ্ধতিগুলির সাথে ক্লোজার ভেরিয়েবলগুলি মিশ্রিত করা উচিত নয় । আপনার এক বা অন্যটি ব্যবহার করা উচিত।

আপনি যখন কোনও ব্যক্তিগত ভেরিয়েবল অ্যাক্সেস করতে ক্লোজার ব্যবহার করেন, প্রোটোটাইপ পদ্ধতিগুলি ভেরিয়েবলটি অ্যাক্সেস করতে পারে না। সুতরাং, আপনাকে বন্ধটি প্রকাশ করতে হবে thisযার অর্থ আপনি এটি প্রকাশ্যভাবে এক বা অন্যভাবে প্রকাশ করছেন। এই পদ্ধতির সাথে লাভ করার খুব কম আছে।

আমি কোনটি বেছে নেব?

সত্যিকারের সরল অবজেক্টের জন্য ক্লোজার সহ একটি সরল অবজেক্ট ব্যবহার করুন।

আপনার যদি প্রোটোটাইপাল উত্তরাধিকারের প্রয়োজন হয় - উত্তরাধিকার, সম্পাদনা ইত্যাদির জন্য - তবে "_প্রাইভেট" নামকরণের কনভেনশনটি বদ্ধ থাকুন এবং ক্লোজার নিয়ে বিরক্ত করবেন না।

আমি বুঝতে পারছি না কেন জেএস বিকাশকারীরা ক্ষেত্রগুলি সত্যই ব্যক্তিগতকরণের জন্য খুব চেষ্টা করে।


4
দুঃখের বিষয়, _privateআপনি যদি নমুনা উত্তরাধিকারের সুযোগ নিতে চান তবে নামকরণের সম্মেলনটি এখনও সেরা সমাধান।
ক্রাশ করুন

1
ES6 এর একটি নতুন ধারণা থাকবে, এটি Symbolব্যক্তিগত ক্ষেত্রগুলি তৈরির একটি দুর্দান্ত উপায়। : এখানে একটি বড় ব্যাখ্যা curiosity-driven.org/private-properties-in-javascript
স্কট Rippey

1
না, আপনি Symbolএমন একটি ক্লোজার রাখতে পারেন যা আপনার পুরো ক্লাসকে ঘিরে রেখেছে। এইভাবে, সমস্ত প্রোটোটাইপ পদ্ধতি সিম্বলটি ব্যবহার করতে পারে তবে এটি শ্রেণীর বাইরে কখনও প্রকাশিত হয় না।
স্কট রিপ্পি

2
নিবন্ধটি আপনার লিঙ্ক বলে " প্রতীক ব্যক্তিগত নাম অনুরূপ কিন্তু রয়েছে - ব্যক্তিগত নাম অসদৃশ - তারা সত্য গোপনীয়তা প্রদান করবেন না "। কার্যকরভাবে, যদি আপনার কাছে উদাহরণ থাকে তবে আপনি এর প্রতীকগুলি সাথে পেতে পারেন Object.getOwnPropertySymbols। সুতরাং এটি কেবল অস্পষ্টতার দ্বারা গোপনীয়তা।
ওরিওল

2
ওরিওল হ্যাঁ, গোপনীয়তাটি ভারী অস্পষ্টতার মাধ্যমে হয়। প্রতীকগুলির মাধ্যমে পুনরাবৃত্তি করা এখনও সম্ভব এবং আপনি প্রতীকটির উদ্দেশ্যটি এর মধ্য দিয়ে অনুমান করেন toString। এটি জাভা বা সি # এর চেয়ে আলাদা নয় ... ব্যক্তিগত সদস্যরা প্রতিবিম্বের মাধ্যমে এখনও অ্যাক্সেসযোগ্য তবে সাধারণত দৃ strongly়ভাবে অস্পষ্ট হন। যা সবই আমার চূড়ান্ত পয়েন্টটিকে শক্তিশালী করতে চলেছে, "জেএস ​​বিকাশকারীরা কেন ক্ষেত্রগুলি সত্যই ব্যক্তিগত করার জন্য এত চেষ্টা করে তা আমি বুঝতে পারি না।"
স্কট রিপ্পি

31

আমি যখন এটি পড়ি তখন এটি শক্ত চ্যালেঞ্জের মতো মনে হয়েছিল তাই আমি কোনও উপায় বের করার সিদ্ধান্ত নিয়েছি। আমি যা নিয়ে এসেছি তা হ'ল CRAAAAZY তবে এটি পুরোপুরি কার্যকর।

প্রথমত, আমি ক্লাসটি একটি তাত্ক্ষণিক ফাংশনে সংজ্ঞায়িত করার চেষ্টা করেছি যাতে আপনি সেই ফাংশনের কিছু ব্যক্তিগত সম্পত্তিতে অ্যাক্সেস পেতে পারেন। এটি কাজ করে এবং আপনাকে কিছু ব্যক্তিগত ডেটা পেতে দেয়, তবে, আপনি ব্যক্তিগত ডেটা সেট করার চেষ্টা করলে আপনি শীঘ্রই দেখতে পাবেন যে সমস্ত বস্তু একই মান ভাগ করবে share

var SharedPrivateClass = (function() { // use immediate function
    // our private data
    var private = "Default";

    // create the constructor
    function SharedPrivateClass() {}

    // add to the prototype
    SharedPrivateClass.prototype.getPrivate = function() {
        // It has access to private vars from the immediate function!
        return private;
    };

    SharedPrivateClass.prototype.setPrivate = function(value) {
        private = value;
    };

    return SharedPrivateClass;
})();

var a = new SharedPrivateClass();
console.log("a:", a.getPrivate()); // "a: Default"

var b = new SharedPrivateClass();
console.log("b:", b.getPrivate()); // "b: Default"

a.setPrivate("foo"); // a Sets private to "foo"
console.log("a:", a.getPrivate()); // "a: foo"
console.log("b:", b.getPrivate()); // oh no, b.getPrivate() is "foo"!

console.log(a.hasOwnProperty("getPrivate")); // false. belongs to the prototype
console.log(a.private); // undefined

// getPrivate() is only created once and instanceof still works
console.log(a.getPrivate === b.getPrivate);
console.log(a instanceof SharedPrivateClass);
console.log(b instanceof SharedPrivateClass);

আপনি যদি ইভেন্টের নামগুলির মত ধ্রুবক মান পেতে চান যা উদাহরণগুলির মধ্যে ভাগ হয়ে যায় এমন ক্ষেত্রে প্রচুর পরিমাণে মামলা রয়েছে। তবে মূলত, তারা ব্যক্তিগত স্ট্যাটিক ভেরিয়েবলগুলির মতো কাজ করে।

প্রোটোটাইপের উপর নির্ভর করে আপনার পদ্ধতিগুলির মধ্যে যদি আপনার কোনও প্রাইভেট নেমস্পেসে ভেরিয়েবলের অ্যাক্সেসের প্রয়োজন হয় তবে আপনি এই প্যাটার্নটি চেষ্টা করতে পারেন।

var PrivateNamespaceClass = (function() { // immediate function
    var instance = 0, // counts the number of instances
        defaultName = "Default Name",  
        p = []; // an array of private objects

    // create the constructor
    function PrivateNamespaceClass() {
        // Increment the instance count and save it to the instance. 
        // This will become your key to your private space.
        this.i = instance++; 
        
        // Create a new object in the private space.
        p[this.i] = {};
        // Define properties or methods in the private space.
        p[this.i].name = defaultName;
        
        console.log("New instance " + this.i);        
    }

    PrivateNamespaceClass.prototype.getPrivateName = function() {
        // It has access to the private space and it's children!
        return p[this.i].name;
    };
    PrivateNamespaceClass.prototype.setPrivateName = function(value) {
        // Because you use the instance number assigned to the object (this.i)
        // as a key, the values set will not change in other instances.
        p[this.i].name = value;
        return "Set " + p[this.i].name;
    };

    return PrivateNamespaceClass;
})();

var a = new PrivateNamespaceClass();
console.log(a.getPrivateName()); // Default Name

var b = new PrivateNamespaceClass();
console.log(b.getPrivateName()); // Default Name

console.log(a.setPrivateName("A"));
console.log(b.setPrivateName("B"));
console.log(a.getPrivateName()); // A
console.log(b.getPrivateName()); // B

// private objects are not accessible outside the PrivateNamespaceClass function
console.log(a.p);

// the prototype functions are not re-created for each instance
// and instanceof still works
console.log(a.getPrivateName === b.getPrivateName);
console.log(a instanceof PrivateNamespaceClass);
console.log(b instanceof PrivateNamespaceClass);

আমি এমন কারও কাছ থেকে কিছু প্রতিক্রিয়া পছন্দ করব যে এটি করার এই পদ্ধতিতে কোনও ত্রুটি দেখে।


4
আমার ধারণা একটি সম্ভাব্য উদ্বেগ হ'ল যে কোনও উদাহরণ পৃথক আইডি ব্যবহার করে অন্য কোনও দৃষ্টান্তের প্রাইভেট ওয়ার অ্যাক্সেস করতে পারে। অগত্যা কোনও খারাপ জিনিস নয় ...
মিমস এইচ রাইট

15
আপনি প্রতিটি কনস্ট্রাক্টর কলের উপরে প্রোটোটাইপ ফাংশনগুলি পুনরায় সংজ্ঞায়িত করেন
Lu4

10
@ Lu4 আমি নিশ্চিত যে এটি সত্য that's কনস্ট্রাক্টর একটি বন্ধের মধ্যে থেকে ফিরে আসে; প্রোটোটাইপ ফাংশন সংজ্ঞায়িত শুধুমাত্র একবার, সঙ্গে সঙ্গে অনুরোধ ফাংশন এক্সপ্রেশন। উপরে গোপনীয়তার বিষয়গুলি উল্লিখিত ছিল, এটি আমার কাছে ভাল দেখাচ্ছে (প্রথম নজরে)।
গাইপ্সার্স

1
@ মিমসএইচ। রাইট অন্যান্য ভাষাগুলি একই শ্রেণীর বেসরকারীদের অন্যান্য বস্তুগুলিতে অ্যাক্সেসের অনুমতি দেয় তবে কেবলমাত্র যখন আপনি সেগুলির উল্লেখ করেন। এটির জন্য অনুমোদনের জন্য আপনি কোনও ফাংশনের পিছনে প্রাইভেটগুলি আড়াল করতে পারেন যা বস্তুগুলির পয়েন্টারটিকে কী হিসাবে নেয় (কোনও আইডিকে প্রয়োগ করা হয়)। এইভাবে আপনার কাছে কেবল অবজেক্টের ব্যক্তিগত ডেটাতে অ্যাক্সেস রয়েছে যা অন্যান্য ভাষায় স্কোপিংয়ের সাথে আরও ইনলাইন। যাইহোক, এই বাস্তবায়ন এটির সাথে গভীর সমস্যা সম্পর্কে আলোকপাত করে। কনস্ট্রাক্টর ফাংশন না হওয়া পর্যন্ত ব্যক্তিগত অবজেক্টগুলি কখনই আবর্জনা সংগ্রহ করা হবে না।
টমাস নাদিন

3
আমি উল্লেখ করতে চাই যে iসমস্ত দৃষ্টান্তে যুক্ত হয়েছে। সুতরাং এটি পুরোপুরি "স্বচ্ছ" নয়, এবং iএখনও এটির সাথে টেম্পার করতে পারে।
স্কট রিপ্পি

18

দেখতে এই ডগ Crockford এর পাতা । আপনাকে এটিকে অপ্রত্যক্ষভাবে এমন কিছু দিয়ে করতে হবে যা প্রাইভেট ভেরিয়েবলের স্কোপ অ্যাক্সেস করতে পারে।

আরেকটি উদাহরণ:

Incrementer = function(init) {
  var counter = init || 0;  // "counter" is a private variable
  this._increment = function() { return counter++; }
  this._set = function(x) { counter = x; }
}
Incrementer.prototype.increment = function() { return this._increment(); }
Incrementer.prototype.set = function(x) { return this._set(x); }

ব্যবহারের ক্ষেত্রে:

js>i = new Incrementer(100);
[object Object]
js>i.increment()
100
js>i.increment()
101
js>i.increment()
102
js>i.increment()
103
js>i.set(-44)
js>i.increment()
-44
js>i.increment()
-43
js>i.increment()
-42

47
এই উদাহরণটি ভয়াবহ অনুশীলন বলে মনে হয়। প্রোটোটাইপ পদ্ধতিগুলি ব্যবহার করার বিষয়টি হ'ল যাতে আপনাকে প্রতিটি উদাহরণের জন্য একটি নতুন তৈরি করতে না হয়। আপনি যেভাবেই করছেন। প্রতিটি পদ্ধতির জন্য আপনি অন্য একটি তৈরি করছেন।
কির

2
@ আর্মডমনকি ধারণাটি দেখতে দুর্দান্ত লাগছে তবে এটি একটি খারাপ উদাহরণ হিসাবে সম্মত হয়েছে কারণ দেখানো প্রোটোটাইপ ফাংশনগুলি তুচ্ছ। প্রোটোটাইপ ফাংশনগুলি যদি 'বেসরকারী' ভেরিয়েবলগুলিতে সাধারণ প্রাপ্ত / সেট অ্যাক্সেসের প্রয়োজন হয় তবে এটি দীর্ঘস্থায়ী হবে।
প্যানকেকে

9
কেন এমনকি প্রকাশক বিরক্ত _setমাধ্যমে set? শুধু নাম setদিয়ে শুরু করবেন না কেন ?
স্কট রিপ্পি

15

আমি পরামর্শ দিচ্ছি যে জাভাস্ক্রিপ্ট বিরোধী-নিদর্শন হিসাবে "কোনও কনস্ট্রাক্টরে প্রোটোটাইপ অ্যাসাইনমেন্ট থাকা" বর্ণনা করা ভাল ধারণা হবে। চিন্তা করুন. এটা উপায় খুব ঝুঁকিপূর্ণ।

দ্বিতীয় বস্তুর (যেমন খ) তৈরিতে আপনি সেখানে যা করছেন তা হ'ল সেই প্রোটোটাইপ ব্যবহারকারী সমস্ত বস্তুর জন্য সেই প্রোটোটাইপ ফাংশনটিকে নতুন করে সংজ্ঞায়িত করছে। এটি কার্যকরভাবে আপনার উদাহরণের জন্য বস্তুর জন্য মানটি পুনরায় সেট করবে। আপনি যদি একটি ভাগ করা পরিবর্তনশীল চান এবং আপনি যদি সমস্ত অবজেক্টটি সামনে তুলে ধরেন তবে এটি কাজ করবে তবে এটি খুব ঝুঁকিপূর্ণ বোধ করে।

আমি সম্প্রতি কিছু জাভাস্ক্রিপ্টে কাজ করেছিলাম এমন একটি বাগ খুঁজে পেয়েছি যা এই সঠিক অ্যান্টি-প্যাটার্নের কারণে হয়েছিল। এটি তৈরি হওয়া নির্দিষ্ট অবজেক্টটিতে একটি ড্রাগ এবং ড্রপ হ্যান্ডলার সেট করার চেষ্টা করছিল তবে সমস্ত দৃষ্টান্তের পরিবর্তে এটি করছে। ভাল না.

ডগ ক্রকফোর্ডের সমাধানটি সেরা।


10

@Kai

যে কাজ করবে না। যদি তুমি করো

var t2 = new TestClass();

তারপরে t2.prototypeHelloটি এর ব্যক্তিগত বিভাগটি অ্যাক্সেস করা হবে।

@AnglesCrimes

নমুনা কোডটি সূক্ষ্মভাবে কাজ করে তবে এটি প্রকৃতপক্ষে সমস্ত পরিস্থিতি দ্বারা ভাগ করা একটি "স্থিতিশীল" ব্যক্তিগত সদস্য তৈরি করে। এটি মর্গানকোডগুলির সন্ধান করা সমাধান নাও হতে পারে।

এখন পর্যন্ত আমি কোনও ব্যক্তিগত হ্যাশ এবং অতিরিক্ত ক্লিনআপ ফাংশন প্রবর্তন না করে এটি করার সহজ এবং পরিষ্কার উপায় খুঁজে পাই না। একটি ব্যক্তিগত সদস্য ফাংশন নির্দিষ্ট পরিমাণে অনুকরণ করা যেতে পারে:

(function() {
    function Foo() { ... }
    Foo.prototype.bar = function() {
       privateFoo.call(this, blah);
    };
    function privateFoo(blah) { 
        // scoped to the instance by passing this to call 
    }

    window.Foo = Foo;
}());

আপনার পয়েন্টগুলি স্পষ্টভাবে বুঝতে পেরেছেন, তবে আপনি দয়া করে ব্যাখ্যা করতে পারেন যে আপনার কোড স্নিপেট কী করার চেষ্টা করছে?
বিশ্বনাথ

privateFooসম্পূর্ণরূপে ব্যক্তিগত এবং একটি পেয়ে যখন অদৃশ্য new Foo()। শুধুমাত্র bar()এখানে একটি সর্বজনীন পদ্ধতি, যার অ্যাক্সেস রয়েছে privateFoo। আপনি সাধারণ ভেরিয়েবল এবং অবজেক্টের জন্য একই প্রক্রিয়াটি ব্যবহার করতে পারেন, তবে আপনাকে সর্বদা মনে রাখতে হবে যে সেগুলি privatesআসলে স্থির এবং আপনার তৈরি সমস্ত বস্তুর দ্বারা ভাগ করা হবে।
ফিলজেন

6

হ্যাঁ এটা সম্ভব. পিপিএফ ডিজাইনের প্যাটার্নটি কেবল এটি সমাধান করে।

পিপিএফ বলতে প্রাইভেট প্রোটোটাইপ ফাংশন বোঝায়। বেসিক পিপিএফ এই সমস্যাগুলি সমাধান করে:

  1. প্রোটোটাইপ ফাংশনগুলি ব্যক্তিগত উদাহরণ ডেটাতে অ্যাক্সেস পায়।
  2. প্রোটোটাইপ ফাংশনগুলি ব্যক্তিগত করা যেতে পারে।

প্রথমটির জন্য, ঠিক:

  1. আপনি কোনও পৃথক ডেটা কনটেইনারের অভ্যন্তরে প্রোটোটাইপ ফাংশন থেকে অ্যাক্সেসযোগ্য হতে চান এমন সমস্ত বেসরকারী উদাহরণের ভেরিয়েবলগুলি রাখুন
  2. প্যারামিটার হিসাবে সমস্ত প্রোটোটাইপ ফাংশনে ডেটা ধারকটির একটি রেফারেন্স দিন।

এটা খুব সহজ। উদাহরণ স্বরূপ:

// Helper class to store private data.
function Data() {};

// Object constructor
function Point(x, y)
{
  // container for private vars: all private vars go here
  // we want x, y be changeable via methods only
  var data = new Data;
  data.x = x;
  data.y = y;

  ...
}

// Prototype functions now have access to private instance data
Point.prototype.getX = function(data)
{
  return data.x;
}

Point.prototype.getY = function(data)
{
  return data.y;
}

...

এখানে পূর্ণ বিবরণ পড়ুন:

পিপিএফ ডিজাইন প্যাটার্ন


4
কেবলমাত্র লিঙ্ক-উত্তর উত্তরে এসও তে নিমগ্ন হয়। দয়া করে একটি উদাহরণ দেখান
কোরি অ্যাডলার

নিবন্ধটির অভ্যন্তরে উদাহরণ রয়েছে, সুতরাং দয়া করে এটি দেখুন
এডওয়ার্ড

5
তবে কি হয়, যদি কোনও এক সময় পরে সেই সাইটে নীচে নেমে যায়? কীভাবে কারও উদাহরণ দেখতে পাওয়ার কথা? নীতিটি স্থানে রয়েছে যাতে কোনও লিঙ্কে থাকা মূল্যবোধের কিছু এখানে রাখা যায়, এবং কোনও ওয়েবসাইটের উপর নির্ভর করতে হবে না যে এটি আমাদের নিয়ন্ত্রণে নেই।
কোরি অ্যাডলার

3
@ অ্যাডওয়ার্ড, আপনার লিঙ্কটি একটি আকর্ষণীয় পঠন! তবে এটি আমার কাছে মনে হয় যে প্রোটোটাইপিকাল ফাংশনগুলি ব্যবহার করে ব্যক্তিগত ডেটা অ্যাক্সেসের প্রধান কারণ হ'ল প্রতিরোধ করা যে প্রতিটি বস্তু অভিন্ন পাবলিক ফাংশন সহ স্মৃতি অপচয় করে। আপনি যে পদ্ধতিটি বর্ণনা করেছেন তা এই সমস্যাটির সমাধান করে না, যেহেতু জনসাধারণের ব্যবহারের জন্য, একটি প্রোটোটাইপিকাল ফাংশনটি নিয়মিত পাবলিক ফাংশনটিতে আবৃত করা দরকার। আমি অনুমান করি যে প্যাটার্নটি স্মৃতি সাশ্রয়ের জন্য কার্যকর হতে পারে যদি আপনার প্রচুর পিপিএফ থাকে যা একক পাবলিক ফাংশনে মিলিত হয়। আপনি এগুলি অন্য কিছুর জন্য ব্যবহার করেন?
ডাইনিং দার্শনিক

@ ডাইনিংফিলোসোফার, আমার নিবন্ধটি প্রশংসা করার জন্য আপনাকে ধন্যবাদ। হ্যাঁ, আপনি ঠিক বলেছেন, আমরা এখনও উদাহরণ ফাংশন ব্যবহার করি use তবে ধারণাটি হ'ল কেবলমাত্র তাদের পিপিএফ সহযোগীদের যেগুলি সমস্ত ভারী কাজ করে তাদের পুনরায় কল করে তাদের যতটা সম্ভব হালকা ওজন করা উচিত। অবশেষে সমস্ত দৃষ্টান্ত একই পিপিএফগুলিকে কল করে (অবশ্যই মোড়কের মাধ্যমে), যাতে একটি নির্দিষ্ট মেমরি সঞ্চয় আশা করা যায়। প্রশ্ন কত। আমি যথেষ্ট সঞ্চয় আশা করি।
এডওয়ার্ড

5

আপনি অ্যাক্সেসর যাচাইকরণ ব্যবহার করে এটি অর্জন করতে পারেন :

(function(key, global) {
  // Creates a private data accessor function.
  function _(pData) {
    return function(aKey) {
      return aKey === key && pData;
    };
  }

  // Private data accessor verifier.  Verifies by making sure that the string
  // version of the function looks normal and that the toString function hasn't
  // been modified.  NOTE:  Verification can be duped if the rogue code replaces
  // Function.prototype.toString before this closure executes.
  function $(me) {
    if(me._ + '' == _asString && me._.toString === _toString) {
      return me._(key);
    }
  }
  var _asString = _({}) + '', _toString = _.toString;

  // Creates a Person class.
  var PersonPrototype = (global.Person = function(firstName, lastName) {
    this._ = _({
      firstName : firstName,
      lastName : lastName
    });
  }).prototype;
  PersonPrototype.getName = function() {
    var pData = $(this);
    return pData.firstName + ' ' + pData.lastName;
  };
  PersonPrototype.setFirstName = function(firstName) {
    var pData = $(this);
    pData.firstName = firstName;
    return this;
  };
  PersonPrototype.setLastName = function(lastName) {
    var pData = $(this);
    pData.lastName = lastName;
    return this;
  };
})({}, this);

var chris = new Person('Chris', 'West');
alert(chris.setFirstName('Christopher').setLastName('Webber').getName());

এই উদাহরণটি প্রোটোটাইপাল ফাংশন এবং ব্যক্তিগত ডেটা সম্পর্কে আমার পোস্ট থেকে আসে এবং সেখানে আরও বিস্তারিতভাবে ব্যাখ্যা করা হয়।


1
এই উত্তরটি দরকারী হিসাবে খুব "চালাক", তবে আমি একটি গোপন হ্যান্ডশেক হিসাবে আইএফএফই-বাউন্ড ভেরিয়েবল ব্যবহারের উত্তরটি পছন্দ করি। এই প্রয়োগ কার্যকর হতে অনেক বেশি ক্লোজার ব্যবহার করে; প্রোটোটাইপ সংজ্ঞায়িত পদ্ধতি থাকার বিষয়টি হ'ল প্রতিটি বস্তুর প্রতিটি পদ্ধতির জন্য নতুন ফাংশন অবজেক্টগুলির নির্মাণ প্রতিরোধ করা।
গ্রেগ.কিন্ডেল

কোন প্রোটোটাইপ পদ্ধতি বিশ্বাসযোগ্য এবং কোনটি নয় তা সনাক্ত করার জন্য এই পদ্ধতিটি একটি গোপন কী ব্যবহার করে। যাইহোক, এটি উদাহরণটি কে কীটি বৈধতা দেয়, তাই কীটি অবশ্যই পাঠাতে হবে। তবে তারপরে, অবিশ্বস্ত কোডটি একটি জাল উদাহরণে একটি বিশ্বস্ত পদ্ধতি কল করতে পারে, যা কীটি চুরি করে। এবং এই কীটি দিয়ে, এমন নতুন পদ্ধতি তৈরি করুন যা বাস্তব দৃষ্টান্ত দ্বারা বিশ্বাসযোগ্য বলে বিবেচিত হবে। সুতরাং এটি কেবল অস্পষ্টতার দ্বারা গোপনীয়তা।
ওরিওল

4

বর্তমান জাভাস্ক্রিপ্ট, আমি মোটামুটি নিশ্চিত যে আছি এক এবং শুধুমাত্র এক উপায় আছে ব্যক্তিগত রাষ্ট্র থেকে প্রবেশযোগ্য প্রোটোটাইপ ফাংশন, কিছু যোগ ছাড়া প্রকাশ্য করার this। উত্তরটি হ'ল "দুর্বল মানচিত্র" প্যাটার্নটি ব্যবহার করা।

এর সংক্ষিপ্তসারটি হিসাবে: Personশ্রেণিতে একটি একক দুর্বল মানচিত্র রয়েছে, যেখানে কীগুলি ব্যক্তিটির উদাহরণ এবং মানগুলি সরল বস্তু যা ব্যক্তিগত স্টোরেজের জন্য ব্যবহৃত হয়।

এখানে সম্পূর্ণ কার্যকরী উদাহরণ: ( http://jsfiddle.net/ScottRippey/BLNVr/ এ খেলুন )

var Person = (function() {
    var _ = weakMap();
    // Now, _(this) returns an object, used for private storage.
    var Person = function(first, last) {
        // Assign private storage:
        _(this).firstName = first;
        _(this).lastName = last;
    }
    Person.prototype = {
        fullName: function() {
            // Retrieve private storage:
            return _(this).firstName + _(this).lastName;
        },
        firstName: function() {
            return _(this).firstName;
        },
        destroy: function() {
            // Free up the private storage:
            _(this, true);
        }
    };
    return Person;
})();

function weakMap() {
    var instances=[], values=[];
    return function(instance, destroy) {
        var index = instances.indexOf(instance);
        if (destroy) {
            // Delete the private state:
            instances.splice(index, 1);
            return values.splice(index, 1)[0];
        } else if (index === -1) {
            // Create the private state:
            instances.push(instance);
            values.push({});
            return values[values.length - 1];
        } else {
            // Return the private state:
            return values[index];
        }
    };
}

যেমনটি আমি বলেছিলাম, সমস্ত 3 অংশ অর্জনের এটিই একমাত্র উপায়।

তবে দুটি ক্যাভেট রয়েছে। প্রথমত, এর জন্য পারফরম্যান্স ব্যয় হয় - প্রতিবার আপনি ব্যক্তিগত ডেটা অ্যাক্সেস করার পরে এটি একটি O(n)অপারেশন, যেখানে nউদাহরণগুলির সংখ্যা। সুতরাং আপনার কাছে প্রচুর পরিমাণে দৃষ্টান্ত থাকলে আপনি এটি করতে চাইবেন না। দ্বিতীয়ত, আপনি যখন একটি উদাহরণ দিয়ে সম্পন্ন করবেন, আপনাকে অবশ্যই কল করতে হবে destroy; অন্যথায়, উদাহরণ এবং ডেটা আবর্জনা সংগ্রহ করা হবে না, এবং আপনি একটি মেমরি ফাঁস শেষ হবে।

এবং সে কারণেই আমার আসল উত্তর, "আপনার উচিত নয়" এটি এমন একটি যা আমি আটকে রাখতে চাই।


যদি আপনি স্পষ্টভাবে ব্যক্তির কোনও উদাহরণটি সুযোগের বাইরে চলে যাওয়ার আগে নষ্ট না করে তবে দুর্বলতা ম্যাপটি কোনও রেফারেন্স রাখে না তাই আপনার স্মৃতি ফাঁস হবে? আমি একটি প্যাটার্ন নিয়ে এসেছেন সংরক্ষিত পারসন অন্যান্য দৃষ্টান্ত ব্যক্তি থেকে করতে পারেন পরিবর্তনশীল এবং যারা উত্তরাধিকার সূত্রে প্রাপ্ত অ্যাক্সেস করতে পারেন হিসাবে। কেবল এটি আউট করে ফেলা হয়েছে তাই নিশ্চিত হন না যে অতিরিক্ত প্রক্রিয়াজাতকরণ ব্যতীত অন্য কোনও সুযোগ-সুবিধাগুলি রয়েছে ( প্রাইভেটগুলি অ্যাক্সেস করার মতো দেখায় না) stackoverflow.com/a/21800194/1641941 ব্যক্তিগত / সুরক্ষিত কোনও জিনিস ফিরে আসা কলিং কোডের পর থেকে ব্যথা তারপরে আপনার ব্যক্তিগত / সুরক্ষিতকে পরিবর্তন করতে পারে।
এইচএমআর

2
@ এইচএমআর হ্যাঁ, আপনাকে স্পষ্টভাবে ব্যক্তিগত ডেটা ধ্বংস করতে হবে। আমি এই উত্তরে আমার উত্তরে যুক্ত করতে যাচ্ছি।
স্কট রিপ্পি

3

পদ্ধতির ব্যবহার bindএবং callপদ্ধতিকে লাভবান করার একটি সহজ উপায় রয়েছে ।

কোনও অবজেক্টে প্রাইভেট ভেরিয়েবল সেট করে আপনি সেই অবজেক্টের স্কোপটি উত্তোলন করতে পারবেন।

উদাহরণ

function TestClass (value) {
    // The private value(s)
    var _private = {
        value: value
    };

    // `bind` creates a copy of `getValue` when the object is instantiated
    this.getValue = TestClass.prototype.getValue.bind(_private);

    // Use `call` in another function if the prototype method will possibly change
    this.getValueDynamic = function() {
        return TestClass.prototype.getValue.call(_private);
    };
};

TestClass.prototype.getValue = function() {
    return this.value;
};

এই পদ্ধতিটি কোনও ত্রুটি ছাড়াই নয়। যেহেতু স্কোপ প্রসঙ্গটি কার্যকরভাবে ওভাররাইড হচ্ছে, আপনার কাছে _privateঅবজেক্টের বাইরে অ্যাক্সেস নেই । যাইহোক, উদাহরণস্বরূপ অবজেক্টের স্কোপটিতে এখনও অ্যাক্সেস দেওয়া যদিও এটি অসম্ভব নয়। প্রোটোটাইপ ফাংশনটিতে এটির সর্বজনীন মানগুলিতে thisদ্বিতীয় যুক্তি হিসাবে bindবা callএখনও অ্যাক্সেসের জন্য আপনি অবজেক্টের প্রসঙ্গে ( ) পাস করতে পারেন ।

জনসাধারণের মূল্যবোধ অ্যাক্সেস করা

function TestClass (value) {
    var _private = {
        value: value
    };

    this.message = "Hello, ";

    this.getMessage = TestClass.prototype.getMessage.bind(_private, this);

}

TestClass.prototype.getMessage = function(_public) {

    // Can still access passed in arguments
    // e.g. – test.getValues('foo'), 'foo' is the 2nd argument to the method
    console.log([].slice.call(arguments, 1));
    return _public.message + this.value;
};

var test = new TestClass("World");
test.getMessage(1, 2, 3); // [1, 2, 3]         (console.log)
                          // => "Hello, World" (return value)

test.message = "Greetings, ";
test.getMessage(); // []                    (console.log)
                   // => "Greetings, World" (return value)

2
কেন কেউ প্রথম স্থানে উদাহরণস্বরূপ পদ্ধতি তৈরির বিপরীতে প্রোটোটাইপ পদ্ধতির অনুলিপি তৈরি করবে?
ক্রাশ করুন

3

চেষ্টা করে দেখুন!

    function Potatoe(size) {
    var _image = new Image();
    _image.src = 'potatoe_'+size+'.png';
    function getImage() {
        if (getImage.caller == null || getImage.caller.owner != Potatoe.prototype)
            throw new Error('This is a private property.');
        return _image;
    }
    Object.defineProperty(this,'image',{
        configurable: false,
        enumerable: false,
        get : getImage          
    });
    Object.defineProperty(this,'size',{
        writable: false,
        configurable: false,
        enumerable: true,
        value : size            
    });
}
Potatoe.prototype.draw = function(ctx,x,y) {
    //ctx.drawImage(this.image,x,y);
    console.log(this.image);
}
Potatoe.prototype.draw.owner = Potatoe.prototype;

var pot = new Potatoe(32);
console.log('Potatoe size: '+pot.size);
try {
    console.log('Potatoe image: '+pot.image);
} catch(e) {
    console.log('Oops: '+e);
}
pot.draw();

1
এটি নির্ভর করে caller, যা বাস্তবায়ন নির্ভর এক্সটেনশন যা কঠোর মোডে অনুমোদিত নয়।
ওরিওল

1

আমি যা নিয়ে এসেছি তা এখানে।

(function () {
    var staticVar = 0;
    var yrObj = function () {
        var private = {"a":1,"b":2};
        var MyObj = function () {
            private.a += staticVar;
            staticVar++;
        };
        MyObj.prototype = {
            "test" : function () {
                console.log(private.a);
            }
        };

        return new MyObj;
    };
    window.YrObj = yrObj;
}());

var obj1 = new YrObj;
var obj2 = new YrObj;
obj1.test(); // 1
obj2.test(); // 2

এই প্রয়োগের মূল সমস্যাটি হ'ল এটি প্রতিটি প্রতিবিম্বের প্রোটোটাইপগুলিকে নতুন করে সংজ্ঞায়িত করে।


আকর্ষণীয়, আমি চেষ্টাটি সত্যিই পছন্দ করি এবং একই জিনিসটি নিয়ে ভাবছিলাম, তবে আপনি ঠিক বলেছেন যে প্রতিটি তাত্ক্ষণীতে প্রোটোটাইপ ফাংশনটিকে নতুনভাবে সংজ্ঞায়িত করা একটি বেশ বড় সীমাবদ্ধতা। এটি কেবল এটি সিপিইউ চক্র নষ্ট করার কারণে নয়, তবে আপনি যদি পরে প্রোটোটাইপটি পরে পরিবর্তন করেন তবে পরের ইনস্ট্যান্টেশন অনুসারে কনস্ট্রাক্টরের সংজ্ঞায়িত হিসাবে এটি "রিসেট" ফিরে আসবে: /
নিকো বেলিক

1
এটি কেবল নতুন সংজ্ঞাযুক্ত প্রোটোটাইপগুলিই নয়, এটি প্রতিটি উদাহরণের জন্য একটি নতুন নির্মাণকারীর সংজ্ঞা দেয়। সুতরাং "দৃষ্টান্তগুলি" আর একই শ্রেণীর উদাহরণ নয়।
ওরিওল

1

এটি করার একটি খুব সহজ উপায় আছে

function SharedPrivate(){
  var private = "secret";
  this.constructor.prototype.getP = function(){return private}
  this.constructor.prototype.setP = function(v){ private = v;}
}

var o1 = new SharedPrivate();
var o2 = new SharedPrivate();

console.log(o1.getP()); // secret
console.log(o2.getP()); // secret
o1.setP("Pentax Full Frame K1 is on sale..!");
console.log(o1.getP()); // Pentax Full Frame K1 is on sale..!
console.log(o2.getP()); // Pentax Full Frame K1 is on sale..!
o2.setP("And it's only for $1,795._");
console.log(o1.getP()); // And it's only for $1,795._

জাভাস্ক্রিপ্ট প্রোটোটাইপগুলি সোনার।


2
আমি বিশ্বাস করি কনস্ট্রাক্টর ফাংশনে প্রোটোটাইপ ব্যবহার না করাই ভাল কারণ এটি প্রতিবার নতুন উদাহরণ তৈরি হওয়ার সাথে সাথে এটি একটি নতুন ফাংশন তৈরি করবে।
ওয়েলসাইকোর

@ ওহামিসিকোর হ্যাঁ সত্য তবে এই ক্ষেত্রে এটি প্রয়োজনীয় কারণ প্রতিটি একক অবজেক্টের জন্য আমাদের ভাগ করে নেওয়া বন্ধের ব্যবস্থা করতে হবে। এই কারণেই ফাংশন সংজ্ঞাগুলি কনস্ট্রাক্টরের অভ্যন্তরে থাকে এবং আমাদের একাধিকবার getP এবং সেটপিকে নতুন করে সংজ্ঞায়িত করার কোনও বড় বিষয় SharedPrivate.prototypeহিসাবে this.constructor.prototypeএটি উল্লেখ করতে হবে ...
রেডু

1

আমি পার্টিতে দেরি করেছি, তবে আমি মনে করি আমি এতে অবদান রাখতে পারি। এখানে, এটি পরীক্ষা করে দেখুন:

// 1. Create closure
var SomeClass = function() {
  // 2. Create `key` inside a closure
  var key = {};
  // Function to create private storage
  var private = function() {
    var obj = {};
    // return Function to access private storage using `key`
    return function(testkey) {
      if(key === testkey) return obj;
      // If `key` is wrong, then storage cannot be accessed
      console.error('Cannot access private properties');
      return undefined;
    };
  };
  var SomeClass = function() {
    // 3. Create private storage
    this._ = private();
    // 4. Access private storage using the `key`
    this._(key).priv_prop = 200;
  };
  SomeClass.prototype.test = function() {
    console.log(this._(key).priv_prop); // Using property from prototype
  };
  return SomeClass;
}();

// Can access private property from within prototype
var instance = new SomeClass();
instance.test(); // `200` logged

// Cannot access private property from outside of the closure
var wrong_key = {};
instance._(wrong_key); // undefined; error logged

আমি এই পদ্ধতিটি অ্যাকসেসর প্যাটার্ন বলি । অপরিহার্য ধারণা যে আমরা একটি আছে অবসান , একটি চাবি অবসান ভিতরে এবং আমরা একে সৃষ্টি ব্যক্তিগত বস্তুর (কন্সট্রাকটর মধ্যে) যে শুধুমাত্র যদি আপনি অ্যাক্সেস করা যেতে পারে কী

আপনি যদি আগ্রহী হন তবে আপনি আমার নিবন্ধে এটি সম্পর্কে আরও পড়তে পারেন । এই পদ্ধতিটি ব্যবহার করে, আপনি প্রতি বস্তুর বৈশিষ্ট্য তৈরি করতে পারেন যা বন্ধের বাইরে অ্যাক্সেস করা যায় না। অতএব, আপনি এগুলি নির্মাণকারী বা প্রোটোটাইপে ব্যবহার করতে পারেন তবে অন্য কোথাও নয়। আমি এই পদ্ধতিটি কোথাও ব্যবহার করতে দেখিনি, তবে আমি মনে করি এটি সত্যই শক্তিশালী।


0

আপনি কি ভেরিয়েবলগুলিকে উচ্চতর সুযোগে রাখতে পারবেন না?

(function () {
    var privateVariable = true;

    var MyClass = function () {
        if (privateVariable) console.log('readable from private scope!');
    };

    MyClass.prototype.publicMethod = function () {
        if (privateVariable) console.log('readable from public scope!');
    };
}))();

4
তারপরে মাই ক্লাসের সমস্ত দৃষ্টান্তের মধ্যে ভেরিয়েবলগুলি ভাগ করা হয়।
ক্রাশ করুন

0

আপনি সরাসরি প্রোটোটাইপে নয়, তবে এটির মতো নির্মাণকারী ফাংশনেও পদ্ধতি যুক্ত করার চেষ্টা করতে পারেন:

var MyArray = function() {
    var array = [];

    this.add = MyArray.add.bind(null, array);
    this.getAll = MyArray.getAll.bind(null, array);
}

MyArray.add = function(array, item) {
    array.push(item);
}
MyArray.getAll = function(array) {
    return array;
}

var myArray1 = new MyArray();
myArray1.add("some item 1");
console.log(myArray1.getAll()); // ['some item 1']
var myArray2 = new MyArray();
myArray2.add("some item 2");
console.log(myArray2.getAll()); // ['some item 2']
console.log(myArray1.getAll()); // ['some item 2'] - FINE!

0

এই সমস্যার সর্বাধিক সহজ সমাধান সন্ধান করার সময় আমি এমন কিছু এখানে এলাম যা সম্ভবত কারও পক্ষে কার্যকর হতে পারে। আমি জাভাস্ক্রিপ্টে নতুন আছি তাই কোড নিয়ে বেশ কিছু সমস্যা থাকতে পারে।

// pseudo-class definition scope
(function () {

    // this is used to identify 'friend' functions defined within this scope,
    // while not being able to forge valid parameter for GetContext() 
    // to gain 'private' access from outside
    var _scope = new (function () { })();
    // -----------------------------------------------------------------

    // pseudo-class definition
    this.Something = function (x) {

        // 'private' members are wrapped into context object,
        // it can be also created with a function
        var _ctx = Object.seal({

            // actual private members
            Name: null,
            Number: null,

            Somefunc: function () {
                console.log('Something(' + this.Name + ').Somefunc(): number = ' + this.Number);
            }
        });
        // -----------------------------------------------------------------

        // function below needs to be defined in every class
        // to allow limited access from prototype
        this.GetContext = function (scope) {

            if (scope !== _scope) throw 'access';
            return _ctx;
        }
        // -----------------------------------------------------------------

        {
            // initialization code, if any
            _ctx.Name = (x !== 'undefined') ? x : 'default';
            _ctx.Number = 0;

            Object.freeze(this);
        }
    }
    // -----------------------------------------------------------------

    // prototype is defined only once
    this.Something.prototype = Object.freeze({

        // public accessors for 'private' field
        get Number() { return this.GetContext(_scope).Number; },
        set Number(v) { this.GetContext(_scope).Number = v; },

        // public function making use of some private fields
        Test: function () {

            var _ctx = this.GetContext(_scope);
            // access 'private' field
            console.log('Something(' + _ctx.Name + ').Test(): ' + _ctx.Number);
            // call 'private' func
            _ctx.Somefunc();
        }
    });
    // -----------------------------------------------------------------

    // wrap is used to hide _scope value and group definitions
}).call(this);

function _A(cond) { if (cond !== true) throw new Error('assert failed'); }
// -----------------------------------------------------------------

function test_smth() {

    console.clear();

    var smth1 = new Something('first'),
      smth2 = new Something('second');

    //_A(false);
    _A(smth1.Test === smth2.Test);

    smth1.Number = 3;
    smth2.Number = 5;
    console.log('smth1.Number: ' + smth1.Number + ', smth2.Number: ' + smth2.Number);

    smth1.Number = 2;
    smth2.Number = 6;

    smth1.Test();
    smth2.Test();

    try {
        var ctx = smth1.GetContext();
    } catch (err) {
        console.log('error: ' + err);
    }
}

test_smth();

0

আমি আজ একই একই প্রশ্নের মুখোমুখি হয়েছি এবং স্কট রিপ্পি প্রথম-শ্রেণীর প্রতিক্রিয়াটি বিশদ দেওয়ার পরে, আমি একটি খুব সাধারণ সমাধান (আইএমএইচও) নিয়ে এসেছি যা ES5 এর সাথে সামঞ্জস্যপূর্ণ এবং দক্ষ উভয়ই, এটি নাম সংঘর্ষ নিরাপদ (_প্রাইভেট ব্যবহারটি অনিরাপদ বলে মনে হয়) ।

/*jslint white: true, plusplus: true */

 /*global console */

var a, TestClass = (function(){
    "use strict";
    function PrefixedCounter (prefix) {
        var counter = 0;
        this.count = function () {
            return prefix + (++counter);
        };
    }
    var TestClass = (function(){
        var cls, pc = new PrefixedCounter("_TestClass_priv_")
        , privateField = pc.count()
        ;
        cls = function(){
            this[privateField] = "hello";
            this.nonProtoHello = function(){
                console.log(this[privateField]);
            };
        };
        cls.prototype.prototypeHello = function(){
            console.log(this[privateField]);
        };
        return cls;
    }());
    return TestClass;
}());

a = new TestClass();
a.nonProtoHello();
a.prototypeHello();

রিঙ্গোজ এবং নোডেজ দিয়ে পরীক্ষা করা হয়েছে। আমি আপনার মতামত পড়তে আগ্রহী।


এখানে একটি রেফারেন্স দেওয়া হয়েছে: 'একটি ধাপ কাছাকাছি' বিভাগটি পরীক্ষা করুন। ফিলিপওয়ালটন.আর্টিকেল /…
জিমাসুন

0
var getParams = function(_func) {
  res = _func.toString().split('function (')[1].split(')')[0].split(',')
  return res
}

function TestClass(){

  var private = {hidden: 'secret'}
  //clever magic accessor thing goes here
  if ( !(this instanceof arguments.callee) ) {
    for (var key in arguments) {
      if (typeof arguments[key] == 'function') {
        var keys = getParams(arguments[key])
        var params = []
        for (var i = 0; i <= keys.length; i++) {
          if (private[keys[i]] != undefined) {
            params.push(private[keys[i]])
          }
        }
        arguments[key].apply(null,params)
      }
    }
  }
}


TestClass.prototype.test = function(){
  var _hidden; //variable I want to get
  TestClass(function(hidden) {_hidden = hidden}) //invoke magic to get
};

new TestClass().test()

এটা কেমন? একটি ব্যক্তিগত অ্যাক্সেসর ব্যবহার করে। কেবলমাত্র আপনাকে ভেরিয়েবলগুলি সেট না করা সত্ত্বেও ব্যবহারের অনুমতি দেয়, এটি ব্যবহারের ক্ষেত্রে নির্ভর করে।


এটি কার্যকর উপায়ে প্রশ্নের উত্তর দেয় নাআপনি কেন এই উত্তরটি বিশ্বাস করেন? এটা কিভাবে কাজ করে? কোনও প্রসঙ্গ বা অর্থ ছাড়াই কাউকে তাদের কোড পরিবর্তন করতে বলা তাদের ভুল কী শিখতে সাহায্য করে না।
গ্রম্পি ক্রাউটন

তিনি ক্লাসের প্রতিটি উদাহরণে সেই গোপন ভেরিয়েবলটি তৈরি না করে প্রোটোটাইপের মাধ্যমে কোনও শ্রেণীর গোপন ব্যক্তিগত ভেরিয়েবলগুলি অ্যাক্সেস করার উপায় চেয়েছিলেন। উপরের কোডটি এমন করার একটি উদাহরণ পদ্ধতি। এটি কীভাবে প্রশ্নের উত্তর নয়?
dylan0150

আমি বললাম না যে এটি প্রশ্নের উত্তর ছিল না। আমি বলেছিলাম এটি কোনও দরকারী উত্তর নয়, কারণ এটি কাউকে শিখতে সহায়তা করে না। আপনার কোডটি কেন ব্যাখ্যা করা উচিত, কেন এটি কাজ করে, কেন এটি করার সঠিক উপায়। আমি যদি প্রশ্ন লেখক হতাম তবে আমি আপনার উত্তরটি গ্রহণ করব না কারণ এটি শেখার জন্য উত্সাহ দেয় না, এটি আমাকে শেখায় না যে আমি কী ভুল করছি বা প্রদত্ত কোডটি কী করছে বা এটি কীভাবে কাজ করে।
গ্রম্পি ক্রাউটন

0

আমার একটি সমাধান আছে, তবে আমি নিশ্চিত নই যে এটি ত্রুটিগুলি ছাড়াই রয়েছে।

এটি কাজ করার জন্য আপনাকে নিম্নলিখিত কাঠামোটি ব্যবহার করতে হবে:

  1. 1 টি ব্যক্তিগত অবজেক্ট ব্যবহার করুন যাতে সমস্ত ব্যক্তিগত ভেরিয়েবল থাকে।
  2. 1 উদাহরণ ফাংশন ব্যবহার করুন।
  3. কনস্ট্রাক্টর এবং সমস্ত প্রোটোটাইপ ফাংশনগুলিতে ক্লোজার প্রয়োগ করুন।
  4. যে কোনও উদাহরণ তৈরি করা বন্ধের সংজ্ঞায়নের বাইরে করা হয়।

কোডটি এখানে:

var TestClass = 
(function () {
    // difficult to be guessed.
    var hash = Math.round(Math.random() * Math.pow(10, 13) + + new Date());
    var TestClass = function () {
        var privateFields = {
            field1: 1,
            field2: 2
        };
        this.getPrivateFields = function (hashed) {
            if(hashed !== hash) {
                throw "Cannot access private fields outside of object.";
                // or return null;
            }
            return privateFields;
        };
    };

    TestClass.prototype.prototypeHello = function () {
        var privateFields = this.getPrivateFields(hash);
        privateFields.field1 = Math.round(Math.random() * 100);
        privateFields.field2 = Math.round(Math.random() * 100);
    };

    TestClass.prototype.logField1 = function () {
        var privateFields = this.getPrivateFields(hash);
        console.log(privateFields.field1);
    };

    TestClass.prototype.logField2 = function () {
        var privateFields = this.getPrivateFields(hash);
        console.log(privateFields.field2);
    };

    return TestClass;
})();

এটি কীভাবে কাজ করে তা এটি "প্রাইভেটফিল্ডস" বেসরকারী ভেরিয়েবল অবজেক্টে অ্যাক্সেসের জন্য "দ্য.জেটপ্রাইভেটফিল্ডস" একটি উদাহরণ ফাংশন সরবরাহ করে তবে এই ফাংশনটি কেবল "প্রাইভেটফিল্ডস" অবজেক্টটিকে মূল ক্লোজারের ভিতরে ফিরিয়ে দেবে ("এই.জেটপ্রাইভেটফিল্ডস ব্যবহার করে প্রোটোটাইপ ফাংশনগুলিও দেবে) "এই বন্ধের মধ্যে সংজ্ঞা দেওয়া দরকার)।

রানটাইম চলাকালীন উত্পাদিত এবং অনুমান করা কঠিন বলে একটি হ্যাশ প্যারামিটার হিসাবে ব্যবহৃত হয় তা নিশ্চিত করার জন্য "গেটপ্রাইভেটফিল্ডস" বন্ধের সুযোগের বাইরেও বলা হলেও "প্রাইভেটফিল্ডস" অবজেক্টটি ফিরিয়ে দেবে না।

অসুবিধাটি হ'ল আমরা ক্লোসের বাইরে আরও প্রোটোটাইপ ফাংশন সহ টেস্টক্লাস প্রসারিত করতে পারি না।

এখানে কিছু পরীক্ষার কোড দেওয়া হল:

var t1 = new TestClass();
console.log('Initial t1 field1 is: ');
t1.logField1();
console.log('Initial t1 field2 is: ');
t1.logField2();
t1.prototypeHello();
console.log('t1 field1 is now: ');
t1.logField1();
console.log('t1 field2 is now: ');
t1.logField2();
var t2 = new TestClass();
console.log('Initial t2 field1 is: ');
t2.logField1();
console.log('Initial t2 field2 is: ');
t2.logField2();
t2.prototypeHello();
console.log('t2 field1 is now: ');
t2.logField1();
console.log('t2 field2 is now: ');
t2.logField2();

console.log('t1 field1 stays: ');
t1.logField1();
console.log('t1 field2 stays: ');
t1.logField2();

t1.getPrivateFields(11233);

সম্পাদনা: এই পদ্ধতিটি ব্যবহার করে, ব্যক্তিগত ফাংশনগুলি "সংজ্ঞায়িত" করাও সম্ভব।

TestClass.prototype.privateFunction = function (hashed) {
    if(hashed !== hash) {
        throw "Cannot access private function.";
    }
};

TestClass.prototype.prototypeHello = function () {
    this.privateFunction(hash);
};

0

আজ এটি নিয়ে ঘুরে বেড়াচ্ছিল এবং এটিই কেবলমাত্র সিম্বলগুলি ব্যবহার না করেই আমি খুঁজে পেলাম solution এটি সম্পর্কে সর্বোত্তম জিনিস এটি আসলে সমস্ত সম্পূর্ণ ব্যক্তিগত হতে পারে।

সমাধানটি মূলত বেসরকারী স্টোরেজ ক্যাশে (একটি দুর্বল মানচিত্র ব্যবহার করে) জন্য মধ্যস্থতাকারী হয়ে ওঠে যা মূলত বেসরকারী মডিউল লোডারকে কেন্দ্র করে তৈরি করা হয়।

   const loader = (function() {
        function ModuleLoader() {}

    //Static, accessible only if truly needed through obj.constructor.modules
    //Can also be made completely private by removing the ModuleLoader prefix.
    ModuleLoader.modulesLoaded = 0;
    ModuleLoader.modules = {}

    ModuleLoader.prototype.define = function(moduleName, dModule) {
        if (moduleName in ModuleLoader.modules) throw new Error('Error, duplicate module');

        const module = ModuleLoader.modules[moduleName] = {}

        module.context = {
            __moduleName: moduleName,
            exports: {}
        }

        //Weak map with instance as the key, when the created instance is garbage collected or goes out of scope this will be cleaned up.
        module._private = {
            private_sections: new WeakMap(),
            instances: []
        };

        function private(action, instance) {
            switch (action) {
                case "create":
                    if (module._private.private_sections.has(instance)) throw new Error('Cannot create private store twice on the same instance! check calls to create.')
                    module._private.instances.push(instance);
                    module._private.private_sections.set(instance, {});
                    break;
                case "delete":
                    const index = module._private.instances.indexOf(instance);
                    if (index == -1) throw new Error('Invalid state');
                    module._private.instances.slice(index, 1);
                    return module._private.private_sections.delete(instance);
                    break;
                case "get":
                    return module._private.private_sections.get(instance);
                    break;
                default:
                    throw new Error('Invalid action');
                    break;
            }
        }

        dModule.call(module.context, private);
        ModuleLoader.modulesLoaded++;
    }

    ModuleLoader.prototype.remove = function(moduleName) {
        if (!moduleName in (ModuleLoader.modules)) return;

        /*
            Clean up as best we can.
        */
        const module = ModuleLoader.modules[moduleName];
        module.context.__moduleName = null;
        module.context.exports = null;
        module.cotext = null;
        module._private.instances.forEach(function(instance) { module._private.private_sections.delete(instance) });
        for (let i = 0; i < module._private.instances.length; i++) {
            module._private.instances[i] = undefined;
        }
        module._private.instances = undefined;
        module._private = null;
        delete ModuleLoader.modules[moduleName];
        ModuleLoader.modulesLoaded -= 1;
    }


    ModuleLoader.prototype.require = function(moduleName) {
        if (!(moduleName in ModuleLoader.modules)) throw new Error('Module does not exist');

        return ModuleLoader.modules[moduleName].context.exports;
    }



     return new ModuleLoader();
    })();

    loader.define('MyModule', function(private_store) {
        function MyClass() {
            //Creates the private storage facility. Called once in constructor.
            private_store("create", this);


            //Retrieve the private storage object from the storage facility.
            private_store("get", this).no = 1;
        }

        MyClass.prototype.incrementPrivateVar = function() {
            private_store("get", this).no += 1;
        }

        MyClass.prototype.getPrivateVar = function() {
            return private_store("get", this).no;
        }

        this.exports = MyClass;
    })

    //Get whatever is exported from MyModule
    const MyClass = loader.require('MyModule');

    //Create a new instance of `MyClass`
    const myClass = new MyClass();

    //Create another instance of `MyClass`
    const myClass2 = new MyClass();

    //print out current private vars
    console.log('pVar = ' + myClass.getPrivateVar())
    console.log('pVar2 = ' + myClass2.getPrivateVar())

    //Increment it
    myClass.incrementPrivateVar()

    //Print out to see if one affected the other or shared
    console.log('pVar after increment = ' + myClass.getPrivateVar())
    console.log('pVar after increment on other class = ' + myClass2.getPrivateVar())

    //Clean up.
    loader.remove('MyModule')

0

আমি জানি যে এটি জিজ্ঞাসা করার পরে এটি 1 দশকেরও বেশি হয়ে গেছে, তবে আমি আমার প্রোগ্রামার জীবনে এন-তম বারের জন্য এই বিষয়ে আমার চিন্তাভাবনা রেখেছি এবং একটি সম্ভাব্য সমাধান পেয়েছি যা আমি জানি না যে আমি এখনও পুরোপুরি পছন্দ করি কিনা । আমি এই পদ্ধতিটি আগে নথিভুক্ত দেখিনি, তাই আমি এটিকে "ব্যক্তিগত / পাবলিক ডলার প্যাটার্ন" বা _ $ / $ প্যাটার্নটির নাম দেব ।

var ownFunctionResult = this.$("functionName"[, arg1[, arg2 ...]]);
var ownFieldValue = this._$("fieldName"[, newValue]);

var objectFunctionResult = objectX.$("functionName"[, arg1[, arg2 ...]]);

//Throws an exception. objectX._$ is not defined
var objectFieldValue = objectX._$("fieldName"[, newValue]);

ধারণাটি একটি শ্রেণিবদ্ধকরণ ফাংশন ব্যবহার করে যা একটি কনস্ট্রাক্টর ফাংশন দেয় যা একটি ইন্টারফেস অবজেক্ট ফেরত দেয় । ইন্টারফেসের একমাত্র পদ্ধতিটি $যা nameকনস্ট্রাক্টর অবজেক্টে সংশ্লিষ্ট ফাংশনটি nameআহ্বানের জন্য একটি আর্গুমেন্ট গ্রহণ করে, অনুরোধে পাস হওয়ার পরে যে কোনও অতিরিক্ত যুক্তি পাস হয়ে যায়।

বিশ্বব্যাপী সংজ্ঞায়িত সহায়ক ফাংশন প্রয়োজন হিসাবে একটিClassValues ক্ষেত্রের সমস্ত ক্ষেত্র সঞ্চয় করে । এটি তাদের অ্যাক্সেস করার জন্য ফাংশনটি সংজ্ঞায়িত করে । এটি একটি সংক্ষিপ্ত গেট / সেট প্যাটার্ন অনুসরণ করে সুতরাং যদি পাস করা হয় তবে এটি নতুন ভেরিয়েবল মান হিসাবে ব্যবহৃত হবে।_$namevalue

var ClassValues = function (values) {
  return {
    _$: function _$(name, value) {
      if (arguments.length > 1) {
        values[name] = value;
      }

      return values[name];
    }
  };
};

বিশ্বব্যাপী সংজ্ঞায়িত ফাংশনটি Interfaceএকটি একক ফাংশন সহ Valuesএকটি ফেরত দিতে একটি অবজেক্ট এবং একটি অবজেক্ট নেয় যা প্যারামিটারের নাম অনুসারে কোনও ফাংশন সন্ধান করতে পরীক্ষা করে এবং এটিকে স্কোপড অবজেক্ট হিসাবে ডাকে । অতিরিক্ত আর্গুমেন্টগুলি পাস করা হবে ফাংশন অনুরোধে পাস করা হবে।_interface$objnamevalues$

var Interface = function (obj, values, className) {
  var _interface = {
    $: function $(name) {
      if (typeof(obj[name]) === "function") {
        return obj[name].apply(values, Array.prototype.splice.call(arguments, 1));
      }

      throw className + "." + name + " is not a function.";
    }
  };

  //Give values access to the interface.
  values.$ = _interface.$;

  return _interface;
};

নীচের নমুনায়, ফাংশন যা ClassXফলাফল নির্ধারিত হয় । যে কোনও যুক্তি পেতে পারে। কনস্ট্রাক্টরকে কল করার পরে বাহ্যিক কোডটি কী হয়।ClassDefinitionConstructorConstructorInterface

var ClassX = (function ClassDefinition () {
  var Constructor = function Constructor (valA) {
    return Interface(this, ClassValues({ valA: valA }), "ClassX");
  };

  Constructor.prototype.getValA = function getValA() {
    //private value access pattern to get current value.
    return this._$("valA");
  };

  Constructor.prototype.setValA = function setValA(valA) {
    //private value access pattern to set new value.
    this._$("valA", valA);
  };

  Constructor.prototype.isValAValid = function isValAValid(validMessage, invalidMessage) {
    //interface access pattern to call object function.
    var valA = this.$("getValA");

    //timesAccessed was not defined in constructor but can be added later...
    var timesAccessed = this._$("timesAccessed");

    if (timesAccessed) {
      timesAccessed = timesAccessed + 1;
    } else {
      timesAccessed = 1;
    }

    this._$("timesAccessed", timesAccessed);

    if (valA) {
      return "valA is " + validMessage + ".";
    }

    return "valA is " + invalidMessage + ".";
  };

  return Constructor;
}());

প্রোটোটাইপযুক্ত ফাংশনগুলিতে থাকার কোনও মানে নেই Constructor, যদিও আপনি এগুলি কনস্ট্রাক্টর ফাংশন বডিতে সংজ্ঞায়িত করতে পারেন। সমস্ত ফাংশন জনসাধারণের ডলার প্যাটার্ন দিয়ে ডাকা হয় this.$("functionName"[, param1[, param2 ...]])। ব্যক্তিগত মানগুলি ব্যক্তিগত ডলার প্যাটার্ন দ্বারা অ্যাক্সেস করা হয় this._$("valueName"[, replacingValue]);। যেমনটির Interfaceসংজ্ঞা নেই _$, মানগুলি বাহ্যিক বস্তু দ্বারা অ্যাক্সেস করা যায় না। যেহেতু প্রতিটি প্রোটোটাইপড ফাংশন বডি ফাংশনে অবজেক্টে thisসেট করা valuesথাকে $, আপনি যদি কনস্ট্রাক্টর ভাইবাল ফাংশনগুলি সরাসরি কল করেন তবে আপনি ব্যতিক্রম পাবেন; : _ $ / $ প্যাটার্ন চাহিদা prototyped ফাংশন লাশ খুব অনুসরণ করা। নমুনা ব্যবহার নীচে।

var classX1 = new ClassX();
console.log("classX1." + classX1.$("isValAValid", "valid", "invalid"));
console.log("classX1.valA: " + classX1.$("getValA"));
classX1.$("setValA", "v1");
console.log("classX1." + classX1.$("isValAValid", "valid", "invalid"));
var classX2 = new ClassX("v2");
console.log("classX1.valA: " + classX1.$("getValA"));
console.log("classX2.valA: " + classX2.$("getValA"));
//This will throw an exception
//classX1._$("valA");

এবং কনসোল আউটপুট।

classX1.valA is invalid.
classX1.valA: undefined
classX1.valA is valid.
classX1.valA: v1
classX2.valA: v2

: _ $ / $ প্যাটার্ন সম্পূর্ণরূপে prototyped ক্লাসের মূল্যবোধের পূর্ণ গোপনীয়তা পারেন। আমি কখনই এটি ব্যবহার করব কিনা তা আমি জানি না, তবে এর ত্রুটিগুলিও রয়েছে, তবে ওহে, এটি একটি ভাল ধাঁধা ছিল!


0

ES6 WeakMaps

একটি সহজ ভিত্তিক প্যাটার্ন ব্যবহারের ES6 WeakMaps প্রাপ্ত করা সম্ভব বেসরকারী সদস্য ভেরিয়েবল, প্রোটোটাইপ ফাংশন থেকে পৌঁছানো

দ্রষ্টব্য: WeakMaps এর ব্যবহার বর্জ্য সংগ্রাহককে অব্যবহৃত দৃষ্টান্তগুলি সনাক্ত এবং বাতিল করতে দিয়ে মেমরি ফাঁসের বিরুদ্ধে সুরক্ষার গ্যারান্টি দেয় ।

// Create a private scope using an Immediately 
// Invoked Function Expression...
let Person = (function() {

    // Create the WeakMap that will hold each  
    // Instance collection's of private data
    let privateData = new WeakMap();
    
    // Declare the Constructor :
    function Person(name) {
        // Insert the private data in the WeakMap,
        // using 'this' as a unique acces Key
        privateData.set(this, { name: name });
    }
    
    // Declare a prototype method 
    Person.prototype.getName = function() {
        // Because 'privateData' is in the same 
        // scope, it's contents can be retrieved...
        // by using  again 'this' , as  the acces key 
        return privateData.get(this).name;
    };

    // return the Constructor
    return Person;
}());

এই নিদর্শনটির আরও বিশদ বিবরণ এখানে পাওয়া যাবে


-1

আপনার কোডে আপনাকে 3 টি জিনিস পরিবর্তন করতে হবে:

  1. var privateField = "hello"সঙ্গে প্রতিস্থাপন this.privateField = "hello"
  2. প্রোটোটাইপ privateFieldসঙ্গে প্রতিস্থাপন this.privateField
  3. অ প্রোটোটাইপ এছাড়াও প্রতিস্থাপন privateFieldসঙ্গে this.privateField

চূড়ান্ত কোডটি নিম্নলিখিত হবে:

TestClass = function(){
    this.privateField = "hello";
    this.nonProtoHello = function(){alert(this.privateField)};
}

TestClass.prototype.prototypeHello = function(){alert(this.privateField)};

var t = new TestClass();

t.prototypeHello()

this.privateFieldএকটি ব্যক্তিগত ক্ষেত্র হবে না। এটি বাইরে থেকে অ্যাক্সেসযোগ্য:t.privateField
ভি। রুবিনেটি

-2

আপনি কনস্ট্রাক্টরের সংজ্ঞায় একটি প্রোটোটাইপ অ্যাসাইনমেন্ট ব্যবহার করতে পারেন।

চলক প্রোটোটাইপ যুক্ত পদ্ধতিতে দৃশ্যমান হবে তবে ফাংশনগুলির সমস্ত দৃষ্টান্ত একই SHARED ভেরিয়েবলটি অ্যাক্সেস করবে।

function A()
{
  var sharedVar = 0;
  this.local = "";

  A.prototype.increment = function(lval)
  {    
    if (lval) this.local = lval;    
    alert((++sharedVar) + " while this.p is still " + this.local);
  }
}

var a = new A();
var b = new A();    
a.increment("I belong to a");
b.increment("I belong to b");
a.increment();
b.increment();

আমি আশা করি এটি কার্যকর হতে পারে।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.