জাভাস্ক্রিপ্টে গতিশীল গেটার / সেটারগুলি প্রয়োগ করা সম্ভব?


132

এই জাতীয় কিছু করে এমন সম্পত্তি দ্বারা যাদের নাম ইতিমধ্যে জানা আছে তার জন্য কীভাবে গেটার এবং সেটটার তৈরি করতে হয় সে সম্পর্কে আমি সচেতন:

// A trivial example:
function MyObject(val){
    this.count = 0;
    this.value = val;
}
MyObject.prototype = {
    get value(){
        return this.count < 2 ? "Go away" : this._value;
    },
    set value(val){
        this._value = val + (++this.count);
    }
};
var a = new MyObject('foo');

alert(a.value); // --> "Go away"
a.value = 'bar';
alert(a.value); // --> "bar2"

এখন, আমার প্রশ্ন, এই ধরণের ক্যাচ-অল গেটার এবং সেটটারগুলি বাছাই করা কি সম্ভব? যেমন, ইতিমধ্যে সংজ্ঞায়িত নয় এমন কোনও সম্পত্তির নামের জন্য গেটার এবং সেটার তৈরি করুন ।

পিএইচপি তে ধারণাটি সম্ভব __get()এবং __set()যাদু পদ্ধতিগুলি ব্যবহার করে ( এইগুলির জন্য তথ্যের জন্য পিএইচপি ডকুমেন্টেশন দেখুন ), তাই আমি সত্যিই জিজ্ঞাসা করছি এর সাথে জাভাস্ক্রিপ্টের সমতুল্য কি আছে?

বলা বাহুল্য, আমি আদর্শভাবে এমন একটি সমাধান চাই যা ক্রস ব্রাউজারের সাথে সামঞ্জস্যপূর্ণ।


আমি এটি করতে পরিচালিত, কীভাবে এখানে আমার উত্তর দেখুন ।

উত্তর:


216

২০১৩ এবং ২০১৫ আপডেট (২০১১ সালের মূল উত্তরের জন্য নীচে দেখুন) :

এটি ES2015 (ওরফে "ES6") স্পেসিফিকেশন হিসাবে পরিবর্তিত হয়েছে: জাভাস্ক্রিপ্টে এখন প্রক্সি রয়েছে । প্রক্সিগুলি আপনাকে এমন অবজেক্ট তৈরি করতে দেয় যা অন্যান্য অবজেক্টের (প্রকৃত দিকে) প্রকৃত প্রক্সি হয়। এখানে একটি সরল উদাহরণ যা কোনও সম্পত্তি মানকে পুনরুদ্ধার করার জন্য সমস্ত ক্যাপগুলিতে স্ট্রিং করে:

"use strict";
if (typeof Proxy == "undefined") {
    throw new Error("This browser doesn't support Proxy");
}
let original = {
    "foo": "bar"
};
let proxy = new Proxy(original, {
    get(target, name, receiver) {
        let rv = Reflect.get(target, name, receiver);
        if (typeof rv === "string") {
            rv = rv.toUpperCase();
        }
        return rv;
      }
});
console.log(`original.foo = ${original.foo}`); // "original.foo = bar"
console.log(`proxy.foo = ${proxy.foo}`);       // "proxy.foo = BAR"

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

ইন getহ্যান্ডলার ফাংশনের আর্গুমেন্ট তালিকা:

  • targetবস্তুটি কি প্রক্সিড হয় ( originalআমাদের ক্ষেত্রে)।
  • name (অবশ্যই) সম্পত্তি পুনরুদ্ধারের নাম, যা সাধারণত স্ট্রিং হয় তবে এটি একটি চিহ্নও হতে পারে।
  • receiverthisসম্পত্তি হ'ল ডেটা প্রপার্টিটির পরিবর্তে অ্যাক্সেসর হলে সেই অবজেক্টটি গেটর ফাংশন হিসাবে ব্যবহার করা উচিত । স্বাভাবিক যদি এই প্রক্সি বা কিছু তা থেকে উত্তরাধিকারী, কিন্তু এটা যে করতে কিছু হওয়ার পর থেকে ফাঁদ দ্বারা আলোড়ন সৃষ্টি করা যেতে পারে Reflect.get

