سؤال

حسنًا، حاولت معرفة هل هذا ممكن بأي شكل من الأشكال.هنا الكود:

a=function(text)
{
   var b=text;
   if (!arguments.callee.prototype.get)
      arguments.callee.prototype.get=function()
    {
         return b;
    }
    else
      alert('already created!');
}

var c=new a("test");  // creates prototype instance of getter
var d=new a("ojoj");  // alerts already created
alert(c.get())        // alerts test 
alert(d.get())        // alerts test from context of creating prototype function :(

كما ترون حاولت إنشاء نموذج أولي.لماذا؟حسنًا إذا كتبت شيئًا مثل هذا:

a=function(text)
{
    var b=text;
    this.getText=function(){ return b}
}

...كل شيء يجب أن يكون على ما يرام..ولكن في الواقع في كل مرة أقوم فيها بإنشاء كائن - أقوم بإنشاء وظيفة getText التي تستخدم الذاكرة.أرغب في الحصول على وظيفة نموذجية واحدة موجودة في الذاكرة من شأنها أن تفعل الشيء نفسه ...أيه أفكار؟

يحرر:

لقد جربت الحل الذي قدمه كريستوف، ويبدو أنه الحل الوحيد المعروف في الوقت الحالي.يحتاج إلى تذكر معلومات المعرف لاسترداد القيمة من السياق، ولكن الفكرة بأكملها جيدة بالنسبة لي :) المعرف هو شيء واحد فقط يجب تذكره، وكل شيء آخر يمكن تخزينه مرة واحدة في الذاكرة.في الواقع، يمكنك تخزين الكثير من الأعضاء الخاصين بهذه الطريقة، واستخدام معرف واحد فقط في أي وقت.في الواقع هذا يرضيني :) (إلا إذا حصل شخص ما على فكرة أفضل).

someFunc = function()
{
  var store = new Array();
  var guid=0;
  var someFunc = function(text)
  {
    this.__guid=guid;
    store[guid++]=text;
  }

  someFunc.prototype.getValue=function()
  {
    return store[this.__guid];
  }

  return someFunc;
}()

a=new someFunc("test");
b=new someFunc("test2");

alert(a.getValue());
alert(b.getValue());
هل كانت مفيدة؟

المحلول

تقليديًا، لم توفر جافا سكريبت آلية لإخفاء الممتلكات ("الأعضاء الخاصون").

نظرًا لأن JavaScript يتم تحديد نطاقه بشكل معجمي، يمكنك دائمًا محاكاة ذلك على مستوى كل كائن باستخدام وظيفة المنشئ كإغلاق على "الأعضاء الخاصين" وتحديد الأساليب الخاصة بك في المنشئ، ولكن هذا لن ينجح مع الأساليب المحددة في خاصية النموذج الأولي للمنشئ.

بالطبع هناك طرق للتغلب على هذه المشكلة، لكن لا أنصح بها:

Foo = (function() {
    var store = {}, guid = 0;

    function Foo() {
        this.__guid = ++guid;
        store[guid] = { bar : 'baz' };
    }

    Foo.prototype.getBar = function() {
        var privates = store[this.__guid];
        return privates.bar;
    };

    Foo.prototype.destroy = function() {
        delete store[this.__guid];
    };

    return Foo;
})();

سيؤدي هذا إلى تخزين الخصائص "الخاصة" في كائن آخر منفصل عن كائنك Foo مثال.تأكد من الاتصال destroy() بعد الانتهاء من استخدام الكائن:وإلا، فقد قمت للتو بإنشاء تسرب للذاكرة.


تحرير 2015-12-01: يجعل ECMAScript6 المتغيرات المحسنة التي لا تتطلب تدميرًا يدويًا للكائنات ممكنة، على سبيل المثال باستخدام ملف خريطة ضعيفة أو يفضل أ رمز, ، وتجنب الحاجة إلى متجر خارجي تمامًا:

var Foo = (function() {
    var bar = Symbol('bar');

    function Foo() {
        this[bar] = 'baz';
    }

    Foo.prototype.getBar = function() {
        return this[bar];
    };

    return Foo;
})();

نصائح أخرى

وطرق على النموذج لا يمكن الوصول إلى أعضاء "الخاص" لأنها موجودة في جافا سكريبت. كنت بحاجة الى بعض النوع من استرجاع الامتيازات. منذ كنت معلنا get حيث يمكن أن نرى مفرداتيا b، فإنه سيعود دائما ما b كان على الخلق.

