কীভাবে ES6 ক্লাস সহ ফাংশন প্রসারিত করবেন?


106

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

class Smth extends Function {
  constructor (x) {
    // What should be done here
    super();
  }
}

(new Smth(256))() // to get 256 at this call?

শ্রেণীর যে কোনও পদ্ধতি শ্রেণীর উদাহরণের মাধ্যমে রেফারেন্স পায় this। কিন্তু যখন এটি একটি ফাংশন হিসাবে ডাকা হয়, thisবোঝায় window। যখন ক্লাস উদাহরণ হিসাবে এটি একটি ফাংশন বলা হয় তখন আমি কীভাবে রেফারেন্স পেতে পারি?

পিএস: রাশিয়ান ভাষায় একই প্রশ্ন।


18
আহ, অবশেষে কেউ এই কুইস্টনকে জিজ্ঞাসা করেছে :-)
বার্গি

4
শুধু কি super(x)(অর্থাত্ এটি পাস Function)? Functionআসলে যদিও বাড়ানো যেতে পারে তা নিশ্চিত নয় ।
ফেলিক্স ক্লিং

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

4
মনে রাখবেন যে Functionকেবল একটি ফাংশন নির্মাণকারী। ফাংশনটি বাস্তবায়নের জন্য কনস্ট্রাক্টরের কাছে যেতে হবে। আপনি যদি Smthকোনও বাস্তবায়ন গ্রহণ করতে না চান তবে আপনাকে এটি নির্মাণকারীর মধ্যে সরবরাহ করতে হবে, যেমন super('function implementation here')
ফেলিক্স ক্লিং

4
@ কুয়ের্টি: আমি যুক্তি দিয়ে বলব যে এটি ব্যতিক্রম , সাধারণ ক্ষেত্রে নয়। এটি ফাংশন এক্সপ্রেশনগুলির জন্যও খুব নির্দিষ্ট , তবে আপনি Functionকনস্ট্রাক্টর (রানটাইম) ব্যবহার করছেন যা কোনও ফাংশন এক্সপ্রেশন (সিনট্যাক্স) থেকে খুব আলাদা।
ফেলিক্স ক্লিং

উত্তর:


49

superকল ডাকা হবে Functionকন্সট্রাকটর, যা একটি কোড স্ট্রিং প্রত্যাশা করে। আপনি যদি আপনার উদাহরণ ডেটা অ্যাক্সেস করতে চান তবে আপনি এটি হার্ডকোড করতে পারেন:

class Smth extends Function {
  constructor(x) {
    super("return "+JSON.stringify(x)+";");
  }
}

তবে তা আসলে সন্তুষ্ট নয়। আমরা একটি বন্ধ ব্যবহার করতে চাই।

ফিরে আসা ক্রিয়াকলাপটি এমন একটি ক্লোজার হতে পারে যা আপনার উদাহরণের ভেরিয়েবলগুলি অ্যাক্সেস করতে পারে তবে এটি সহজ নয়। ভাল জিনিস হ'ল আপনি না চাইলে কল superকরতে হবে না - আপনি এখনও returnআপনার ES6 শ্রেণীর নির্মাতাদের থেকে নির্বিচারে বস্তুগুলি করতে পারেন । এই ক্ষেত্রে, আমরা করব

class Smth extends Function {
  constructor(x) {
    // refer to `smth` instead of `this`
    function smth() { return x; };
    Object.setPrototypeOf(smth, Smth.prototype);
    return smth;
  }
}

তবে আমরা আরও ভাল করতে পারি এবং এই জিনিসটি বিমূর্ত করতে পারি Smth:

class ExtensibleFunction extends Function {
  constructor(f) {
    return Object.setPrototypeOf(f, new.target.prototype);
  }
}

class Smth extends ExtensibleFunction {
  constructor(x) {
    super(function() { return x; }); // closure
    // console.log(this); // function() { return x; }
    // console.log(this.prototype); // {constructor: …}
  }
}
class Anth extends ExtensibleFunction {
  constructor(x) {
    super(() => { return this.x; }); // arrow function, no prototype object created
    this.x = x;
  }
}
class Evth extends ExtensibleFunction {
  constructor(x) {
    super(function f() { return f.x; }); // named function
    this.x = x;
  }
}