এটি আপনাকে যে সমস্ত ক্যাচ-অল গেটর এবং সেটার বৈশিষ্ট্যটি চায় তা দিয়ে একটি বস্তু তৈরি করতে দেয়:

"use strict";
if (typeof Proxy == "undefined") {
    throw new Error("This browser doesn't support Proxy");
}
let obj = new Proxy({}, {
    get(target, name, receiver) {
        if (!Reflect.has(target, name)) {
            console.log("Getting non-existent property '" + name + "'");
            return undefined;
        }
        return Reflect.get(target, name, receiver);
    },
    set(target, name, value, receiver) {
        if (!Reflect.has(target, name)) {
            console.log(`Setting non-existent property '${name}', initial value: ${value}`);
        }
        return Reflect.set(target, name, value, receiver);
    }
});

console.log(`[before] obj.foo = ${obj.foo}`);
obj.foo = "bar";
console.log(`[after] obj.foo = ${obj.foo}`);

উপরের ফলাফল:

অস্তিত্বের সম্পত্তি 'ফু' পাওয়া
[আগে] obj.foo = অপরিবর্তিত
অস্তিত্বের সম্পত্তি 'foo' সেট করা হচ্ছে, প্রাথমিক মান: বার
[পরে] obj.foo = বার bar

আমরা কীভাবে "অস্তিত্বহীন" বার্তাটি পাই fooতা যখন আমরা উপস্থিত নেই তখন পুনরুদ্ধার করার চেষ্টা করি এবং আবার কখন এটি তৈরি করি, তবে তার পরে নয় Note


২০১১ থেকে উত্তর (২০১৩ এবং ২০১৫ আপডেটের জন্য উপরে দেখুন) :

না, জাভাস্ক্রিপ্টে ক্যাচ-অল প্রপার্টি বৈশিষ্ট্য নেই। আপনি যে অ্যাকসেসর সিনট্যাক্সটি ব্যবহার করছেন তা অনুচ্ছেদটির 11.1.5 অনুচ্ছেদে আচ্ছাদিত এবং কোনও ওয়াইল্ডকার্ড বা এর মতো কিছু সরবরাহ করে না।

আপনি অবশ্যই এটি করার জন্য কোনও ফাংশন বাস্তবায়ন করতে পারেন, তবে আমি অনুমান করছি আপনি সম্ভবত এটির f = obj.prop("foo");চেয়ে f = obj.foo;এবং obj.prop("foo", value);তার চেয়ে বেশি ব্যবহার করতে চান না obj.foo = value;(যা অজানা সম্পত্তি পরিচালনা করতে ফাংশনের জন্য প্রয়োজনীয় হবে)।

এফডাব্লুআইডাব্লু, গিটার ফাংশন (আমি সেটার যুক্তির সাথে বিরক্ত করিনি) এরকম কিছু দেখবে:

MyObject.prototype.prop = function(propName) {
    if (propName in this) {
        // This object or its prototype already has this property,
        // return the existing value.
        return this[propName];
    }

    // ...Catch-all, deal with undefined property here...
};

তবে আবারও, আমি ভাবতে পারি না যে আপনি কীভাবে এটি করতে চান তা কীভাবে আপনি কীভাবে এটি ব্যবহার করেন তা পরিবর্তনের কারণে use


1
সেখানে বিকল্প নেই Proxy: Object.defineProperty()। আমি আমার নতুন উত্তরে বিশদটি রেখেছি ।
অ্যান্ড্রু

@ অ্যান্ড্রু - আমি ভয় করি আপনি প্রশ্নটি ভুলভাবে পড়েছেন, আপনার উত্তর সম্পর্কে আমার মন্তব্য দেখুন।
টিজে ক্রোডার

4

নিম্নলিখিত এই সমস্যার মূল পদ্ধতির হতে পারে:

var obj = {
  emptyValue: null,
  get: function(prop){
    if(typeof this[prop] == "undefined")
        return this.emptyValue;
    else
        return this[prop];
  },
  set: function(prop,value){
    this[prop] = value;
  }
}

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

//To set a property
obj.set('myProperty','myValue');

//To get a property
var myVar = obj.get('myProperty');