بعد أن استلهمت أفكار كريستوف بشكل كبير، توصلت إلى مفهوم معدل قليلاً يوفر بعض التحسينات.مرة أخرى، هذا الحل مثير للاهتمام، ولكن لا يوصى به بالضرورة.تشمل هذه التحسينات:

  • لم تعد بحاجة إلى إجراء أي إعداد في المُنشئ
  • تمت إزالة الحاجة إلى تخزين GUID عام في المثيلات
  • وأضاف بعض السكر النحوي

تتمثل الحيلة هنا في استخدام كائن المثيل نفسه كمفتاح للوصول إلى الكائن الخاص المرتبط.عادةً لا يكون هذا ممكنًا مع الكائنات العادية نظرًا لأن مفاتيحها يجب أن تكون عبارة عن سلاسل.ومع ذلك، تمكنت من تحقيق ذلك باستخدام حقيقة أن التعبير ({} === {}) عائدات false.وبعبارة أخرى عامل المقارنة يستطيع التمييز بين مثيلات الكائن الفريدة.

باختصار، يمكننا استخدام مصفوفتين للحفاظ على المثيلات والكائنات الخاصة المرتبطة بها:

Foo = (function() {
    var instances = [], privates = [];

    // private object accessor function
    function _(instance) {
        var index = instances.indexOf(instance), privateObj;

        if(index == -1) {
            // Lazily associate instance with a new private object
            instances.push(instance);
            privates.push(privateObj = {});
        }
        else {
            // A privateObject has already been created, so grab that
            privateObj = privates[index];
        }
        return privateObj;
    }

    function Foo() {
        _(this).bar = "This is a private bar!";
    }

    Foo.prototype.getBar = function() {
        return _(this).bar;
    };

    return Foo;
})();

ستلاحظ _ وظيفة أعلاه.هذه هي وظيفة الوصول للاستيلاء على الكائن الخاص.إنه يعمل بتكاسل، لذلك إذا قمت باستدعائه بمثيل جديد، فسوف يقوم بإنشاء كائن خاص جديد بسرعة.

إذا كنت لا ترغب في تكرار _ كود لكل فئة، يمكنك حل هذه المشكلة عن طريق تغليفها داخل وظيفة المصنع:

function createPrivateStore() {
    var instances = [], privates = [];

    return function (instance) {
        // Same implementation as example above ...
    };
}

يمكنك الآن تقليله إلى سطر واحد فقط لكل فصل:

var _ = createPrivateStore();

مرة أخرى، عليك أن تكون حذرين للغاية باستخدام هذا الحل كما هو يستطيع إنشاء تسرب للذاكرة إذا لم تقم بتنفيذ واستدعاء وظيفة التدمير عند الضرورة.

ومع المتصفحات الحديثة تتبنى بعض التكنولوجيات ES6، يمكنك استخدام WeakMap للالتفاف على المشكلة GUID. هذا وتعمل في IE11 وأعلاه:

// Scope private vars inside an IIFE
var Foo = (function() { 
    // Store all the Foos, and garbage-collect them automatically
    var fooMap = new WeakMap();

    var Foo = function(txt) { 
        var privateMethod = function() { 
            console.log(txt); 
        };
        // Store this Foo in the WeakMap
        fooMap.set(this, {privateMethod: privateMethod}); 
    } 

    Foo.prototype = Object.create(Object.prototype); 
    Foo.prototype.public = function() { 
        fooMap.get(this).p(); 
     } 
     return Foo; 
 }());

 var foo1 = new Foo("This is foo1's private method");
 var foo2 = new Foo("This is foo2's private method");
 foo1.public(); // "This is foo1's private method"
 foo2.public(); // "This is foo2's private method"
سوف

وWeakMap تقم بتخزين ما يشير إلى أي Foo بعد يحصل حذفه أو تقع خارج النطاق، ونظرا لأنه يستخدم ككائنات مفاتيح، لا تحتاج إلى إرفاق المعرفات الفريدة العمومية وجوه الخاص بك.

أنا شخصياً لا أحب الحل مع الدليل، لأنه يجبر المطور على الإعلان عنه بالإضافة إلى المتجر وزيادته في المُنشئ.في تطبيقات جافا سكريبت الكبيرة، قد ينسى مطورو التطبيقات القيام بذلك وهو أمر معرض للخطأ تمامًا.