স্বীকার করা যায়, এটি উত্তরাধিকার শৃঙ্খলে অতিরিক্ত স্তরের ইন্ডিয়ারেশন তৈরি করে, তবে এটি অগত্যা কোনও খারাপ জিনিস নয় (আপনি দেশীয়ের পরিবর্তে এটি প্রসারিত করতে পারেন Function)। আপনি যদি এড়াতে চান তবে ব্যবহার করুন

function ExtensibleFunction(f) {
  return Object.setPrototypeOf(f, new.target.prototype);
}
ExtensibleFunction.prototype = Function.prototype;

তবে লক্ষ্য করুন যে Smthস্থির Functionবৈশিষ্ট্যগুলি গতিশীলভাবে উত্তরাধিকার সূত্রে প্রাপ্ত হবে না ।


আমি ফাংশন থেকে শ্রেণি রাজ্যে অ্যাক্সেস পেতে চাই।
কিওয়ারটি

4
@ কিওয়ার্টি: তারপরে বার্গির দ্বিতীয় পরামর্শটি ব্যবহার করুন।
ফেলিক্স ক্লিং

@ আলেকজান্ডার'মারা: আপনি যদি নিজের Smthদৃষ্টান্তগুলি চান instanceof Smth(যেমনটি সবার প্রত্যাশা থাকে) আপনি চান তবে ফাংশনটির প্রোটোটাইপটি পরিবর্তন করতে পারবেন না। Object.setPrototypeOfআপনার ক্লাসে ঘোষিত আপনার বা প্রোটোটাইপ পদ্ধতিগুলির কোনও প্রয়োজন না হলে আপনি কলটি বাদ দিতে পারেন।
বার্গি

@ আলেকজান্ডার ও'মারা: Object.setPrototypeOfঅবজেক্টটি তৈরি করার পরে যতক্ষণ না এটি করা হয় ততক্ষণ কোনও অপ্টিমাইজেশনের ঝুঁকি নেই। এটি ঠিক যদি আপনি কোনও জীবের [[প্রোটোটাইপ]] এর জীবদ্দশায় পিছনে পিছনে পরিবর্তন করেন যে এটি খারাপ হবে।
বার্গি

4
@ এ্যামন না, আপনি করবেন না, যখন আপনি ব্যবহার করবেন না thisএবং returnকোনও বস্তু ব্যবহার করবেন না ।
বার্গি

33

এটি কলযোগ্যযোগ্য বস্তু তৈরির জন্য একটি দৃষ্টিভঙ্গি যা তাদের অবজেক্টের সদস্যদের সঠিকভাবে রেফারেন্স দেয় এবং প্রোটোটাইপের সাথে গোলযোগ না করে সঠিক উত্তরাধিকার বজায় রাখে।

কেবল:

class ExFunc extends Function {
  constructor() {
    super('...args', 'return this.__self__.__call__(...args)')
    var self = this.bind(this)
    this.__self__ = self
    return self
  }

  // Example `__call__` method.
  __call__(a, b, c) {
    return [a, b, c];
  }
}

এই শ্রেণিটি প্রসারিত করুন এবং __call__আরও নীচে একটি পদ্ধতি যুক্ত করুন ...

কোড এবং মন্তব্যে একটি ব্যাখ্যা:

// This is an approach to creating callable objects
// that correctly reference their own object and object members,
// without messing with prototypes.

// A Class that extends Function so we can create
// objects that also behave like functions, i.e. callable objects.
class ExFunc extends Function {
  constructor() {
    super('...args', 'return this.__self__.__call__(...args)');
    // Here we create a function dynamically using `super`, which calls
    // the `Function` constructor which we are inheriting from. Our aim is to create
    // a `Function` object that, when called, will pass the call along to an internal
    // method `__call__`, to appear as though the object is callable. Our problem is
    // that the code inside our function can't find the `__call__` method, because it
    // has no reference to itself, the `this` object we just created.
    // The `this` reference inside a function is called its context. We need to give
    // our new `Function` object a `this` context of itself, so that it can access
    // the `__call__` method and any other properties/methods attached to it.
    // We can do this with `bind`:
    var self = this.bind(this);
    // We've wrapped our function object `this` in a bound function object, that
    // provides a fixed context to the function, in this case itself.
    this.__self__ = self;
    // Now we have a new wrinkle, our function has a context of our `this` object but
    // we are going to return the bound function from our constructor instead of the
    // original `this`, so that it is callable. But the bound function is a wrapper
    // around our original `this`, so anything we add to it won't be seen by the
    // code running inside our function. An easy fix is to add a reference to the
    // new `this` stored in `self` to the old `this` as `__self__`. Now our functions
    // context can find the bound version of itself by following `this.__self__`.
    self.person = 'Hank'
    return self;
  }
  
