最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - What does Reflect.construct let us do that wasn't doable before? - Stack Overflow

programmeradmin0浏览0评论

I'm trying to find a good reason to use Reflect.construct to achieve something noteworthy that I could not achieve before.

I'm not looking for an answer like the one here, because that example don't seem to be very useful. For example, why would I write

function greetingFactory(name) {
  return Reflect.construct(Greeting, [name]);
}

when I can just write

function greetingFactory(name) {
  return new Greeting(name);
}

?

Do you know any notable use cases for Reflect.construct?

EDIT: Seems like I may have found a use case myself, but I'm not sure if it is solid and if it won't fall apart, but basically it seems like I can make new.target work with ES5-style classes by writing them like this:

function Foo() {
  console.log('Foo, new.target:', new.target)
  this.name = "foo"
}

Foo.prototype.sayHello = function sayHello() {
  return this.name
}

function Bar() {
  console.log('Bar, new.target:', new.target)
  let _ = Reflect.construct(Foo, [], new.target)
  _.name = _.name + " bar"
  return _
}

Bar.prototype = Object.create(Foo.prototype)

Bar.prototype.sayHello = function() {
  return "Hello " + Foo.prototype.sayHello.call(this) + "!"
}

function Baz() {
  console.log('Baz, new.target:', new.target)
  let _ = Reflect.construct(Bar, [], new.target)
  _.name = _.name + " baz"
  return _
}

Baz.prototype = Object.create(Bar.prototype)

Baz.prototype.sayHello = function() {
  return Bar.prototype.sayHello.call(this) + " Hello again!"
}

let baz = new Baz

console.log(baz.sayHello())

The cool thing about it is that this is as expected inside the prototype methods!

I'm trying to find a good reason to use Reflect.construct to achieve something noteworthy that I could not achieve before.

I'm not looking for an answer like the one here, because that example don't seem to be very useful. For example, why would I write

function greetingFactory(name) {
  return Reflect.construct(Greeting, [name]);
}

when I can just write

function greetingFactory(name) {
  return new Greeting(name);
}

?

Do you know any notable use cases for Reflect.construct?

EDIT: Seems like I may have found a use case myself, but I'm not sure if it is solid and if it won't fall apart, but basically it seems like I can make new.target work with ES5-style classes by writing them like this:

function Foo() {
  console.log('Foo, new.target:', new.target)
  this.name = "foo"
}

Foo.prototype.sayHello = function sayHello() {
  return this.name
}

function Bar() {
  console.log('Bar, new.target:', new.target)
  let _ = Reflect.construct(Foo, [], new.target)
  _.name = _.name + " bar"
  return _
}

Bar.prototype = Object.create(Foo.prototype)

Bar.prototype.sayHello = function() {
  return "Hello " + Foo.prototype.sayHello.call(this) + "!"
}

function Baz() {
  console.log('Baz, new.target:', new.target)
  let _ = Reflect.construct(Bar, [], new.target)
  _.name = _.name + " baz"
  return _
}

Baz.prototype = Object.create(Bar.prototype)

Baz.prototype.sayHello = function() {
  return Bar.prototype.sayHello.call(this) + " Hello again!"
}

let baz = new Baz

console.log(baz.sayHello())

The cool thing about it is that this is as expected inside the prototype methods!

Share Improve this question edited Jan 6, 2017 at 22:56 trusktr asked Jan 6, 2017 at 21:54 trusktrtrusktr 45.6k58 gold badges210 silver badges287 bronze badges 5
  • I don't think it's about enabling things that haven't not been possible before, but rather providing a unified API for these kind if "meta" operations. – Felix Kling Commented Jan 6, 2017 at 22:14
  • @FelixKling I suppose APIs as shortcuts for lengthier ways of doing something are valid, but I suppose I'm also curious to know if Reflect.construct solves any problems aside from possibly being a shortcut. – trusktr Commented Jan 6, 2017 at 22:40
  • @FelixKling I updated my answer, I think I might have found a use case. – trusktr Commented Jan 6, 2017 at 22:41
  • 1 "The cool thing about it is that this is as expected inside the prototype methods!" It would be anyway, thanks to the way you're calling them. All that using Reflect.construct does in the above is ensure that new.target is set for the calls to Bar and Foo (which could indeed be useful; that's basically a generalized version of my #3). – T.J. Crowder Commented May 13, 2020 at 7:44
  • Subclass Error, for example. – dumbass Commented May 10, 2024 at 5:28
