What is new.target ?
You didn't find it in the spec because in the syntax definitions it is written with blanks, as new . target
. The name of the expression is NewTarget
, and you'll find that term a few times around.
NewTarget is the first of the so-called meta properties and can be found in §12.3.8.
Its sole purpose is to retrieve the current value of the [[NewTarget]] value of the current (non-arrow) function environment. It is a value that is set when a function is called (very much like the this
binding), and according to §8.1.1.3 Function Environment Records:
If this Environment Record was created by the [[Construct]] internal method, [[NewTarget]] is the value of the [[Construct]]
newTarget
parameter. Otherwise, its value isundefined
.
So, for one thing, finally enables us to detect whether a function was called as a constructor or not.
But that's not its real purpose. So what is it then? It is part of the way how ES6 classes are not only syntactic sugar, and how they allow us inheriting from builtin objects. When you call a class
constructor via new X
, the this
value is not yet initialised - the object is not yet created when the constructor body is entered. It does get created by the super constructor during the super()
call (which is necessary when internal slots are supposed to be created). Still, the instance should inherit from the .prototype
of the originally called constructor, and that's where newTarget comes into the play. It does hold the "outermost" constructor that received the new
call during super()
invocations. You can follow it all the way down in the spec, but basically it always is the newTarget
not the currently executed constructor that does get passed into the OrdinaryCreateFromConstructor
procedure - for example in step 5 of §9.2.2 [[Construct]] for user-defined functions.
Long text, maybe an example is better suited:
class Parent {
constructor() {
// implicit (from the `super` call)
// new.target = Child;
// implicit (because `Parent` doesn't extend anything):
// this = Object.create(new.target.prototype);
console.log(new.target) // Child!
}
}
class Child extends Parent {
constructor() {
// `this` is uninitialised (and would throw if accessed)
// implicit (from the `new` call):
// new.target = Child
super(); // this = Reflect.construct(Parent, [], new.target);
console.log(this);
}
}
new Child;
JS new.target vs. instanceof
Using this instanceof Foo you will check if this instance is a Foo, but you can't ensure that was called with a new.
I can just do a thing like this
var foo = new Foo("Test");
var notAFoo = Foo.call(foo, "AnotherWord");
And will work fine. Using new.target you can avoid this issues.
I suggest you to read this book https://leanpub.com/understandinges6/read
What is javascript Reflect.construct newTarget doing
I'd say the documentation is somewhat misleadingly worded. What seems to be happening is that construct()
invokes the first the first argument as the constructor (i.e. to initialize the object), but uses the last argument as the prototype (i.e. the actual "class" of the object). In your case, result instanceof Child
returns true, but result instanceof Parent
returns false.
So, the result of Reflect.construct(target, args, newTarget)
seems to be equivalent to this:
var result = Object.create(newTarget.prototype);
target.apply(result, args);
However, there is one significant difference: in the above example, the new.target
operator within either function will return undefined
, since you're not using the new
keyword to create the object. When you use Reflect.construct()
, on the other hand, new.target
will point to newTarget
(hence the name, I suppose) -- probably because, in the end, the resulting object will belong to that class.
(Note: I have since requested an edit to the MDN page about Reflect.construct()
to include these details)
new.target property behaves unexpected in bound functions
new.target
does not always refer to the called function. Rather, it refers to the function whose .prototype
property should be used as the prototype for the new instance (so that superclasses can create the right thing).
The .bind()
method does create special "bound function" objects whose only purpose it is to call the original function with the provided this
value and partially applied arguments list. They don't even have a .prototype
property - which should make clear that they are not an appropriate value for new.target
. And indeed, their [[construct]] method is specified to use the original function in place of the bound function.
So what should you do here? Of course, "using new
to configure functions" should be avoided in production code, but it's a nice experiment. I would suggest to avoid bind
here and instead make use of closures:
function makeTest(config) {
return function ConfiguredTest(newConfig) {
if (new.target) {
let mergedConfig = {};
Object.assign(mergedConfig, newConfig || {}, config) // I presume you want to swap the latter two
return makeTest(mergedConfig);
} else {
// use `config` here
return config.a + config.b;
}
};
}
const Test = makeTest({});
// like before
let Test2 = new Test(…)
let Test3 = new Test2(…)
Test3()
new.target with a prefix operator
This syntax should be supported, and the error was confirmed to be a webkit bug:
if(!new.target){
throw new Error('Must be called with new keyword!')
}
A patch has been written and merged, and will ship with a future version of webkit
https://bugs.webkit.org/show_bug.cgi?id=157970#c17
Until the fix lands in a released version, a workaround is to explicitly check new.target
if(new.target === undefined){
throw new Error('Must be called with new keyword!')
}
How do you polyfill Javascript ES6 `new.target`?
As Jaromanda commented, you cannot polyfill new syntax, but you can easily work around some new.target
use cases for now
Taking a look at the new.target docs you'll see some examples that can easily be written with es5
with new.target
function Foo() {
if (!new.target) throw "Foo() must be called with new";
console.log("Foo instantiated with new");
}
Foo(); // throws "Foo() must be called with new"
new Foo(); // logs "Foo instantiated with new"
without
function Foo() {
if (!(this instanceof Foo)) throw "Foo() must be called with new";
console.log("Foo instantiated with new");
}
Foo(); // throws "Foo() must be called with new"
new Foo(); // logs "Foo instantiated with new"
with new.target
class A {
constructor() {
console.log(new.target.name);
}
}
class B extends A { constructor() { super(); } }
var a = new A(); // logs "A"
var b = new B(); // logs "B"
without
class A {
constructor() {
// class forces constructor to be called with `new`, so
// `this` will always be set
console.log(this.constructor.name);
}
}
class B extends A { constructor() { super(); } }
var a = new A(); // logs "A"
var b = new B(); // logs "B"
Hope this helps a little
target= _blank vs. target= _new
Use "_blank"
According to the HTML5 Spec:
A valid browsing context name is any string with at least one character that does not start with a U+005F LOW LINE character. (Names starting with an underscore are reserved for special keywords.)
A valid browsing context name or keyword is any string that is either a valid browsing context name or that is an ASCII case-insensitive match for one of: _blank, _self, _parent, or _top." - Source
That means that there is no such keyword as _new
in HTML5, and not in HTML4 (and consequently XHTML) either. That means, that there will be no consistent behavior whatsoever if you use this as a value for the target attribute.
Security recommendation
As Daniel and Michael have pointed out in the comments, when using target _blank
pointing to an untrusted website, you should, in addition, set rel="noopener"
. This prevents the opening site to mess with the opener via JavaScript. See this post for more information.
New target column based on a pattern
First create a dict for mapping the target, then apply it to every target
m = dict((zip(df.source, df.target)))
def mapper(x):
for i in range(len(m)):
x = m.get(x, x)
return x
df["new_target"] = df.target.apply(mapper)
How to target the selector on new tab after clicking a[target= _blank ] - Failing to activate the new tab created
managed to solve this together (Linker :)
Process
First, we mapped the target being created to check for focus
browser.on('targetcreated', function (target) {
console.log('New tab:');
console.log(target);
});
We saw the URL is trying to open - for some reason the URLs in the target were empty. We re-installed stuff to rule out weird dependency bugs, then figured there's a focus issue.
Workaround
To solve it, we need to wait for the .newPage()
to open before goto
'ing to the URL, calling bringToFront()
and then waiting for it to load (short sleep is the easy way). Once we did that, we had a working POC to start from.
Relevant part from the solution:
let mappedURL = tabs
.map((e, index) => e.url())
.filter((e, idx) => idx == 2)
console.log("MAPPED URL ", mappedURL)
sleep(2500)
const page3 = await browser.newPage()
await page3.goto(`${mappedURL}`)
await page3.bringToFront()
Ref
Here's a cool SO Answer showing how to use once
syntax to test the event. Happy we were able to solve it, and I hope the process helps other people out.
Related Topics
Why Are Callbacks from Promise '.Then' Methods an Anti-Pattern
Detect Ie Version (Prior to V9) in JavaScript
Using Jquery's Ajax Method to Retrieve Images as a Blob
JavaScript Document.Getelementsbyclassname Compatibility with Ie
JavaScript Filter Array of Objects
Is Right Click a JavaScript Event
How to Share $Scope Data Between States in Angularjs Ui-Router
How to Get the Text Node of an Element
Browsers, Time Zones, Chrome 67 Error (Historic Timezone Changes)
Node.Js on Multi-Core MAChines
Jquery Load More Data on Scroll
How to Loop Through an Array Containing Objects and Access Their Properties
How to Pass JSON Post Data to Web API Method as an Object
Two Sets of Parentheses After Function Call