জাভাস্ক্রিপ্টে নতুন অপারেটর এড়ানো - আরও ভাল উপায়


16

সতর্কতা: এটি একটি দীর্ঘ পোস্ট।

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

এর চারপাশের সহজ উপায় হ'ল ...

function Make(x) {
  if ( !(this instanceof arguments.callee) )
  return new arguments.callee(x);

  // do your stuff...
}

তবে, আমার পরিবর্তনশীল নংটি গ্রহণ করার জন্য এটি দরকার। এই মত যুক্তি, ...

m1 = Make();
m2 = Make(1,2,3);
m3 = Make('apple', 'banana');

প্রথম তাত্ক্ষণিক সমাধানটি এর মতো 'প্রয়োগ' পদ্ধতি বলে মনে হচ্ছে ...

function Make() {
  if ( !(this instanceof arguments.callee) )
    return new arguments.callee.apply(null, arguments);

  // do your stuff
}

যদিও ভুল - নতুন বস্তু পাস করা হয়েছে applyনা আমাদের কন্সট্রাকটর করার পদ্ধতি এবং arguments.callee

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

প্রথম - eval()গতিশীলভাবে জাভাস্ক্রিপ্ট কোড তৈরি করতে ব্যবহার করুন যা নির্মাণকারীকে কল করে calls

function Make(/* ... */) {
  if ( !(this instanceof arguments.callee) ) {
    // collect all the arguments
    var arr = [];
    for ( var i = 0; arguments[i]; i++ )
      arr.push( 'arguments[' + i + ']' );

    // create code
    var code = 'new arguments.callee(' + arr.join(',') + ');';

    // call it
    return eval( code );
  }

  // do your stuff with variable arguments...
}

দ্বিতীয় - প্রতিটি বস্তুর __proto__সম্পত্তি রয়েছে যা তার প্রোটোটাইপ অবজেক্টের 'গোপন' লিঙ্ক। ভাগ্যক্রমে এই সম্পত্তি লিখনযোগ্য।

function Make(/* ... */) {
  var obj = {};

  // do your stuff on 'obj' just like you'd do on 'this'
  // use the variable arguments here

  // now do the __proto__ magic
  // by 'mutating' obj to make it a different object

  obj.__proto__ = arguments.callee.prototype;

  // must return obj
  return obj;
}

তৃতীয় - এটি দ্বিতীয় সমাধানের অনুরূপ।

function Make(/* ... */) {
  // we'll set '_construct' outside
  var obj = new arguments.callee._construct();

  // now do your stuff on 'obj' just like you'd do on 'this'
  // use the variable arguments here

  // you have to return obj
  return obj;
}

// now first set the _construct property to an empty function
Make._construct = function() {};

// and then mutate the prototype of _construct
Make._construct.prototype = Make.prototype;

  • eval সমাধান আনাড়ি বলে মনে হয় এবং "অশুভ বিভাজন" এর সমস্ত সমস্যার সাথে আসে।

  • __proto__ সমাধানটি মানহীন এবং "গ্রেট ব্রাউজার অফ মিছরি" এটি সম্মান করে না।

  • তৃতীয় সমাধান অত্যধিক জটিল বলে মনে হচ্ছে।

তবে উপরোক্ত তিনটি সমাধানের সাহায্যে আমরা এরকম কিছু করতে পারি, যা আমরা অন্যথায় পারি না ...

m1 = Make();
m2 = Make(1,2,3);
m3 = Make('apple', 'banana');

m1 instanceof Make; // true
m2 instanceof Make; // true
m3 instanceof Make; // true

Make.prototype.fire = function() {
  // ...
};

m1.fire();
m2.fire();
m3.fire();

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

-- হালনাগাদ --