تعجبني إجابة بيتر إلى حد كبير لأنه يمكنك الوصول إلى الأعضاء الخاصين باستخدام السياق (هذا).ولكن الشيء الوحيد الذي يزعجني كثيرًا هو حقيقة أن الوصول إلى الأعضاء الخاصين يتم بطريقة معقدة للغاية.في الواقع، العثور على فهرس كائن في المصفوفة هو خوارزمية خطية.ضع في اعتبارك أنك تريد استخدام هذا النمط لكائن تم إنشاء مثيل له 10000 مرة.ثم يمكنك التكرار خلال 10000 مثيل في كل مرة تريد فيها الوصول إلى عضو خاص.

من أجل الوصول إلى المتاجر الخاصة في درجة تعقيد o(1)، لا توجد طريقة أخرى سوى استخدام الأدلة.ولكن لكي لا أزعج إعلان الدليل والزيادة ومن أجل استخدام السياق للوصول إلى المتجر الخاص، قمت بتعديل نمط مصنع بيترز على النحو التالي:

createPrivateStore = function () {
var privates = {}, guid = 0;

return function (instance) {
    if (instance.__ajxguid__ === undefined) {
        // Lazily associate instance with a new private object
        var private_obj = {};
        instance.__ajxguid__ = ++guid;
        privates[instance.__ajxguid__] = private_obj;
        return private_obj;
    }

    return privates[instance.__ajxguid__];
}

}

الحيلة هنا هي أن نعتبر أن الكائنات التي لا تحتوي على com.ajxguid لم يتم التعامل مع الممتلكات بعد.في الواقع، يمكن للمرء ضبط الخاصية يدويًا قبل الوصول إلى المتجر لأول مرة، لكن أعتقد أنه لا يوجد حل سحري.

وأعتقد الخصوصية الحقيقية هي مبالغا فيه. الخصوصية الافتراضية هي كل ما هو مطلوب. أعتقد أن استخدام _privateIdentifier هو خطوة في الاتجاه الصحيح ولكن ليس بعيدا بما فيه الكفاية لأنك لا يزال قدم مع قائمة بجميع _privateIdentifiers في بالنوافذ التحسس. خطوة أخرى وأفضل هو خلق كائن في وظيفة النموذج و / أو منشئ لفصل الحقول وأساليب خاصة عمليا للخروج من مشهد مثل ذلك:

  // Create the object
  function MyObject() {}

  // Add methods to the prototype
  MyObject.prototype = {

    // This is our public method
    public: function () {
      console.log('PUBLIC method has been called');
    },

    // This is our private method tucked away inside a nested privacy object called x
    x: {
      private: function () {
        console.log('PRIVATE method has been called');
      }
    },

  }

// Create an instance of the object
var mo = new MyObject(); 

والآن عندما يكتب المبرمج "مو". والتحسس تظهر فقط في وظيفة عامة و "س". حتى لا تظهر جميع أعضاء القطاع الخاص ولكن مخفية وراء "س" مما يجعلها أكثر المرجح لالمبرمج للاتصال عن طريق الخطأ عضوا الخاص لأنها سوف تضطر إلى الخروج من طريقهم واكتب "mo.x." لرؤية أعضاء من القطاع الخاص. هذا الأسلوب أيضا يتجنب التحسس سرد من أن تشوش مع أسماء الأعضاء خاصة متعددة، إخفائها وراء كل بند واحد "س".

وأنا أعرف هذا الموضوع هو حقا حقا القديمة الآن، ولكن يعتقد أن هذا الحل قد يكون من مصلحة أحد المارة:

const Immutable = function ( val ) {
    let _val = val;

    this.$ = {
        _resolve: function () {
            return _val;
        }
    };
};
Immutable.prototype = {
    resolve: function () {
        return this.$._resolve();
    }
};

ويختبئ في الأساس داخلي <م> _val من كونها التلاعب بها، وجعل مثيل هذا الكائن غير قابل للتغيير.

ولقد خلق مكتبة جديدة لتمكين طرق خاصة على سلسلة النموذج. https://github.com/TremayneChrist/ProtectJS

مثال:

var MyObject = (function () {

  // Create the object
  function MyObject() {}

  // Add methods to the prototype
  MyObject.prototype = {

    // This is our public method
    public: function () {
      console.log('PUBLIC method has been called');
    },

    // This is our private method, using (_)
    _private: function () {
      console.log('PRIVATE method has been called');
    }
  }

  return protect(MyObject);

})();

// Create an instance of the object
var mo = new MyObject();

// Call its methods
mo.public(); // Pass
mo._private(); // Fail
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top