Add a ment  | 

4 Answers 4

Reset to default 5

The only three use cases I know of for Reflect.construct are:

  1. Using it within a Proxy construct trap to get the default behavior (or to get slightly-modified default behavior).

  2. Using it to avoid creating and using an iterator when you need to call a constructor function using an array whose elements need to be passed as discrete arguments. You can just do

    t = new Thing(...theArray);
    

    but that involves creating and using an iterator, whereas

    t = Reflect.construct(Thing, theArray);
    

    doesn't use an iterator, which is much less work (not that it usually matters; this is for a situation where you know time is crucial). (Instead of an iterator, construct just uses length and directly accesses the 0, 1, etc. properties.)

    Neither of those options was available before ES2015. Instead, you had to do this:

    t = Thing.apply(Object.create(Thing.prototype), theArray);
    

    which worked with ES5 constructor functions. (It wouldn't work with an ES2015+ constructor function created via class, but you don't need it to — you'd use one of the two options above instead.)

  3. Using it to avoid using class when constructing an instance of a subtype of Error or Array or a web ponent (some people don't like to use class, and there are good arguments for that in projects that may need to be transpiled). (That said, Reflect.construct can't be perfectly polyfilled, either.)

I've been trying to sort out a useful application of the Reflect.construct as well. I think I may have found something but it would be nice to bounce the idea off other people on a similar path.

What I was thinking is that you could use Reflect.construct to wedge a [[Prototype]] between the instantiated object and it's intended [[Prototype]]. This would allow you to shadow properties and methods that belong to the intended [[Prototype]] without being too intrusive.

function Wedge() {};

Wedge.prototype = Object.create(String.prototype);

Wedge.prototype.toUpperCase = function () {
    return "nope";
}

let someString = Reflect.construct(String, ['Foo Bar'], Wedge)

someString.toUpperCase() // "nope"

It's late on the topic, but it is in fact possible to properly subclass native classes in ES5 code. It looks like this:

//ES6-class version
class MyArray extends Array {
  peekLast() {
    return this[this.length - 1];
  }
}

//ES5-class version
function MyArray() {
  //No need to use new since that instance gets discarded
  var retval = new Array();
  retval.__proto__ = MyArray.prototype; //This is the key line
  //Do any other initialization to retval here.
  return retval;
}
MyArray.prototype = Object.create(Array.prototype, {
  constructor: {
    configurable: true,
    writable: true,
    value: MyArray
  },
  peekLast: {
    configurable: true,
    writable: true,
    value: function peekLast() { return this[this.length - 1]; }
  }
});
MyArray.__proto__ = Array;

I get that __proto__ was never in the ES standard before ES6, but it was a defacto web standard that all major browsers and engines supported. That's what makes it possible.

It accepts the constructor whose prototype should be used in Reflect.constructor 3rd parameter. Try this code below and take a look to the prototype in array1Proto. It set Array as constructor despite was Object/func1 at the beginning.

    function func1(a, b, c) {
      this.sum = a + b + c;
    }
    
    const args = [1, 2, 3];
    const object1 = new func1(...args);
    const object2 = Reflect.construct(func1, args);
    const array1Proto = Reflect.construct(func1, args, Array);
    
    console.log(object1)
    console.log(object2)
    console.log(array1Proto)

发布评论

评论列表(0)

  1. 暂无评论