সম্পাদনা করুন: আমি প্রস্তাবিত কিসের উপর ভিত্তি করে একটি উন্নত, আরও অবজেক্ট-ভিত্তিক পদ্ধতির নিম্নলিখিতটি হল:

function MyObject() {
    var emptyValue = null;
    var obj = {};
    this.get = function(prop){
        return (typeof obj[prop] == "undefined") ? emptyValue : obj[prop];
    };
    this.set = function(prop,value){
        obj[prop] = value;
    };
}

var newObj = new MyObject();
newObj.set('myProperty','MyValue');
alert(newObj.get('myProperty'));

আপনি এটি এখানে কাজ দেখতে পারেন ।


এটি কাজ করে না। আপনি সম্পত্তিটির নাম উল্লেখ না করে কোনও গেটর সংজ্ঞায়িত করতে পারবেন না।
জন কুরলাক

@JohnKurlak এই jsFiddle চেক করুন: jsfiddle.net/oga7ne4x এটি কাজ করে। আপনাকে কেবল সম্পত্তিটির নাম স্ট্রিং হিসাবে পাস করতে হবে।
clami219

3
আহ, স্পষ্ট করার জন্য ধন্যবাদ। আমি ভেবেছিলাম আপনি গেট () / সেট () ভাষা বৈশিষ্ট্যটি ব্যবহার করার চেষ্টা করছেন, নিজের গেট () / সেট () লিখছেন না। আমি এখনও এই সমাধানটি পছন্দ করি না কারণ এটি সত্যিকার অর্থে মূল সমস্যাটি সমাধান করে না।
জন কুর্লাক 21

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

@ জনকুরলাক দেখুন এখন যদি এটি আরও ভাল দেখায়! :)
clami219

0

মুখবন্ধ:

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

(পিএস আমি Proxyসম্প্রতি লিনাক্সে ফায়ারফক্সে পুরোপুরি পরীক্ষা করে দেখেছি এবং এটি বেশ সক্ষম বলে মনে করেছি, তবে কিছুটা বিভ্রান্তিকর / কাজ করা এবং সঠিকভাবে কাজ করাও কঠিন difficult আরও গুরুত্বপূর্ণ, আমি এটি বেশ ধীর হয়েও পেয়েছি (কমপক্ষে আজকাল জাভাস্ক্রিপ্ট কীভাবে অনুকূলিত হয়েছে এর সাথে সম্পর্কযুক্ত) - আমি ডেকা-গুণগুলি আরও ধীরের অঞ্চলে কথা বলছি))


গতিশীলভাবে তৈরি গেটারস এবং সেটটারগুলি বিশেষত কার্যকর করতে আপনি ব্যবহার করতে পারেন Object.defineProperty()বা করতে পারেন Object.defineProperties()। এটিও বেশ দ্রুত।

সংক্ষিপ্তসারটি হ'ল আপনি এমন কোনও জিনিসে গেটর এবং / অথবা সেটারকে সংজ্ঞায়িত করতে পারেন:

let obj = {};
let val = 0;
Object.defineProperty(obj, 'prop', { //<- This object is called a "property descriptor".
  //Alternatively, use: `get() {}`
  get: function() {
    return val;
  },
  //Alternatively, use: `set(newValue) {}`
  set: function(newValue) {
    val = newValue;
  }
});

//Calls the getter function.
console.log(obj.prop);
let copy = obj.prop;
//Etc.

//Calls the setter function.
obj.prop = 10;
++obj.prop;
//Etc.

এখানে কয়েকটি বিষয় লক্ষণীয়:

  • আপনি ব্যবহার করতে পারবেন না valueসম্পত্তি বর্ণনাকারী (সম্পত্তি না দিয়ে একযোগে উপরে দেখানো হয়নি) getএবং / অথবা set; ডক্স থেকে:

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

  • সুতরাং, তুমি মনে রাখবেন করবেন যে আমি একটি নির্মিত valসম্পত্তি বাহিরে এর Object.defineProperty()কল / সম্পত্তি বর্ননাকারী। এটি মানক আচরণ।
  • ত্রুটি অনুযায়ী এখানে , সেট না writableকরার trueসম্পত্তি বর্ণনাকারী যদি আপনি ব্যবহার getবা set
  • আপনি সেটিংটি বিবেচনা করতে চাইতে পারেন configurableএবং enumerableতবে আপনার পরে কী হবে তার উপর নির্ভর করে; ডক্স থেকে:

    কনফিগার

    • true যদি এবং কেবলমাত্র এই সম্পত্তি বর্ণনাকারীর ধরণ পরিবর্তন করা যেতে পারে এবং যদি সম্পত্তিটি সম্পর্কিত অবজেক্ট থেকে মুছে ফেলা যায়।

    • মিথ্যা ডিফল্ট।


    গণনীয়

    • true যদি এবং শুধুমাত্র যদি এই সম্পত্তি সম্পর্কিত অবজেক্টের বৈশিষ্ট্যগুলির গণনার সময় প্রদর্শিত হয়।

    • মিথ্যা ডিফল্ট।