  // An example property to demonstrate member access.
  get venture() {
    return this.person;
  }
  
  // Override this method in subclasses of ExFunc to take whatever arguments
  // you want and perform whatever logic you like. It will be called whenever
  // you use the obj as a function.
  __call__(a, b, c) {
    return [this.venture, a, b, c];
  }
}

// A subclass of ExFunc with an overridden __call__ method.
class DaFunc extends ExFunc {
  constructor() {
    super()
    this.a = 'a1'
    this.b = 'b2'
    this.person = 'Dean'
  }

  ab() {
    return this.a + this.b
  }
  
  __call__(ans) {
    return [this.ab(), this.venture, ans];
  }
}

// Create objects from ExFunc and its subclass.
var callable1 = new ExFunc();
var callable2 = new DaFunc();

// Inheritance is correctly maintained.
console.log('\nInheritance maintained:');
console.log(callable2 instanceof Function);  // true
console.log(callable2 instanceof ExFunc);  // true
console.log(callable2 instanceof DaFunc);  // true

// Test ExFunc and its subclass objects by calling them like functions.
console.log('\nCallable objects:');
console.log( callable1(1, 2, 3) );  // [ 'Hank', 1, 2, 3 ]
console.log( callable2(42) );  // [ 'a1b2', Dean', 42 ]

// Test property and method access
console.log(callable2.a, callable2.b, callable2.ab())

Repl.it এ দেখুন

এর আরও ব্যাখ্যা bind:

function.bind()অনেকটা মত কাজ করে function.call()এবং তারা একটি অনুরূপ পদ্ধতির স্বাক্ষর ভাগ করে:

fn.call(this, arg1, arg2, arg3, ...);সম্পর্কে আরও MDN

fn.bind(this, arg1, arg2, arg3, ...);সম্পর্কে আরও MDN

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

সুতরাং আপনি যখন একটি ফাংশন সংজ্ঞায়িত করেন তখন এর bindকিছু যুক্তি:

var foo = function(a, b) {
  console.log(this);
  return a * b;
}

foo = foo.bind(['hello'], 2);

আপনি কেবলমাত্র বাকী যুক্তি দিয়ে বাউন্ড ফাংশনটিকে কল করেন, এর প্রসঙ্গটি এই ক্ষেত্রে প্রিসেট রয়েছে ['hello']

// We pass in arg `b` only because arg `a` is already set.
foo(2);  // returns 4, logs `['hello']`

আপনি দয়া করে একটি ব্যাখ্যা যুক্ত করতে পারেন কেন bindকাজ করে (যেমন এটি কেন একটি উদাহরণ ফেরৎ দেয় ExFunc)?
বার্গি

@ বার্গি bindএকটি স্বচ্ছ ফাংশন অবজেক্ট ফিরিয়ে দেয় যা ডেকে আনা ফাংশন অবজেক্টটিকে আবৃত করে, যা আমাদের কলযোগ্য অবজেক্ট, ঠিক thisপ্রসঙ্গের প্রত্যাবর্তনের সাথে। সুতরাং এটি সত্যিই স্বচ্ছভাবে মোড়ানো উদাহরণটি দেয় ExFunc। আরও তথ্যের সাথে পোস্ট আপডেট হয়েছে bind
অ্যাড্রিয়েন

