This question is a follow-up to this one. For some reason I'm coming back to JS after 7 years and boy, I can hardly recognize the dear old beast.
Purely for educational purpose, I decided to rewrite naive implementations of the various things Function.prototype.bind() allows to do. It's just an exercise to try to understand what's going on and spark a few questions.
I would be happy to stand corrected for all the mistakes and misunderstandings in my examples and comments.
Also, this code is not mine. I got the idea from a blog and only slightly tweaked it, but unfortunately I lost track of the source. If anyone recognizes the original, I'll be happy to give due credit. Meanwhile, I apologize for the blunder.
Naive binding
The initial idea is simply to do what lambda calculus savvies apparently call a "partial application", i.e. fixing the value of the first parameters of a function, that also accepts an implicit "this" first parameter, like so:
Function.prototype.naive_bind = function (fixed_this, ...fixed_args) {
const fun = this; // close on the fixed args and the bound function
return function(...free_args) { // leave the rest of the parameters free
return fun.call(fixed_this, ...fixed_args, ...free_args);
}
}
Binding constructors (1st round)
class class1 {
constructor (p1, p2) {
this.p1 = p1;
this.p2 = p2;
}
}
var innocent_bystander = { "huh?":"what?" }
var class2 = class1.naive_bind(innocent_bystander);
class2 (1,2) // exception: class constructor must be invoked with new (as expected)
console.log(new class2(1,2)) // exception: class constructor must be invoked with new (Rats!)
function pseudoclass1 (p1, p2) {
this.p1 = p1;
this.p2 = p2;
}
var pseudoclass2 = pseudoclass1.naive_bind(innocent_bystander);
pseudoclass2 (1,2) // same exception (as expected)
console.log(new pseudoclass2(1,2)) // same again (at least it's consistent...)
Tonnerre de Brest ! Apparently the runtime is not happy with a mere wrapper based on Function.prototype.call().
It seems the real bind() is adding the dollop of secret sauce needed to give the generated function the appropriate "constructor" flavour (Apparently by "constructor" the ECMA 262 specification does not mean a class constructor, but any function that can be invoked with "new" and use "this" to populate the properties and methods of a freshly created object)
Binding other functions
var purefunction1 = console.log
var purefunction2 = purefunction1.naive_bind (null, "Sure,", "but")
purefunction2 ("you can still", "bind pure", "functions")
// sure, but you can still bind pure functions
// ...and make animals talk (by binding simple methods)
var cat = { speech: "meow" }
var dog = { speech: "woof" }
var fish= { speech: "-" }
var talk = function(count) { console.log ((this.speech+", ").repeat(count-1) + this.speech + "!") }
talk.naive_bind (cat,1)(); // meow!
talk.naive_bind (dog,1)(); // woof!
talk.naive_bind (cat)(3) // meow, meow, meow!
talk.naive_bind (fish)(10) // -, -, -, -, -, -, -, -, -, -!
// and bind arrow functions
// ("this" is wasted on them, but their parameters can still be bound)
var surprise = (a,b,c) => console.log (this.surprise, a,b,c)
var puzzlement = surprise.naive_bind(innocent_bystander, "don't", "worry");
// "this" refers to window, so we get our own function as first output.
surprise ("where", "am", "I?") // function surprise(a, b, c) where am I?
// the bound value of this is ignored, but the other arguments are working fine
puzzlement("dude") // function surprise(a, b, c) don't worry dude
Apparently, everything works as expected. Or did I miss something?
Binding constructors (2nd round)
We apparently can't get away with passing a wrapper to new, but we can try invoking new directly.
Since the value of this is provided by new, the construction-specialized wrapper has only to worry about real constructor parameters.
Function.prototype.constructor_bind = function (...fixed_args) {
const fun = this;
return function(...free_args) {
return new fun (...fixed_args, ...free_args);
}
}
var class1_ctor = class1.constructor_bind(1);
console.log (class1_ctor(2)) // class1 { p1:1, p2:2 }
var monster = (a,b) => console.log ("boooh", a, b)
var abomination = monster.constructor_bind(1);
console.log (abomination(2)) // exception: fun is not a constructor (as expected)
Well, that seems to cut it. I imagine the real bind() is far safer and faster, but at least we can reproduce the basic functionalities, namely:
providing a fixed value of this to methods
doing partial applications on any legit function, though constructors require a specific variant
edit: questions removed to comply with SO policy.
Replaced by just one, the one that matches the title of this post, and that I tried to explore by providing a naive and possibly erroneous equivalent of what I thought the real function did:
Please help me understand how the native Function.prototype.bind() method works, according to the version 6.0 of the ECMAScript specification.
The only bit you have been missing is the introduction of new.target in ES6, which a) makes it possible to distinguish between [[call]] and [[construct]] in a function and b) needs to be forwarded in the new call.
So a more complete polyfill might look like this:
Function.prototype.bind = function (fixed_this, ...fixed_args) {
const fun = this;
return function(...free_args) {
return new.target != null
? Reflect.construct(fun, [...fixed_args, ...free_args], new.target)
: fun.call(fixed_this, ...fixed_args, ...free_args);
}
}
Some other details would involve that fun is asserted to be a function object, and that the returned bound function has a special .name, an accurate .length, and no .prototype. You can find these things in the spec, which apparently you've been reading already.
I am working on a large Flash project.
I have tried "Goto Declaration" but that doesn't seem help.
Btw I am using FlashDevelop. And Yes I can perfectly compile and build TO 100% working source.
Here is a code sample. I know you can't do much with this but tell how I can work with this.
public function aim_(_arg_1:Vector3D, _arg_2:Vector3D, _arg_3:ProjectileProperties):Vector3D
{
var _local_4:Vector3D;
var _local_5:GameObject;
var _local_6:Vector3D;
var _local_7:Number;
var _local_8:Number;
var _local_9:int;
var _local_10:Boolean;
var _local_11:int;
var _local_12:Boolean;
var _local_13:* = undefined;
var _local_14:int = Parameters.data_.aimMode;
var _local_15:Number = (_arg_3.speed_ / 10000);
var _local_16:Number = ((_local_15 * _arg_3.lifetime_) + ((Parameters.data_.Addone) ? 1 : 0));
var _local_17:Number = 0;
var _local_18:Number = int.MAX_VALUE;
var _local_19:Number = int.MAX_VALUE;
aimAssistTarget = null;
for each (_local_5 in map_.goDict_)
{
if (_local_5.props_.isEnemy_)
{
_local_10 = false;
for each (_local_11 in Parameters.data_.AAException)
{
if (_local_11 == _local_5.props_.type_)
{
_local_10 = true;
break;
};
};
What you're trying to achieve is reverse engineering a decompiled code. With "_local" variables you need to investigate what values they are assigned, in what algorithms do they participate, and here you just need to read this single function in its entirety to be able to discern meaning of those local variables. But, you would also need to understand many of the named parameters to get some of those meanings. For example, _local_11 iterates through some Parameters.data_.AAException list of ints, and is compared with current outside loop iterator's props.type_, therefore "AAException" should mean "AA exemption" and _local_10 provides check result, whether current enemy is exempt from AA (whatever is that AA). And so on.
Same with _arg_X variables, you need to find out what's being passed into a function from wherever it's called, and retrieve the context of those parameters, also taking their type into consideration, like here _arg3 is of type "ProjectileProperties", meaning this function should relate to some projectile which properties affect its outcome somehow. Most likely it's taking two vectors of projectile (or source, this is outside of this code) and target (or speed, same here), and generates another vector of yet unknown purpose.
When you have investigated every function like this, you'll have quite a bunch of pieces to a single puzzle that you can combine by references, discovering all the algorithms that combine the code of whatever app you've decompiled. Then you will be able to do targeted modifications of whatever kind you wanted initially. But yes, it'll be better if you'd have access to actual sources from whoever created this the first time.
In short: Think. Think, think and think.
I used to work on AS2 and make games, and now I wanna learn AS3 and have all its nice features (using Flash CS IDE). Now I m trying to rewrite a function to discard it.
function something():void{
//do something
}
function something():void{}
like this. please help or just give some alternatives, thanks.
What you're trying to do is very illogical - a function should be defined once and exist always. Not only that, but it should definitely always behave the same way, especially considering AS3 does not support overloading.
AS3 introduces the OOP paradigm for you to use - this further emphasises the above - you should create classes which define a fixed collection of properties and methods. This way, the intent of each class in your application is clear, and what you expect something to be able to do won't change.
If you absolutely must be able to delete functions, you can assign them to a dynamic object and remove or redefine them with the delete keyword:
var methods:Object = {
something: function():void
{
trace('Still here.');
}
};
methods.something(); // Still here.
delete methods.something;
methods.something(); // TypeError: something is not a function.
methods.something = function():void
{
// Define new function.
}
Or assign an anonymous function to a variable of type Function, from which point you can set the reference to null:
var something:Function = function():void
{
trace("Still here.");
}
something(); // Still here.
something = null;
something(); // TypeError: value is not a function.
something = function():void
{
// Define new function.
}
Okay so I have a function called changeHandler - it is called by several eventListeners in other functions. I want to write several if statements that evaluate the source of function call and change the dataProvider of my ComboBox depending on the originating function. Example: one of the many functions is called displayCarbs() and has an eventListener like so:
function displayCarbs(event:MouseEvent):void {
myComboBox.addEventListener(Event.CHANGE, changeHandler);
}
(I've removed all of the unnecessary code from the function above)
The if statement inside the changeHandler will look something like this:
if (****referring function = displayCarbs****) {
myComboBox2.dataProvider = new DataProvider(carbItems);
}
I've searched high and low for something that can achieve this, but I just don't have a good enough grasp of AS3 or vocabulary to describe what describe what I mean to get the answer from Google.
The simplest way I can think of... Couldn't you simply create a text string that updates to the name of function before going to changeHandler then in turn changeHandler can check string content and act accordingly..
public var referring_function:String;
function displayCarbs(event:MouseEvent):void
{
referring_function = "displayCarbs";
myComboBox.addEventListener(Event.CHANGE, changeHandler);
}
function displayCarbs(event:Event):void
{
if (referring_function == "displayCarbs")
{ myComboBox2.dataProvider = new DataProvider(carbItems); }
if (referring_function == "displayOthers")
{ myComboBox2.dataProvider = new DataProvider(otherItems); }
// etc etc
}
I cant remember right now if you need == or just = when checking the If statement against strings.
I know there is an accepted answer already, but based on what I gleaned about the problem, here is a solution that wouldn't require adding another variable to check :
function displayCarbs(event:MouseEvent):void
{
myComboBox.addEventListener(Event.CHANGE, changeHandler);
}
function changeHandler(event:Event):void
{
var comboBox:ComboBox = event.target as ComboBox;
if (comboBox.dataProvider == uniqueProvider)
{
myComboBox2.dataProvider = new DataProvider(appropriateItems);
}
}
This should work if the second dataProvider is determined based on the first dataProvider. This of course requires that your uniqueProvider is a class member variable so it has scope within the handler.
Can anyone tell me how to make a function that works like below in ActionScript3.0?
function test(one:int){ trace(one);}
function test(many:Vector<int>){
for each(var one:int in many){ test(one); }
}
You can use an asterisk and the is keyword:
function test(param:*):void
{
if(param is int)
{
// Do stuff with single int.
trace(param);
}
else if(param is Vector.<int>)
{
// Vector iteration stuff.
for each(var i:int in param)
{
test(i);
}
}
else
{
// May want to notify developers if they use the wrong types.
throw new ArgumentError("test() only accepts types int or Vector.<int>.");
}
}
This is seldom a good approach over having two sepaprate, clearly labelled methods, because it can be hard to tell what that methods' intent is without a specific type requirement.
I suggest a more clear set of methods, named appropriately, e.g.
function testOne(param:int):void
function testMany(param:Vector.<int>):void
Something that could be useful in this particular situation is the ...rest argument. This way, you could allow one or more ints, and also offer a little more readability for others (and yourself later on) to understand what the method does.
function test(many:*):void {
//now many can be any type.
}
In case of using Vector, this also should work:
function test(many:Vector.<*>):void {
//now many can be Vector with any type.
}