General Object Initiating Function by the Example of $injector.instantiate Implementation in angular

前端之家收集整理的这篇文章主要介绍了General Object Initiating Function by the Example of $injector.instantiate Implementation in angular前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。





General Object Initiating Function by the Example of $injector.instantiate Implementation in angularjs


fsou11, 8 Jun 2017
The article discovers object instantiating within angularjs applications in details and contains an example of universal function implementation


Have you ever thought about initiating objects within your angularjs applications? Controllers,factories,services,decorators and even values - all of them finally are created using the instantiating method of the$injectorclass and here is a very interesting line code that I'd like to discover for you.

Today I'm going to describe the next code line:

return new (Function.prototype.bind.apply(ctor,args))();

Is the work principle of this line obvIoUs to you? If the answer is "Yes",so,thanks for your time and patience,hope to see you in next articles. :)

Now,when all the readers who cut their teeth on JavaScript have left us,I'd like to answer my own question: When I saw this line for the first time,I was confused and didn't understand anything about these "relationships" amongbind,apply,0)">newand(). Let's try to puzzle out! I offer to start doing it from the end,meaning: assume that we have some parameterized constructor,the instance of which we would like to instantiate:

function Animal(name,sound) {
  this.name = name;
  this.sound = sound;
}

new

"What could be easier?" - you would say and will be absolutely right:

var dog = new Animal('Dog',Woof!'); 

Thenewoperator is the first thing that we will need if we'd like to get a new instance of theAnimalconstructor. Let me give you some details about thenewoperator usage details:

Quote:

When the code new Foo(...) is executed,the following things happen:

  1. A new object is created,inheriting from Foo.prototype.@H_403_229@
  2. The constructor function Foo is called with the specified arguments,and with this bound to the newly created object. new Foo is equivalent to new Foo(),i.e. if no argument list is specified,Foo is called without arguments.@H_403_229@
  3. The object returned by the constructor function becomes the result of the whole new expression. If the constructor function doesn't explicitly return an object,the object created in step 1 is used instead. (Normally constructors don't return a value,but they can choose to do so if they want to override the normal object creation process.)@H_403_229@

For further details:https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/new

Great,now let's wrap ourAnimalconstructor execution with the function to make it common for all possible calls in the application:

function CreateAnimal(name,sound) { 
  new Animal(name,sound); 
}

After a while,we decide to initiate not only an animal but also a human being (I agree with you,this is not the best example ever) and this means that we have at least 2 possible ways to achieve it:

  1. Implement the factory which will initiate the required constructor instance itself depending on the required type@H_403_229@
  2. Extend the declaration of our current function with an argument that should contain the constructor function and,based on this constructor,return the new function with the bounded arguments (and in this casebindis really helpful)@H_403_229@

In case of$injector.instantiateimplementation,the second point was chosen.

bind

function Create(ctorFunc,name,255)">new (ctorFunc.bind(null,sound)); 
} 

console.log( Create(Animal,128)">Woof') ); 
console.log( Create(Human,128)">Person') );

Let me give you some details aboutbindfunction usage details:

The bind() method creates a new function that,when called,has its this keyword set to the provided value,with a given sequence of arguments preceding any provided when the new function is called.

For further details:https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Function/bind

In our case,we passnullasthisbecause we are going to use the returned frombindfunction with the new operator,which ignores existingthisand replaces it with a new empty object. The result of thebindfunction call is the new function with the already bounded arguments (in other words,0)">return new fn;wherefnis thebindcall result).

Excellent,now we can use ourCreatefunction to create any animals and human beings whose constructors... are declared with thenameandsoundarguments. "But it's not true that all the arguments that are required for animal constructors will be required for human constructors in the same way" - you could reply and will be absolutely right again. And there are 2 problems that we could notice:

  1. Constructor declaration can vary or be changed (for example,the order or quantity of parameters),which means that we have to make changes simultaneously in a few places: constructor declaration,lines of code that call theCreatefunction and instantiating line of the instancereturn new (ctorFunc.bind(null,sound));@H_403_229@
  2. The more constructors we have,the higher chance that required arguments will be different and we won't be able to continue using the sameCreatefunction (otherwise,we have to pass all the declared arguments for each constructor,but use only the required ones).@H_403_229@

apply

<Meta charset="utf-8" />The transparent passing arguments from theCreatefunction directly to the constructor could become the solution of the above problems,in other words - the universal function that accepts the constructor and required by-passed constructor array of arguments and returns a new function with the already bounded arguments. There is a wonderful function namedapplyin JavaScript for this case (or its analogue namedcallif we know the number of arguments beforehand).

Let me give you a small excursus aboutapplyfunction usage details:

The apply() method calls a function with a given this value,and arguments provided as an array (or an array-like object).

apply is very similar to call(),except for the type of arguments it supports. You use an arguments array instead of a list of arguments (parameters).

For further details:https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Function/apply

<Meta charset="utf-8" />I think here is the most difficult part of the article,because first of all,we have toapplyour constructor asbindfunctionthiskeyword (similarly toctorFunc.bind). Secondly,we have to pass the shifted right by 1 constructor arguments usingctorArgs.unshift(null)tobindfunction (as we remember,the first argument of the bind function will be used asthisfunction's keyword).

bindfunction is not accessible inside theCreate,because thewindowobject is used as the function context and that's why we have to access it usingFunction.prototype.

Finally,we get the next universal instantiating function:

null); 
  new (Function.prototype.bind.apply(ctorFunc,ctorArgs )); 
} 

console.log( Create(Animal,[Woof']) ); 
console.log( Create(Human,128)">Person',128)">John',128)">Engineer',128)">Moscow']) );

If we return to angularJS,we will notice thatAnimalandHumanare used precisely as factory constructors,and their array arguments are represented by found and resolved dependencies.

angular
  .module(app')
  .factory(function($scope) {
    // constructor 
  });

or:

angular
  .module(app')
  .factory([$scope', constructor 
  }]);

All we have to do at the final stage of implementing our own$injector.instantiatemethod is to find out the instantiating instance constructor,receive (as possible resolve) the required arguments and that's it. :)

Feel free to send comments,vote and thank you for reading. Hope to see you in the next articles.

License

This article,along with any associated source code and files,is licensed underThe Code Project Open License (CPOL)

原文链接:https://www.f2er.com/angularjs/146841.html

猜你在找的Angularjs相关文章