4
@Bergi সকল getters / setters ও পদ্ধতি প্রবেশযোগ্য, বৈশিষ্ট্য / বৈশিষ্ট্য নির্ধারিত করা আবশ্যক constructorপর bindExFunc। এক্সফুঙ্কের সাবক্লাসে, সমস্ত সদস্য অ্যাক্সেসযোগ্য। হিসাবে হিসাবে instanceof; es6 আবদ্ধ ফাংশন এ, বহিরাগত হিসেবে উল্লেখ করা হয়, যাতে তাদের ভেতরের কাজগুলোকে আপাত হয় না, কিন্তু আমি এটা তার আবৃত টার্গেটের উপর কল পাসের চিন্তা করছি মাধ্যমে Symbol.hasInstance। এটি অনেকটা প্রক্সির মতো, তবে পছন্দসই প্রভাবটি সম্পাদন করার এটি একটি সহজ পদ্ধতি। তাদের স্বাক্ষর একই নয়।
অ্যাড্রিয়েন

4
@ অ্যাড্রিন কিন্তু ভিতরে থেকে __call__আমি অ্যাক্সেস করতে পারি না this.aবা this.ab()। উদাহরণস্বরূপ repl.it/repls/FlineFinishedDesktopen ਵਾਤਾਵਰਣ
রব

4
@ আরব ভালভাবে চিহ্নিত, একটি রেফারেন্স ত্রুটি আছে, আমি একটি সমাধান এবং একটি নতুন ব্যাখ্যা সহ উত্তর এবং কোড আপডেট করেছি।
অ্যাড্রিয়েন

20

আপনি একটি প্রস্তুত হত্তয়া উদাহরণস্বরূপ মোড়ানো পারেন প্রক্সি একটি সঙ্গে apply(এবং হয়ত construct) ফাঁদ:

class Smth extends Function {
  constructor (x) {
    super();
    return new Proxy(this, {
      apply: function(target, thisArg, argumentsList) {
        return x;
      }
    });
  }
}
new Smth(256)(); // 256

দুর্দান্ত ধারণা। এটার মত. আমি প্রয়োগের ভিতরে না রেখে কি আরও যুক্তি প্রয়োগ করব?
কিওয়ার্টি

4
একটি প্রক্সি বেশ কিছু ওভারহেড ব্যয় করবে, তাই না? এছাড়াও, thisএখনও একটি খালি ফাংশন (চেক new Smth().toString())।
বার্গি

4
@ বার্গি কর্মক্ষমতা সম্পর্কে কোন ধারণা নেই। MDN এর সম্পর্কে একটি বড় লাল সাহসী সতর্কতা রয়েছে setPrototypeOfএবং প্রক্সিগুলি সম্পর্কে কিছুই বলে না। তবে আমার ধারণা, প্রক্সিগুলি যতটা সমস্যাযুক্ত হতে পারে setPrototypeOf। এবং প্রায় toString, এটিকে একটি কাস্টম পদ্ধতিতে ছায়া দেওয়া যেতে পারে Smth.prototype। নেটিভ এক যাইহোক বাস্তবায়ন নির্ভর।
অরিওল

@ কিওয়ারটি আপনি constructএর আচরণটি নির্দিষ্ট করতে একটি ফাঁদ যুক্ত করতে পারেন new new Smth(256)()। এবং কাস্টম পদ্ধতিগুলি যুক্ত করুন যা toStringদেশীগুলিকে ছায়া দেয় যা কোনও ফাংশনের কোডগুলিতে অ্যাক্সেস করে, যেমন বার্গি উল্লেখ করেছেন।
অরিওল

আমি আপনার applyপদ্ধতিটি যেভাবে এটি ব্যবহার করার কথা বলে মনে করা হচ্ছে তা প্রয়োগ করা হয়েছে, বা এটি কেবল একটি প্রদর্শনী এবং এর সম্পর্কে আরও তথ্যের সন্ধান করা Proxyএবং Reflectএটি সঠিকভাবে ব্যবহার করার দরকার আছে?
কিওয়ারটি

3

আমি বার্গির উত্তর থেকে পরামর্শ নিয়ে এটিকে একটি এনপিএম মডিউলটিতে গুটিয়ে রেখেছি ।

var CallableInstance = require('callable-instance');

class ExampleClass extends CallableInstance {
  constructor() {
    // CallableInstance accepts the name of the property to use as the callable
    // method.
    super('instanceMethod');
  }