এই নোটে, এগুলিও আগ্রহী হতে পারে:

  • Object.getOwnPropertyNames(obj): একটি অবজেক্টের সমস্ত সম্পত্তি এমনকি অ-গণনাযোগ্যও পায় (আফাইক এটি করার একমাত্র উপায়!)।
  • Object.getOwnPropertyDescriptor(obj, prop): একটি বস্তুর সম্পত্তি বর্ণনাকারী, যে বস্তুটি Object.defineProperty()উপরের দিকে প্রেরণ করা হয়েছিল তা পায় ।
  • obj.propertyIsEnumerable(prop);: একটি নির্দিষ্ট বস্তুর উদাহরণে পৃথক সম্পত্তির জন্য, নির্দিষ্ট সম্পত্তিটি গণনাযোগ্য কিনা তা নির্ধারণের জন্য এই ফাংশনটিকে অবজেক্টের উদাহরণে কল করুন।

2
আমি ভয় করি আপনি প্রশ্নটি ভুলভাবে পড়েছেন। ওপি বিশেষত পিএইচপি এবং এর মতো সমস্ত ধরার জন্য বলেছিল । কেস পরিচালনা করে না প্রশ্ন থেকে: "অর্থাৎ, যে কোনও সম্পত্তির নাম ইতিমধ্যে সংজ্ঞায়িত হয়নি তার জন্য গেটার এবং সেটটার তৈরি করুন " " (তাদের জোর)। অগ্রিম বৈশিষ্ট্য সংজ্ঞায়িত ওপি যা চেয়েছিল তা করার একমাত্র উপায় হ'ল প্রক্সি। __get__setdefinePropertydefineProperty
টিজে ক্রোডার

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

@ অ্যান্ড্রু যখন আমি এই প্রশ্নটি ২০১১ সালে ফিরে জিজ্ঞাসা করি তখন আমার মনে যে ব্যবহার-মামলা ছিল তা ছিল একটি লাইব্রেরি যা কোনও অবজেক্ট ফিরিয়ে দিতে পারে যার উপর ব্যবহারকারী obj.whateverPropertyএমনভাবে ফোন করতে পারে যে গ্রন্থাগারটি জেনেরিক গেটারের সাথে বাধা দিতে পারে এবং সম্পত্তিটির নাম দেওয়া যেতে পারে ব্যবহারকারী অ্যাক্সেস করার চেষ্টা করেছে। সুতরাং 'ক্যাচ-অল গেটারস এবং সিটার' এর প্রয়োজনীয়তা।
দাইস্কোগ

-6
var x={}
var propName = 'value' 
var get = Function("return this['" + propName + "']")
var set = Function("newValue", "this['" + propName + "'] = newValue")
var handler = { 'get': get, 'set': set, enumerable: true, configurable: true }
Object.defineProperty(x, propName, handler)

এটা আমার জন্য কাজ করে


13
এর Function()মতো ব্যবহার করাও ব্যবহারের মতো eval। পরামিতি হিসাবে সরাসরি ফাংশন রাখুন defineProperty। অথবা, যদি কোনও কারণে আপনি গতিশীলভাবে তৈরির জন্য জোর দিয়ে থাকেন getএবং set, তারপরে একটি হাই-অর্ডার ফাংশন ব্যবহার করুন যা ফাংশনটি তৈরি করে এবং এটি ফেরত দেয়, যেমনvar get = (function(propName) { return function() { return this[propName]; };})('value');
ক্রিস-এল
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.