I have been reading through the dojo 1.9 documentation about declare.safeMixin(), focusing on the difference between it and lang.mixin.
Here is the explanation I found...
safeMixin() is a function defined in dojo/declare. It has the same functionality as dojo/_base/lang::mixin(), but additionally it annotates all copied methods compatibly with dojo/declare. This decoration can affect how this.inherited() works in mixed-in methods.
I can follow the example but it doesn't really explain exactly what is added and where, can anyone give any further examples of what annotation is added to each copied method?
So to be clear, I'm not asking for an explanation of inheritance, I'm just asking specifically about the annotations added by using declare.safeMixin() instead of lang.mixin.
Using safeMixin allows you to mix functions into an instance that can take advantage of this.inherited the same way that prototype methods defined using declare can.
For example, the following will log 2 messages:
require([
"dojo/_base/lang",
"dojo/_base/declare"
], function(lang, declare){
var A = declare(null, {
method: function () {
console.log('method in prototype');
}
});
var a = new A();
declare.safeMixin(a, {
method: function () {
this.inherited(arguments);
console.log('method in instance');
}
});
a.method();
});
Without safeMixin, you wouldn't be able to call this.inherited(arguments) from the overriding method (at least, not without additional parameters) - you'd end up getting an error:
Error: declare: can't deduce a name to call inherited()
safeMixin adds the nom property to functions that are mixed in to the target. This property is set to the key from the source object that the function was assigned to. e.g. if you call declare.safeMixin(target, { foo: function() {} }), the nom property for that function is "foo". This is necessary for this.inherited(arguments) to automatically figure out that it should call the parent "foo". The alternative to using safeMixin would be to explicitly specify the name of the parent function: this.inherited('foo', arguments);.
Related
I need to compile my code with closure compiler in ADVANCED mode. I also need to keep prototypes of my objects in my application because I'm looping on Javascript objects prototypes. Trying to get both results in some ReferenceError when starting the application.
When compiling with ADVANCED mode, some prototypes are removed and replaced by a function that is using an object parameter in order to recover "this" keyword. This is due to crossModuleCodeMotionNoStubMethods attribute of CompilerOptions.java.
Example of code before compilation :
function MyClass() = { // Some code }
MyClass.prototype.someFunc = function() { // Some code calling someOtherFunc };
MyClass.prototype.someOtherFunc = function(someParam) { // Some code };
Example of code after compilation :
function MyCompiledClass = { // Some code }
MyCompiledClass.prototype.someCompiledFunc = function() { // Some code calling someOtherFunc }
function someOtherCompiledFunc(that, someParam) = { // Some code }
I first tried to use #this and #preserve JSDoc tags to solve the problem, without success. Using #export is not a solution, because functions will then keep their original names.
I've found two options to solve my problem for now :
Refactor the code as seen here
Build a custom version of Closure Compiler as seen here
Option 1 will need to much modifications in my code and will make it less readable, if it's the only solution, I will have a go for this one.
Option 2 seems to be a nice workaround, but I've read that some changes on CompilationLevel.java may violate some core assumptions of the compiler. Can someone tell me if by modifying setCrossModuleMethodMotion from true to false, will it still respect all core assumptions of the compiler ?
I'm currently building a custom version of the compiler to check if the code is compiling properly, but even if the code is usable, I need to be sure it will be properly obfuscated.
Thank you !
The specific optimization pass you are referring to is DevirtualizePrototypeMethods. The best way to block the optimization would be to use the #nocollapse annotation. It will allow your method to be renamed but not allow it to be removed from the prototype.
I'm not 100% sure it will work for this case, but if it doesn't it should and you can file an issue to have that fixed: https://github.com/google/closure-compiler/issues
You can export constructors and prototype properties in the same way.
For example:
MyClass = function(name) {
this.myName = name;
};
MyClass.prototype.myMethod = function() {
alert(this.myName);
};
window['MyClass'] = MyClass; // <-- Constructor
MyClass.prototype['myMethod'] = MyClass.prototype.myMethod;
As in https://developers.google.com/closure/compiler/docs/api-tutorial3
I'm trying to update a Gnome-shell extension. In it, I override the _init method of an object, which I'm doing like this:
function newInitAppSwitcherPopup() {
this.parent();
...
}
AltTab.AppSwitcherPopup.prototype._init = newInitAppSwitcherPopup;
The new method fails with:
JS ERROR: TypeError: The method 'parent' cannot be called
What I find very surprising here is that the parent method actually exists (if I change the name I get a "not defined" error).
What I don't understand is that the original AppSwitcherPopup._init is still using this call to parent (https://git.gnome.org/browse/gnome-shell/tree/js/ui/altTab.js?h=gnome-3-16#n54).
This was working well under Gnome 3.12, but is broken for Gnome 3.16...I guess they changed something in their GObject or inheritance models?
i have a similar code working for my config widget
const MenuConfigWidget = new GObject.Class({
Name: 'SimpleMenu.Prefs.MenuConfigWidget',
GTypeName: 'SimpleMenuMenuConfigWidget',
Extends: Gtk.Grid,
_init: function(params) {
this.parent({... });
...
}
});
Do you extend the class our just monkey patch the _init function?
I'm implementing a client-side application using ECMAScript6 and use JSHint for static code analysis. I often use the following pattern in my code:
class MyClass {
constructor() {
//This is how I would like to call myMethod
myMethod();
//This is how I should call myMethod to make JSHint analysis pass
this.myMethod();
}
myMethod(){
//Implementation
}
}
My primary language is Java so I expect that simply calling myMethod() should be ok. However without adding this to method call I'm getting "'myMethod' is not defined" warning from JSHint. My questions are:
Is it correct to make calls without this in such situation? (e.g. in PHP you always need to add $this-> to non-static method call)
If that's correct to make calls without this is there any way (any .jshintrc flag) to turn off this warning in JSHint?
No, this is and never was correct in JavaScript. Methods always need to be called on a receiver explicitly to make this work, and they need to be referred to using property access notation because methods are just functions on properties in javascript. They're not available as functions in the scope of your other methods. It's the same for properties, btw.
JsHint is right here, and there's no reason to turn that warning off. Even if that may possible, executing your program in spite of that would just make it not work.
Is it correct to make calls without this in such situation? (e.g. in
PHP you always need to add $this-> to non-static method call)
No, it is not. You always have to specify the receiver of the method.
If that's correct to make calls without this is there any way (any
.jshintrc flag) to turn off this warning in JSHint?
JSHint returns "'myMethod' is not defined" warning correctly as there is not function called myMethod in the scope of the constructor.
In the code you provided the identifier myMethod isn't defined, but the inherited property myMethod of instances of MyClass is defined.
If you define myMethod as a Function under a closure which isn't available elsewhere then you can access as it in the form you desire
var MyClass = (function () {
function myMethod() {
//Implementation
}
class MyClass {
constructor() {
myMethod();
}
}
return MyClass;
}());
I don't get to write much ES6 so I'm not sure if putting the function myMethod inside MyClass's definition is a SyntaxError
Please note however that this is required to reference your specific instance of MyClass, so you'll probably need to use it somewhere if you want MyMethod to act on the instance.
function myMethod(obj) {...}
// ...
myMethod(this);
If you read the MDN's description of class
JavaScript classes are introduced in ECMAScript 6 and are syntactical sugar over JavaScript's existing prototype-based inheritance. The class syntax is not introducing a new object-oriented inheritance model to JavaScript. JS classes provide a much simpler and clearer syntax to create objects and dealing with inheritance.
This is saying using class is just shorthand for the old way of doing it, not a new model, so it may be easier to think of what your current code would look like if written in ES5,
var MyClass = (function () {
function MyClass() {
this.constructor.apply(this, arguments);
}
MyClass.prototype = Object.create(null);
MyClass.prototype.constructor = function () {
myMethod(); // referenceError
this.myMethod(); // works
};
MyClass.prototype.myMethod = function () {
//Implementation
};
return MyClass;
}());
I've seen quite a few tutorials or code examples where the developer used either Underscore's _.extend method or Lodash's _.assign method when a simply adding the property would have sufficed, it's always confused me, what is the benefit of using extend/assign instead of simply adding the property? There are plenty of times where I can see the benefits of using these methods, when adding multiple properties from another object for instance but most often I've seen it used as in the example below where I don't see any benefit.
Is there a benefit that I am not aware of for the following code instead of assigning the property?
http://tech.pro/tutorial/1734/building-decoupled-javascript-applications-with-postaljs
var Weather = function() {
this.channel = postal.channel( "weather" );
this.channel.subscribe( "fetch", this.fetch ).withContext( this );
};
_.extend(Weather.prototype, {
fetch: function( city ) {
$.ajax({
url: "http://openweathermap.org/data/2.1/find/name?q=" + city + "&units=imperial",
dataType: "jsonp",
success: _.bind(function( data ) {
this.channel.publish( "fetched", data.list[ 0 ] );
}, this )
});
}
});
For instance, couldn't the above code be rewritten thusly:
Weather.prototype.fetch = function(...){...}
Or is there a negative to this?
It exists for the same reason jQuery has $.extend (including an npm port) and it has nothing to do with performance: to add one object's properies to a another object, thereby extending one with the other. Lodash' version allows for some more fine-grained control over the merge process using a customizer function.
Extending objects has a couple of uses, of which one is stated by the jQuery developers on writing plugins:
An improvement we can, and should, make to the code above is to expose the default plugin settings. This is important because it makes it very easy for plugin users to override/customize the plugin with minimal code. And this is where we begin to take advantage of the function object.
// Plugin definition.
$.fn.hilight = function( options ) {
// Extend our default options with those provided.
// Note that the first argument to extend is an empty
// object – this is to keep from overriding our "defaults" object.
var opts = $.extend( {}, $.fn.hilight.defaults, options );
// Our plugin implementation code goes here.
};
// Plugin defaults – added as a property on our plugin function.
$.fn.hilight.defaults = {
foreground: "red",
background: "yellow"
};
In the above example you can clearly see that with are dealing with a preset object with properties, which needs to be extended or even overwritten by an unknown object with unknown properties, because that object is out of the plugin-developer's control
Sometimes we simply don't know which properties are on the extension object, sometimes it just makes things more readable and sometimes it is just to cumbersome to do it manually especially if you need a deep merge.
Another application is where you want to simulate a simple inheritance hierarchy:
// very trivial example:
var Super = { superFoo: function() {} };
var Sub1 = { sub1Foo: function() {} };
var Sub2 = { sub2Foo: function() {} };
$.extend(Sub1, Super) // now Sub1 has Super powers
$.extend(Sub2, Super) // now Sub2 has Super powers too
In many cases, using Object.assign() (or the library-provided equivalent) lets one write in a more functional style. Instead of using multiple statements just to add a single property to an object, you can do everything in one big expression.
Procedural:
function doThing(options) {
options.x = 5;
return _doThing(options);
}
Functional:
function doThing(options) {
_doThing(Object.assign(options, {x: 5}));
}
Also, if used with an empty object it idiomatically creates a shallow copy so as not to disturb a passed-in object in ways that might confuse the caller:
function doThing(options) {
_doThing(Object.assign({}, options, {x: 5}));
}
Basically Dub and Dub.socialize objects already exist as an included library. I'm trying to extend the library with some additional custom functions that I created.
I attempted the following concept below:
Dub.socialize = {
setUID : function(preUID, postUID)
{
// .. function code here
}
}
However, I receive the following error "Uncaught TypeError: Cannot set property 'setUID' of undefined" from my console.
Obviously my knowledge of objects is a bit misled. What would be the proper method of extending this function into the already existing object library?
A simple solution could be
Dub.socialize.setUID = function(preUID, postUID) {};
Try this:
Dub.socialize.prototype.setUID = function(preUID, postUID) {
...
};
Object Constructor and prototyping
Edit: Realized you're working with a "static" object. This only works for something that is instantiated, and since you're not making new instances, this doesn't apply.
If you are going to create the function for declared object means then you have to use "prototype" keyword for example.
`var Dub = {
socialize: new Object()
};
Dub.socialize.prototype.setUID = function(preUID, postUID) {
// Function Body
};`
http://www.javascriptkit.com/javatutors/proto3.shtml