  instanceMethod() {
    console.log("instanceMethod called!");
  }
}

var test = new ExampleClass();
// Invoke the method normally
test.instanceMethod();
// Call the instance itself, redirects to instanceMethod
test();
// The instance is actually a closure bound to itself and can be used like a
// normal function.
test.apply(null, [ 1, 2, 3 ]);

3

হালনাগাদ:

দুর্ভাগ্যক্রমে এটি বেশ কার্যকর হয় না কারণ এটি এখন ক্লাসের পরিবর্তে কোনও ফাংশন অবজেক্টটি ফিরিয়ে দিচ্ছে, তাই দেখে মনে হচ্ছে প্রোটোটাইপটি পরিবর্তন না করেই এটি করা যায় না। পঙ্গু.


মূলত সমস্যাটি হচ্ছে কনস্ট্রাক্টরের thisজন্য মান নির্ধারণের কোনও উপায় নেই Function। এটি করার একমাত্র উপায় .bindহ'ল পদ্ধতিটি পরে ব্যবহার করা হবে তবে এটি খুব শ্রেণীবান্ধব নয়।

আমরা এটি একটি সহায়ক বেস ক্লাসে করতে পারি, তবে thisপ্রাথমিক কলয়ের পরে এটি উপলব্ধ হয় না super, তাই এটি কিছুটা জটিল।

কাজের উদাহরণ:

'use strict';

class ClassFunction extends function() {
    const func = Function.apply(null, arguments);
    let bound;
    return function() {
        if (!bound) {
            bound = arguments[0];
            return;
        }
        return func.apply(bound, arguments);
    }
} {
    constructor(...args) {
        (super(...args))(this);
    }
}

class Smth extends ClassFunction {
    constructor(x) {
        super('return this.x');
        this.x = x;
    }
}

console.log((new Smth(90))());

(উদাহরণের জন্য আধুনিক ব্রাউজার প্রয়োজন বা node --harmony))

মূলত বেস ফাংশন ClassFunctionপ্রসারিতগুলি Functionকাস্টম ফাংশনের সাথে কনস্ট্রাক্টর কলটি আবৃত করবে যা অনুরূপ .bind, তবে এটি প্রথম কলটিতে পরে বাঁধাইয়ের অনুমতি দেয়। তারপরে ClassFunctionকনস্ট্রাক্টর নিজেই, এটি পুনরায় ফাংশনটিকে কল করে superযা থেকে এখন সীমাবদ্ধ ফাংশন, thisকাস্টম বাইন্ড ফাংশনটি সেটআপ শেষ করে চলেছে।

(super(...))(this);

এটি সমস্ত কিছুটা জটিল, তবে এটি প্রোটোটাইপকে রূপান্তর করতে এড়াতে পারে না, যা অপ্টিমাইজেশনের কারণে খারাপ-রূপ হিসাবে বিবেচিত হয় এবং ব্রাউজার কনসোলগুলিতে সতর্কতা উত্পন্ন করতে পারে।


4
আপনি অত্যধিক জটিল জিনিস। boundআপনি returnযে বেনাম শ্রেণীর থেকে ফাংশনটি উল্লেখ করবেন । কেবল এটির নাম দিন এবং সরাসরি এটি উল্লেখ করুন। আমি চারপাশে কোডের স্ট্রিংগুলি এড়ানোর পরামর্শ দেব, তারা ( বিকাশ প্রক্রিয়াটির প্রতিটি ধাপে) কাজ করার জন্য কেবল একটি গোলমাল ।
বার্গি

এটি extendsবাস্তবে প্রত্যাশিতভাবে কাজ করবে বলে মনে হয় না, যেমনটি Function.isPrototypeOf(Smth)এবং new Smth instanceof Functionমিথ্যাও।
বার্গি

@ বারগি আপনি কী জেএস ইঞ্জিন ব্যবহার করছেন? console.log((new Smth) instanceof Function);হয় trueনোড v5.11.0 এবং সর্বশেষ ফায়ারফক্স আমার জন্য।
আলেকজান্ডার ও'মারা