কেউ কেউ "শুধু একটি ত্রুটি নিক্ষেপ" বলেছেন। আমার প্রতিক্রিয়াটি হ'ল: আমরা ১০++ কনস্ট্রাক্টর সহ একটি ভারী অ্যাপ্লিকেশন করছি এবং আমি মনে করি যে যদি প্রতিটি নির্মাতা কনসোলটিতে ত্রুটি বার্তা না ছুঁড়ে দিয়ে "ভুল করে" ভুলটি পরিচালনা করতে পারে তবে এটি আরও বেশি মজাদার হতে চাই।


2
বা স্ট্যাকট্রেসটি পরীক্ষা করা খারাপ হলে কেবল একটি ত্রুটি ফেলে দিন এবং আপনি কোডটি ঠিক করতে পারেন
র‌্যাচেট ফ্রেইক

2
আমি মনে করি স্ট্যাক ওভারফ্লো বা কোড পর্যালোচনায় এই প্রশ্নটি আরও ভাল জিজ্ঞাসা করা হবে । এটি ধারণাগত প্রশ্নের চেয়ে বেশিরভাগ কোডকেন্দ্রিক বলে মনে হচ্ছে।
অ্যাডাম লিয়ার

1
@ গ্রিনজিট এর পরিবর্তে একটি ত্রুটি নিক্ষেপ করে একটি জ্লসিন্ট ব্যবহার করুন। এটি আপনাকে সতর্ক করে দেবে যদি আপনি Make()এটি না করে করেন newকারণ মেক মূলধন হয় এবং সুতরাং এটি এটি
নির্মাতা হিসাবে

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

5
হাস্যকরভাবে, প্রোগ্রামার ভুলগুলি 'স্মার্টলি' হ্যান্ডেল করার চেষ্টা করা জাভাস্ক্রিপ্টের অনেকগুলি 'খারাপ অংশ' এর জন্য নিজেই দায়ী।
ড্যানিয়েল প্র্যাট

উত্তর:


19

প্রথমে arguments.calleeকঠোরভাবে ES5 এ অবচয় করা হয়েছে যাতে আমরা এটি ব্যবহার করি না। আসল সমাধান বরং সহজ।

আপনি কিছু ব্যবহার করবেন না new

var Make = function () {
  if (Object.getPrototypeOf(this) !== Make.prototype) {
    var o = Object.create(Make.prototype);
    o.constructor.apply(o, arguments);
    return o;
  }
  ...
}

ঠিক ডানায় পাছায় একটা ব্যথা হচ্ছে?

চেষ্টা enhance

var Make = enhance(function () {
  ...
});

var enhance = function (constr) {
  return function () {
    if (Object.getPrototypeOf(this) !== constr.prototype) {
      var o = Object.create(constr.prototype);
      constr.apply(o, arguments);
      return o;
    }
    return constr.apply(this, arguments);
  }
}

এখন অবশ্যই এটির জন্য ES5 দরকার, তবে প্রত্যেকে ES5-shim ব্যবহার করে ?

আপনি আগ্রহী হতে পারে বিকল্প জেএস ওও নিদর্শনগুলিতেও

সরাইয়া হিসাবে আপনি বিকল্প দুটি প্রতিস্থাপন করতে পারেন

var Make = function () {
  var that = Object.create(Make.prototype);
  // use that 

  return that;
}

আপনি যদি নিজের ইএস 5 Object.createশিম চান তবে এটি সত্যিই সহজ

Object.create = function (proto) {
  var dummy = function () {};
  dummy.prototype = proto;
  return new dummy;
};

হ্যাঁ সত্য - তবে এখানে সমস্ত যাদু রয়েছে Object.create। প্রি ES5 সম্পর্কে কি? Object.createইএস 5 -শিম দুবাইস হিসাবে তালিকাবদ্ধ করে।
বিশ্বাসঘাতক

@ গ্রিনজিট যদি আপনি এটি আবার পড়েন তবে ইএস 5 শিম অবজেক্ট.ক্রিয়েটের দ্বিতীয় আর্গুমেন্টটিকে দ্বিবিউস বলে। প্রথমটি ঠিক আছে।
রায়নস

