What does "this._events || (this._events = {});" mean? - javascript

I have started learning Backbone.js. Currently my JavaScript skills are not too good. I have started to examine the backbone.js file and have come across a strange line of code whose purpose I can not figure out. Code sample (if you need more context, manually download backbone.js for developers and see line 80):
var Events = Backbone.Events = {
// Bind an event to a `callback` function. Passing `"all"` will bind
// the callback to all events fired.
on: function(name, callback, context) {
if (!eventsApi(this, 'on', name, [callback, context]) || !callback) return this;
this._events || (this._events = {});
var events = this._events[name] || (this._events[name] = []);
events.push({callback: callback, context: context, ctx: context || this});
return this;
},
What does the line this._events || (this._events = {}); mean? For me, _events looks like an inner variable, but is (this._events = {}) used for assignment or is it an or comparison? Or is || a completely different operation in this context?

It is a trick that uses javascripts "falsy" evaluation. It is the same as:
if (this._events) {
// do nothing, this._events is already defined
} else {
this._events = {};
}
The same goes for the line var events = this._events[name] || (this._events[name] = []); which could be translated to
var events;
if (this._events[name]) {
events = this._events[name];
} else {
this._events[name] = [];
events = this._events[name];
}

What line “this._events || (this._events = {});” means?
The logical OR (||) executes the first expression this._events and if falsy executes the second expression (this._events = {}).
In essence it checks if this._events is falsy and if so then assigns a new empty object to it.
That way no matter what this._events will always be at least an empty object and the code following will be able to execute without issues.

It's a way to write
if (!this._events) {
this._events = {};
}
In my opinion it's bad practice to use that kind of short hand, and I think the following line
var events = this._events[name] || (this._events[name] = []);
is even worse.
Mixing assignment, of the events with the creation of this._events[name] is quite short, but it's also hard to read. If you don't know what you're doing you might introduce subtle errors that way. That doesn't outweigh the benefits of having it all in one line.
And in the end it will be minified anyway. Let the minifiers take care of stuffing everything in one line. No need to do it yourself.

Related

OOP Question About Vanilla JS: The class's constructor won't accept the variable I'm feeding it as a parameter

I'm trying to learn OOP through practice, but I'm pretty stuck at this point.
This is the code:
const itemEdit = () => {
let editIndex = buttonObj.editArr.indexOf(editID);
console.log(`the editIndex outside of the class is ${editIndex}`);
if (typeof editIndex != "undefined") {
editText = new htmlTextualizer(editIndex);
console.log(
"new class successfully created as variable is not 'undefined' type"
);
}
editText.printOut();
This is the class/constructor:
class htmlTextualizer {
constructor(curr) {
this.curr = curr;
}
printOut() {
console.log(this.curr);
}
}
The output is either 'undefined' or nothing at all. The logic generally works outside of the function, so I suspect it's something to do with the scope of initiation, but I simply fail to work my way around it. Assistance would be much appreciated. Thanks.
JavaScript's indexOf() returns -1 if no match is found. That check should look something like this:
if (editIndex > -1) {…}
I'm not sure if that will resolve your problem or not, but it's a problem in general.
Also, if that if statement is not true, and if editText is not defined somewhere outside what you've pasted here, there will be an error because editText is undefined (and doesn't have methods available).
There are several things that are unclear about your example, since you reference several undefined objects: buttonObj.editArr, editID, editText.
In general, I would approach testing for existence more carefully. You don't want to attempt to access the indexOf method on something undefined.
I'm not sure what your business logic is exactly, but here is how to do what I think it is: always create the new object, unless buttonObj.editArr contains editID.
Here is how to do that:
const itemEdit = () => {
if ( !buttonObj ||
!buttonObj.editArr ||
(typeof buttonObj.editArr !== "object") ||
!editID ||
(buttonObj.editArr.indexOf(editID) < 0) ) {
editText = new htmlTextualizer(buttonObj.editArr.indexOf(editID));
console.log("creating instance of class htmlTextualizer");
}
}

JS-Interpreter - changing “this” context

JS-Interpreter is a somewhat well-known JavaScript Interpreter. It has security advantages in that it can completely isolate your code from document and allows you to detect attacks such as infinite loops and memory bombs. This allows you to run externally defined code safely.
I have an object, say o like this:
let o = {
hidden: null,
regex: null,
process: [
"this.hidden = !this.visible;",
"this.regex = new RegExp(this.validate, 'i');"
],
visible: true,
validate: "^[a-z]+$"
};
I'd like to be able to run the code in process through JS-Interpreter:
for (let i = 0; i < o.process.length; i++)
interpretWithinContext(o, o.process[i]);
Where interpretWithinContext will create an interpreter using the first argument as the context, i.e. o becomes this, and the second argument is the line of code to run. After running the above code, I would expect o to be:
{
hidden: false,
regex: /^[a-z]+$/i,
process: [
"this.hidden = !this.visible;",
"this.regex = new RegExp(this.validate, 'i');"
],
visible: true,
validate: '^[a-z]+$'
}
That is, hidden and regex are now set.
Does anyone know if this is possible in JS-Interpreter?
I’ve spent a while messing around with the JS-Interpreter now, trying to figure out from the source how to place an object into the interpreter’s scope that can be both read and modified.
Unfortunately, the way this library is built, all the useful internal things are minified so we cannot really utilize the internal things and just put an object inside. Attempts to add a proxy object also failed failed since the object just wasn’t used in a “normal” way.
So my original approach to this was to just fall back to providing simple utility functions to access the outside object. This is fully supported by the library and probably the safest way of interacting with it. It does require you to change the process code though, in order to use those functions. But as a benefit, it does provide a very clean interface to communicate with “the outside world”. You can find the solution for this in the following hidden snippet:
function createInterpreter (dataObj) {
function initialize (intp, scope) {
intp.setProperty(scope, 'get', intp.createNativeFunction(function (prop) {
return intp.nativeToPseudo(dataObj[prop]);
}), intp.READONLY_DESCRIPTOR);
intp.setProperty(scope, 'set', intp.createNativeFunction(function (prop, value) {
dataObj[prop] = intp.pseudoToNative(value);
}), intp.READONLY_DESCRIPTOR);
}
return function (code) {
const interpreter = new Interpreter(code, initialize);
interpreter.run();
return interpreter.value;
};
}
let o = {
hidden: null,
regex: null,
process: [
"set('hidden', !get('visible'));",
"set('regex', new RegExp(get('validate'), 'i'));"
],
visible: true,
validate: "^[a-z]+$"
};
const interprete = createInterpreter(o);
for (const process of o.process) {
interprete(process);
}
console.log(o.hidden); // false
console.log(o.regex); // /^[a-z]+$/i
<script src="https://neil.fraser.name/software/JS-Interpreter/acorn_interpreter.js"></script>
However, after posting above solution, I just couldn’t stop thinking about this, so I dug deeper. As I learned, the methods getProperty and setProperty are not just used to set up the initial sandbox scope, but also as the code is being interpreted. So we can use this to create a proxy-like behavior for our object.
My solution here is based on code I found in an issue comment about doing this by modifying the Interpreter type. Unfortunately, the code is written in CoffeeScript and also based on some older versions, so we cannot use it exactly as it is. There’s also still the problem of the internals being minified, which we’ll get to in a moment.
The overall idea is to introduce a “connected object” into the scope which we will handle as a special case inside the getProperty and setProperty to map to our actual object.
But for that, we need to overwrite those two methods which is a problem because they are minified and received different internal names. Fortunately, the end of the source contains the following:
// Preserve top-level API functions from being pruned/renamed by JS compilers.
// …
Interpreter.prototype['getProperty'] = Interpreter.prototype.getProperty;
Interpreter.prototype['setProperty'] = Interpreter.prototype.setProperty;
So even if a minifier mangles the names on the right, it won’t touch the ones on the left. So that’s how the author made particular functions available for public use. But we want to overwrite them, so we cannot just overwrite the friendly names, we also need to replace the minified copies! But since we have a way to access the functions, we can also search for any other copy of them with a mangled name.
So that’s what I’m doing in my solution at the beginning in patchInterpreter: Define the new methods we’ll overwrite the existing ones with. Then, look for all the names (mangled or not) that refer to those functions, and replace them all with the new definition.
In the end, after patching the Interpreter, we just need to add a connected object into the scope. We cannot use the name this since that’s already used, but we can just choose something else, for example o:
function patchInterpreter (Interpreter) {
const originalGetProperty = Interpreter.prototype.getProperty;
const originalSetProperty = Interpreter.prototype.setProperty;
function newGetProperty(obj, name) {
if (obj == null || !obj._connected) {
return originalGetProperty.call(this, obj, name);
}
const value = obj._connected[name];
if (typeof value === 'object') {
// if the value is an object itself, create another connected object
return this.createConnectedObject(value);
}
return value;
}
function newSetProperty(obj, name, value, opt_descriptor) {
if (obj == null || !obj._connected) {
return originalSetProperty.call(this, obj, name, value, opt_descriptor);
}
obj._connected[name] = this.pseudoToNative(value);
}
let getKeys = [];
let setKeys = [];
for (const key of Object.keys(Interpreter.prototype)) {
if (Interpreter.prototype[key] === originalGetProperty) {
getKeys.push(key);
}
if (Interpreter.prototype[key] === originalSetProperty) {
setKeys.push(key);
}
}
for (const key of getKeys) {
Interpreter.prototype[key] = newGetProperty;
}
for (const key of setKeys) {
Interpreter.prototype[key] = newSetProperty;
}
Interpreter.prototype.createConnectedObject = function (obj) {
const connectedObject = this.createObject(this.OBJECT);
connectedObject._connected = obj;
return connectedObject;
};
}
patchInterpreter(Interpreter);
// actual application code
function createInterpreter (dataObj) {
function initialize (intp, scope) {
// add a connected object for `dataObj`
intp.setProperty(scope, 'o', intp.createConnectedObject(dataObj), intp.READONLY_DESCRIPTOR);
}
return function (code) {
const interpreter = new Interpreter(code, initialize);
interpreter.run();
return interpreter.value;
};
}
let o = {
hidden: null,
regex: null,
process: [
"o.hidden = !o.visible;",
"o.regex = new RegExp(o.validate, 'i');"
],
visible: true,
validate: "^[a-z]+$"
};
const interprete = createInterpreter(o);
for (const process of o.process) {
interprete(process);
}
console.log(o.hidden); // false
console.log(o.regex); // /^[a-z]+$/i
<script src="https://neil.fraser.name/software/JS-Interpreter/acorn_interpreter.js"></script>
And that’s it! Note that while that new implementation does already work with nested objects, it may not work with every type. So you should probably be careful what kind of objects you pass into the sandbox. It’s probably a good idea to create separate and explicitly safe objects with only basic or primitive types.
Have not tried JS-Interpreter. You can use new Function() and Function.prototype.call() to achieve requirement
let o = {
hidden: null,
regex: null,
process: [
"this.hidden = !this.visible;",
"this.regex = new RegExp(this.validate, 'i');"
],
visible: true,
validate: "^[a-z]+$"
};
for (let i = 0; i < o.process.length; i++)
console.log(new Function(`return ${o.process[i]}`).call(o));
Hi may be interpretWithinContext look like something like that ?
let interpretWithinContext = (function(o, p){
//in dunno for what you use p because all is on object o
o.hidden = (o.hidden === null) ? false : o.hidden;
o.regex = (o.regex === null) ? '/^[a-z]+$/i' : o.regex;
console.log(o);
return o;
});
https://codepen.io/anon/pen/oGwyra?editors=1111

Can a Knockout pureComputed work if it contains an observable that might not always exist?

Sorry if the question is poorly worded.
My problem is that I want to change an elements style based on a pureComputed but the computed contains an observable that may not always exist when the component is constructed, because the observable is from a different component and that component may not be constructed beforehand.
So I currently have something like this that I was hoping would be enough but doesn't work:
this.thingRunning = ko.pureComputed(function() {
if(app.thing){
return app.thing.running();
}else{
return false
}
}, this);
So problem is that if app.thing is initially undefined then this computed always returns false. app.thing does get defined eventually, just not before the computed so I'm hoping that I can have the computed return true when it does.
I know this may be a problem with how my app is set up in general but I'm just wondering if there's an easy way around this that I'm missing as I'm still quite a noob at Knockout and JavaScript in general.
Yes it definitely can!
However, with how things are structure right now you probably won't get a re-evaluation as you'd expect.
A better approach would be:
this.thingRunning = ko.pureComputed(function() {
var app = ko.unwrap(app) || {},
thing = ko.unwrap(app.thing) || {},
running = ko.unwrap(thing.running);
return ((typeof running == 'undefined' || running === null) ? false : running);
}, this);
Using this form, the dependencies of the pureComputed are very clear. More importantly they're properly registered, insofar that if any one of the three changes (and is one of the forms of subscribable) then this pureComputed will re-evaluate. It has the benefit of safely navigating the potentially non-existant values.
Here is a fully working example:
function vm(){
var self = this;
self.thing = ko.observable({
running: ko.observable(true)
});
};
function otherVm(appModel){
var self = this;
self.appModel = appModel;
self.thingRunning = ko.pureComputed(function(){
var app = ko.unwrap(self.appModel) || {},
thing = ko.unwrap(app.thing) || {},
running = ko.unwrap(thing.running);
return ((typeof running == 'undefined' || running === null) ? false : running);
});
};
var app = new vm(); //try commenting this out
var other = new otherVm();
console.log(ko.unwrap(other.thingRunning));

How to assign a function to a object method in javascript?

I'd like to 'proxy' (not sure if that's the term at all) a function inside a function object for easy calling.
Given the following code
function Soldier() {
this.el = $("<div></div>").addClass('soldier');
this.pos = this.el.position; // $(".soldier").position(), or so I thought
}
In the console:
s = new Soldier();
$("#gamemap").append(s.el); // Add the soldier to the game field
s.pos === s.el.position // this returns true
s.el.position() // Returns Object {top: 0, left: 0}
s.pos() // Returns 'undefined'
What am I doing wrong in this scenario and is there an easy way to achieve my goal (s.pos() to return the result of s.el.position()) ?
I thought about s.pos = function() { return s.el.position(); } but looks a bit ugly and not apropriate. Also I'd like to add more similar functions and the library will become quite big to even load.
When you're calling s.pos(), its this context is lost.
You can simulate this behavior using call():
s.pos.call(s); // same as s.pos()
s.pos.call(s.el); // same as s.el.position()
This code is actually ok:
s.pos = function() { return s.el.position(); }
An alternative is using bind():
s.pos = s.el.position.bind(el);
You can use the prototype, that way the functions will not be created separately for every object:
Soldier.prototype.pos = function(){ return this.el.position(); }
I'd recommend to use the prototype:
Soldier.prototype.pos = function() { return this.el.position(); };
Not ugly at all, and quite performant actually.
If you want to directly assign it in the constructor, you'll need to notice that the this context of a s.pos() invocation would be wrong. You therefore would need to bind it:
…
this.pos = this.el.position.bind(this.el);
It's because the context of execution for position method has changed. If you bind the method to work inside the element context it will work.
JS Fiddle
function Soldier() {
this.el = $("<div></div>").addClass('soldier');
this.pos = this.el.position.bind(this.el);
}
var s = new Soldier();
$("#gamemap").append(s.el);
console.log(s.pos());