উফ, ভুল উদাহরণ এটি new Smth instanceof Smthআপনার সমাধানের সাথে কাজ করছে না। এছাড়াও কোনও Smthউদাহরণ আপনার দৃষ্টান্তগুলিতে অ্যাক্সেসযোগ্য হবে না - আপনি কেবলমাত্র একটি স্ট্যান্ডার্ড ফিরিয়ে Functionনাও, একটি Smth
বার্গি

4
@ বেরগি এটি ছুঁড়ে ফেলুন, দেখে মনে হচ্ছে আপনি ঠিক আছেন। তবে যে কোনও দেশীয় প্রকার প্রসারিত করার ক্ষেত্রে একই সমস্যা রয়েছে বলে মনে হয়। extend Functionএছাড়াও new Smth instanceof Smthমিথ্যা তোলে ।
আলেকজান্ডার ও'মারা

2

প্রথমদিকে আমি সমাধানে এসেছি arguments.callee, তবে এটি ছিল ভয়াবহ।
আমি এটি বিশ্বব্যাপী কঠোর মোডে ভাঙ্গার প্রত্যাশা করেছি, তবে মনে হয় এটি সেখানেও কার্যকর হয়।

class Smth extends Function {
  constructor (x) {
    super('return arguments.callee.x');
    this.x = x;
  }
}

(new Smth(90))()

arguments.calleeকোডটি স্ট্রিং হিসাবে পাস করার জন্য এবং অ-কঠোর মোডে এর প্রয়োগ কার্যকর করার জন্য এটি একটি খারাপ উপায় ছিল । তবে ওভাররাইড করার চেয়ে ধারণা applyহাজির।

var global = (1,eval)("this");

class Smth extends Function {
  constructor(x) {
    super('return arguments.callee.apply(this, arguments)');
    this.x = x;
  }
  apply(me, [y]) {
    me = me !== global && me || this;
    return me.x + y;
  }
}

এবং পরীক্ষা, দেখিয়ে আমি এটিকে বিভিন্ন উপায়ে ফাংশন হিসাবে চালাতে সক্ষম হয়েছি:

var f = new Smth(100);

[
f instanceof Smth,
f(1),
f.call(f, 2),
f.apply(f, [3]),
f.call(null, 4),
f.apply(null, [5]),
Function.prototype.apply.call(f, f, [6]),
Function.prototype.apply.call(f, null, [7]),
f.bind(f)(8),
f.bind(null)(9),
(new Smth(200)).call(new Smth(300), 1),
(new Smth(200)).apply(new Smth(300), [2]),
isNaN(f.apply(window, [1])) === isNaN(f.call(window, 1)),
isNaN(f.apply(window, [1])) === isNaN(Function.prototype.apply.call(f, window, [1])),
] == "true,101,102,103,104,105,106,107,108,109,301,302,true,true"

সাথে সংস্করণ

super('return arguments.callee.apply(arguments.callee, arguments)');

আসলে bindকার্যকারিতা রয়েছে :

(new Smth(200)).call(new Smth(300), 1) === 201

সাথে সংস্করণ

super('return arguments.callee.apply(this===(1,eval)("this") ? null : this, arguments)');
...
me = me || this;

তোলে callএবং applyউপর windowঅসঙ্গত:

isNaN(f.apply(window, [1])) === isNaN(f.call(window, 1)),
isNaN(f.apply(window, [1])) === isNaN(Function.prototype.apply.call(f, window, [1])),

সুতরাং চেকটি এতে স্থানান্তরিত হওয়া উচিত apply:

super('return arguments.callee.apply(this, arguments)');
...
me = me !== global && me || this;

4
আপনি আসলে কী করার চেষ্টা করছেন?
ধন্যবাদ

4
আমার মনে হয় ক্লাসগুলি সর্বদা কঠোর মোডে থাকে: stackoverflow.com/questions/29283935/…
আলেকজান্ডার ও'মারা

@ আলেকজান্ডার'মারা, যাইহোক, thisউইন্ডো, অপরিজ্ঞাত নয়, সুতরাং তৈরি ফাংশনটি কঠোর মোডে নয় (কমপক্ষে ক্রোমে)।
কিওয়ারটি