1
হ্যাঁ আমি এটা পড়েছি। এবং আমি মনে করি (আইএফ) তারা __proto__সেখানে কোনও ধরণের জিনিস ব্যবহার করছে তবে আমরা এখনও একই পয়েন্টে রয়েছি। কারণ ES5 পূর্বের প্রোটোটাইপকে রূপান্তরিত করার সহজ উপায় নেই। তবে যাইহোক, আপনার সমাধানটি সবচেয়ে মার্জিত এবং এগিয়ে খুঁজছেন বলে মনে হচ্ছে। তার জন্য +1। (আমার ভোটদানের সীমাটি পৌঁছে গেছে)
বিশ্বাসঘাতক

1
ধন্যবাদ @ পিএসআর। এবং রেইনোস আপনার শিমটি Object.createআমার তৃতীয় সমাধানের চেয়ে কম তবে জটিল এবং আমার চেয়ে অবশ্যই ভাল দেখাচ্ছে।
বিশ্বাসঘাতক

37

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

এর সুস্পষ্ট উত্তরটি ভুলে যাবেন না new

আপনি ভাষার গঠন এবং অর্থ পরিবর্তন করছেন।

যা আমার মতে এবং আপনার কোডের ভবিষ্যতের রক্ষণাবেক্ষণকারীদের পক্ষে, এটি একটি ভয়াবহ ধারণা।


9
+1 কারওর খারাপ কোডিং অভ্যাসের চারপাশে কোনও ভাষা র‌্যাংগল করা বিশ্রী বলে মনে হয়। অবশ্যই কিছু সিনট্যাক্স হাইলাইট / চেক-ইন নীতি বাগ-প্রবণ নিদর্শন / সম্ভাব্য টাইপগুলি এড়িয়ে চলতে পারে।
Stoive

যদি আমি এমন একটি লাইব্রেরি পাই যেখানে সমস্ত কন্সট্রাক্টর আপনি ব্যবহার করেন newবা না দেখেন সেদিকে খেয়াল রাখে না, আমি আরও বেশি রক্ষণাবেক্ষণের সন্ধান করব।
জ্যাক

@ জ্যাক, তবে বাগগুলি খুঁজে পেতে এটি আরও কঠোর এবং সূক্ষ্মতার পরিচয় দেবে। জাভাস্ক্রিপ্ট "কেয়ারিং নয়" এর ফলে ঘটে যাওয়া সমস্ত বাগের চারপাশে কেবলমাত্র যদি আপনি ;শেষের বিবৃতি অন্তর্ভুক্ত করেন তবে । (স্বয়ংক্রিয় সেমিকোলন সন্নিবেশ)
ক্যাফগিক

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

14

সবচেয়ে সহজ সমাধানটি কেবল মনে রাখা newএবং এটি ভুলে গিয়েছিল তা স্পষ্ট করে দেওয়ার জন্য একটি ত্রুটি নিক্ষেপ করা।

if (Object.getPrototypeOf(this) !== Make.prototype) {
    throw new Error('Remember to call "new"!');
}

আপনি যাই করুন না কেন, ব্যবহার করবেন না eval। আমি অ-মানক বৈশিষ্ট্যগুলি __proto__বিশেষত ব্যবহার করা থেকে বিরত হই কারণ তারা মানহীন এবং তাদের কার্যকারিতা পরিবর্তন হতে পারে।


.__proto__নিশ্চয়ই এটিকে শয়তান এড়িয়ে চলুন
রায়নোস

3

আমি আসলে এই সম্পর্কে একটি পোস্ট লিখেছি। http://js-bits.blogspot.com/2010/08/constructors-without-using-new.html