Restoring a nullified function back in JavaScript

I was simply practicing a little bit of JavaScript. My goal was to create a function that can call another function with the .invoke() until .revoke() is called, which then nullifies the function.
Later on, I've added .porcupine() which was, in theory, supposed to take the firstly invoked function (in this case, alert()) and then reapply it to the original "temp". The issue is, though, after being revoked temp becomes unknown, therefore it can not call anything anymore. Is there something very obvious to this that I'm missing out or will the solution have to be fairly messy?
var denullifier;
function revocable(unary) {
if (denullifier === null)
denullifier = unary;
return {
invoke: function(x) {
return unary(x);
},
revoke: function() {
var nullifier = unary;
unary = null;
return nullifier.apply(this, arguments);
},
porcupine: function() {
unary = denullifier;
return unary.apply(denullifier, arguments);
}
};
};
console.log('----------');
temp = revocable(alert);
temp.invoke(7); ///alerts 7
temp.revoke();
temp.porcupine(); //exception
temp.invoke(7); //doesn't get here
I don't quite understand what you're doing, but there are a few problems with your code.
if (denullifier === null)
denullifier = unary;
denullifier is not null here, it's undefined - so the condition isn't met.
return nullifier.apply(this, arguments);
You can't call alert this way, the first param must be null or window.
return unary.apply(denullifier, arguments);
The same.
This is your problem:
var denullifier;
function revocable(unary) {
if (denullifier === null)
denullifier = unary;
denullifier is undefined when declared without a value. However, you are checking for type-strict equality with null, which will be false, so denullifier is never set and porcupine is not able to restore the unary function.
I'd suggest:
Use == instead of === to get equality with undefined
Even better, use typeof denullifier != "function"
Or, (although I don't know your design) you should not make denullifier a global, static variable that will be shared amongst revocable instances, but instead make it instance-specific by putting the declaration inside the function body.

Categories

Resources