দয়া করে, এই উত্তরটি নিচে নামা বন্ধ করুন। আমি ইতিমধ্যে লিখেছি যে এটি একটি খারাপ উপায়। তবে এটি সত্যিই একটি উত্তর - এটি এফএফ এবং ক্রোম উভয় ক্ষেত্রেই কাজ করে (পরীক্ষা করার এজ নেই)।
কিওয়ারটি

আমি এই কাজগুলি অনুমান করছি কারণ Functionকঠোর মোডে নেই। ভয়ঙ্কর হলেও, এটি আকর্ষণীয় +1। আপনি সম্ভবত আর কোনও চেইন হাঁটাতে সক্ষম হবেন না।
আলেকজান্ডার ও'মারা

1

এই সমাধানটি আমি কাজ করেছি যা আমার সমস্ত প্রসারিত ক্রিয়াকলাপের প্রয়োজন এবং আমাকে বেশ ভালভাবে পরিবেশন করেছে। এই কৌশলটির সুবিধাগুলি হ'ল:

  • প্রসারিত করার সময় ExtensibleFunction, কোডটি কোনও ইএস 6 শ্রেণি প্রসারিত করে না io
  • প্রোটোটাইপ শৃঙ্খল সব উপশ্রেণী মাধ্যমে থাকলো এবং তাঁরা হয় instanceof/ .constructorপ্রত্যাশিত মান ফিরে।
  • .bind() .apply()এবং .call()সমস্ত ফাংশন প্রত্যাশিত হিসাবে ExtensibleFunction(বা এটি সাবক্লাস ') উদাহরণের বিপরীতে "অভ্যন্তরীণ" ক্রিয়াকলাপের প্রসঙ্গ পরিবর্তনের জন্য এই পদ্ধতিগুলি ওভাররাইড করেই করা হয় ।
  • .bind()ফাংশন কনস্ট্রাক্টরের একটি নতুন উদাহরণ প্রদান করে (এটি হোক ExtensibleFunctionবা সাবক্লাস হোক)। এটি Object.assign()সীমাবদ্ধ ফাংশনে সঞ্চিত বৈশিষ্ট্যগুলি উত্সক ক্রিয়াকলাপের সাথে সামঞ্জস্যপূর্ণ তা নিশ্চিত করার জন্য এটি ব্যবহার করে।
  • বন্ধগুলি সম্মানিত হয়, এবং তীর ফাংশন যথাযথ প্রসঙ্গ বজায় রাখতে থাকে।
  • "অভ্যন্তরীণ" ফাংশনটি একটি এর মাধ্যমে সঞ্চিত হয় Symbol, যা মডিউল বা একটি আইআইএফই (বা রেফারেন্সকে বেসরকারীকরণের কোনও সাধারণ কৌশল) দ্বারা আচ্ছন্ন করতে পারে।

এবং পরবর্তী বিজ্ঞাপন ছাড়াই কোড:

// The Symbol that becomes the key to the "inner" function 
const EFN_KEY = Symbol('ExtensibleFunctionKey');

// Here it is, the `ExtensibleFunction`!!!
class ExtensibleFunction extends Function {
  // Just pass in your function. 
  constructor (fn) {
    // This essentially calls Function() making this function look like:
    // `function (EFN_KEY, ...args) { return this[EFN_KEY](...args); }`
    // `EFN_KEY` is passed in because this function will escape the closure
    super('EFN_KEY, ...args','return this[EFN_KEY](...args)');
    // Create a new function from `this` that binds to `this` as the context
    // and `EFN_KEY` as the first argument.
    let ret = Function.prototype.bind.apply(this, [this, EFN_KEY]);
    // For both the original and bound funcitons, we need to set the `[EFN_KEY]`
    // property to the "inner" function. This is done with a getter to avoid
    // potential overwrites/enumeration
    Object.defineProperty(this, EFN_KEY, {get: ()=>fn});
    Object.defineProperty(ret, EFN_KEY, {get: ()=>fn});
    // Return the bound function
    return ret;
  }

  // We'll make `bind()` work just like it does normally
  bind (...args) {
    // We don't want to bind `this` because `this` doesn't have the execution context
    // It's the "inner" function that has the execution context.
    let fn = this[EFN_KEY].bind(...args);
    // Now we want to return a new instance of `this.constructor` with the newly bound
    // "inner" function. We also use `Object.assign` so the instance properties of `this`
    // are copied to the bound function.
    return Object.assign(new this.constructor(fn), this);
  }

  // Pretty much the same as `bind()`
  apply (...args) {
    // Self explanatory
    return this[EFN_KEY].apply(...args);
  }

  // Definitely the same as `apply()`
  call (...args) {
    return this[EFN_KEY].call(...args);
  }
}

/**
 * Below is just a bunch of code that tests many scenarios.
 * If you run this snippet and check your console (provided all ES6 features
 * and console.table are available in your browser [Chrome, Firefox?, Edge?])
 * you should get a fancy printout of the test results.
 */

// Just a couple constants so I don't have to type my strings out twice (or thrice).
const CONSTRUCTED_PROPERTY_VALUE = `Hi, I'm a property set during construction`;
const ADDITIONAL_PROPERTY_VALUE = `Hi, I'm a property added after construction`;

// Lets extend our `ExtensibleFunction` into an `ExtendedFunction`
class ExtendedFunction extends ExtensibleFunction {
  constructor (fn, ...args) {
    // Just use `super()` like any other class
    // You don't need to pass ...args here, but if you used them
    // in the super class, you might want to.
    super(fn, ...args);
    // Just use `this` like any other class. No more messing with fake return values!
    let [constructedPropertyValue, ...rest] = args;
    this.constructedProperty = constructedPropertyValue;
  }
}

// An instance of the extended function that can test both context and arguments
// It would work with arrow functions as well, but that would make testing `this` impossible.
// We pass in CONSTRUCTED_PROPERTY_VALUE just to prove that arguments can be passed
// into the constructor and used as normal
let fn = new ExtendedFunction(function (x) {
  // Add `this.y` to `x`
  // If either value isn't a number, coax it to one, else it's `0`
  return (this.y>>0) + (x>>0)
}, CONSTRUCTED_PROPERTY_VALUE);

// Add an additional property outside of the constructor
// to see if it works as expected
fn.additionalProperty = ADDITIONAL_PROPERTY_VALUE;

// Queue up my tests in a handy array of functions
// All of these should return true if it works
let tests = [
  ()=> fn instanceof Function, // true
  ()=> fn instanceof ExtensibleFunction, // true
  ()=> fn instanceof ExtendedFunction, // true
  ()=> fn.bind() instanceof Function, // true
  ()=> fn.bind() instanceof ExtensibleFunction, // true
  ()=> fn.bind() instanceof ExtendedFunction, // true
  ()=> fn.constructedProperty == CONSTRUCTED_PROPERTY_VALUE, // true
  ()=> fn.additionalProperty == ADDITIONAL_PROPERTY_VALUE, // true
  ()=> fn.constructor == ExtendedFunction, // true
  ()=> fn.constructedProperty == fn.bind().constructedProperty, // true
  ()=> fn.additionalProperty == fn.bind().additionalProperty, // true
  ()=> fn() == 0, // true
  ()=> fn(10) == 10, // true
  ()=> fn.apply({y:10}, [10]) == 20, // true
  ()=> fn.call({y:10}, 20) == 30, // true
  ()=> fn.bind({y:30})(10) == 40, // true
];

// Turn the tests / results into a printable object
let table = tests.map((test)=>(
  {test: test+'', result: test()}
));

// Print the test and result in a fancy table in the console.
// F12 much?
console.table(table);

সম্পাদনা করুন

যেহেতু আমি মুডে ছিলাম, তাই আমি বুঝতে পেরেছিলাম যে আমি এর জন্য এনপিএমের জন্য একটি প্যাকেজ প্রকাশ করব ।


1

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

class Funk
{
    constructor (f)
    { let proto       = Funk.prototype;
      let methodNames = Object.getOwnPropertyNames (proto);
      methodNames.map (k => f[k] = this[k]);
      return f;
    }

    methodX () {return 3}
}

let myFunk  = new Funk (x => x + 1);
let two     = myFunk(1);         // == 2
let three   = myFunk.methodX();  // == 3

উপরেরটি নোড.জেএস 8 তে পরীক্ষা করা হয়েছিল।

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

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


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