function Ctor() {
    if (!(this instanceof Ctor) {
        return new Ctor(); 
    }
    // regular construction code
}

এবং আপনি এমনকি এটি সাধারণকরণ করতে পারেন যাতে আপনাকে এটি প্রতিটি নির্মাণকারীর শীর্ষে যুক্ত করতে হবে না। আপনি আমার পোস্ট পরিদর্শন করে যে দেখতে পারেন

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


সম্ভাব্যভাবে লুকানো ত্রুটি: যদি আমার var x = new Ctor();পরে থাকে এবং পরে এক্স থাকে thisএবং করি var y = Ctor();তবে এটি প্রত্যাশার মতো আচরণ করবে না।
লুস্কুবাল

@ লুইসুবাল আপনি "পরে x হিসাবে this" কী বলছেন তা নিশ্চিত নন , আপনি সম্ভবত সম্ভাব্য সমস্যাটি দেখানোর জন্য একটি জিসফিডেল পোস্ট করতে পারেন?
হুয়ান মেন্ডেস

আপনার কোডটি আমি প্রথমে ভাবার
লুস্কুবাল

@ লুইসুবাল আমি আপনার বক্তব্যটি দেখতে পাচ্ছি তবে এটি সত্যই একটি সংশ্লেষিত। আপনি ধরে নিচ্ছেন যে ফোন করা ঠিক আছে Ctor.call(ctorInstance, 'value')। আপনি যা করছেন তার জন্য আমি কোনও বৈধ দৃশ্য দেখতে পাচ্ছি না। একটি অবজেক্ট তৈরি করতে, আপনি হয় ব্যবহার করুন var x = new Ctor(val)বা var y=Ctor(val)। এমনকি যদি কোনও বৈধ দৃশ্যের উপস্থিতি ছিল, তবে আমার দাবিটি হল যে আপনি ব্যবহার new Ctorনা করেই কনস্ট্রাক্টর থাকতে পারেন , আপনি যে কনস্ট্রাক্টর ব্যবহার করে কাজ করতে পারেন তা নয় jsfiddle.net/JHNcR/2Ctor.call দেখুন
জুয়ান মেন্ডেস

0

এটি সম্পর্কে কীভাবে?

/* thing maker! it makes things! */
function thing(){
    if (!(this instanceof thing)){
        /* call 'new' for the lazy dev who didn't */
        return new thing(arguments, "lazy");
    };

    /* figure out how to use the arguments object, based on the above 'lazy' flag */
    var args = (arguments.length > 0 && arguments[arguments.length - 1] === "lazy") ? arguments[0] : arguments;

    /* set properties as needed */
    this.prop1 = (args.length > 0) ? args[0] : "nope";
    this.prop2 = (args.length > 1) ? args[1] : "nope";
};

/* create 3 new things (mixed 'new' and 'lazy') */
var myThing1 = thing("woo", "hoo");
var myThing2 = new thing("foo", "bar");
var myThing3 = thing();

/* test your new things */
console.log(myThing1.prop1); /* outputs 'woo' */
console.log(myThing1.prop2); /* outputs 'hoo' */

console.log(myThing2.prop1); /* outputs 'foo' */
console.log(myThing2.prop2); /* outputs 'bar' */

console.log(myThing3.prop1); /* outputs 'nope' */
console.log(myThing3.prop2); /* outputs 'nope' */

সম্পাদনা: আমি যুক্ত করতে ভুলে গেছি:

"যদি আপনার অ্যাপটি সত্যই 'ভারী' হয়, আপনি সর্বশেষ জিনিসটি চান এটি হ্রাস করার জন্য কয়েকটি ওভারস্ট্রাক্ট নির্মাণ ব্যবস্থা"

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


নিখোঁজ কনস্ট্রাক্টর আর্গুমেন্টের জন্য মানগুলি আবিষ্কার করা ত্রুটি প্রবণ। যদি তারা নিখোঁজ থাকে তবে বৈশিষ্ট্যগুলি অপরিশোধিত রেখে দিন। যদি সেগুলি অপরিহার্য হয় তবে তারা অনুপস্থিত থাকলে একটি ত্রুটি নিক্ষেপ করুন। প্রোপ 1 বুল হওয়ার কথা যদি হয়? সত্যতার জন্য "না" পরীক্ষা করা ত্রুটির উত্স হতে চলেছে।
জেবিআরউইলকিনসন
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.