How to select a property of an Object containing a class - javascript

Is it possible to select a property from an object containing a class like this below?
//Object
const voices = {
fmsynth: Tone.FMSynth,
amsynth: Tone.AMSynth,
synth: Tone.Synth
}
//my function to select the above synths
switch_synth(synth_id) {
const synth = new Tone.PolySynth(voices[synth_id], 6).toDestination();
console.log(voices[synth_id]);
}

Yes, as long as you call it with the appropriate key
In your code, call voices["fmsynth"] or even voices.fmsynth, to get Tone.FMSynth.
So your code seems to be doing the right thing, as long as you are calling switch_synth with an appropriate synth_id, e.g.
switch_synth("fmsynth")
Are you getting an error, and if so, what error?

Related

Dexie JS (Indexed DB): Using get( ) in addEventListener returning undefined

I've been working on chrome extention project.
What I am trying to do is store the input value and pull it out when the specific button is pressed.
Below is the part of js code:
import { Dexie } from '../node_modules/dexie/dist/dexie.mjs';
var DBName = 'test';
buttonA.addEventListener('click', () => {
const inp = document.getElementById("inp");
const db = new Dexie(DBName);
db.version(2).stores({
friend: '++id, name'
});
db.friend.add({
name: inp.value
})
});
buttonB.addEventListener('click', () => {
const db = new Dexie(DBName);
const ch = db.friend;
console.log("Checking the value in DB: " + ch);
});
When I try it, it stores whatever input to indexed DB after clicking buttonA (confirmed by using Chrome Developer Tool), however when it comes to clicking on buttonB, the log tells that ch is undefined (same for db.friend.name or db.name as well).
Because of this, even when I use get(), it returns me an error since I am accessing on undefined variable.
Could someone help figuring out why the program does not access properly to an indexed DB that exists when I click on a buttonB?
Thank you.
Problems:
The second instance of Dexie does not declare which tables there are, so db.friend is unknown.
Your code creates a new Dexie for every click. It would be much better and faster to reuse a single Dexie instance. If you create a new Dexie instance everytime, you must also close it after you to avoid resource leakage.
Recommendation:
Declare a singleton Dexie instance with version().stores(...) so it populates the 'friend' property for you.
Preferably this code could be in it's own module (such as 'db.js').
Use that single Dexie instance from any place where you need to store or read from the db.

Can I add custom methods to Google Apps Script classes?

I want to invoke custom methods on Google Apps Script classes such as Spreadsheet, Sheet, and DriveApp.
In https://stackoverflow.com/a/6117889, a minimal prototyping solution is used to add a method to the Javascript Date() class to get the week number. Is it possible to apply the same strategy to Google Apps Script classes?
As an example, I want to create a custom method for the Spreadsheet class that allows the spreadsheet to be moved to a particular folder in my google drive given the ID of that folder. Here is what I've tried:
Spreadsheet.prototype.moveToFolder = function(folderID) {
const file = DriveApp.getFileById(this.getId());
const destination = DriveApp.getFolderById(folderID);
file.moveTo(destination);
}
However, I get the error message "ReferenceError: Spreadsheet is not defined".
Is there another way to achieve what I want?
It is possible to add custom methods. But Spreadsheet class is not directly accessible. So, it is needed to first get a instance of Spreadsheet class using any of methods available:
const Spreadsheet = SpreadsheetApp.getActive();
Then use Object.getPrototypeOf() on the Spreadsheet instance to get it's prototype.
Object.getPrototypeOf(Spreadsheet).myMethod = function (){
console.info("myMethod was called!")
return true;
}
Any property defined on the prototype will then propogate through all Spreadsheet instances.
Update:
The prototype object returned by Object.getPrototypeOf(Spreadsheet) is Object. This can also be confirmed by logging Spreadsheet.constructor.name. This means that there is no special Spreadsheet prototype or constructor used to create the Spreadsheet instance. Therefore, Although you can add custom methods, They're added to all objects say, Range, DriveApp and any object created with var obj = {} or Object.create("Any object except null").
Given that Spreadsheet doesn't have a unique prototype but actually uses that of Object, as noted by TheMaster, you can simply add your method to the Object prototype.
Object.prototype.moveToFolder = function(folderID) {
const file = DriveApp.getFileById(this.getId());
const destination = DriveApp.getFolderById(folderID);
file.moveTo(destination);
}
Since this method will apply to all objects, you should ask yourself if it's really worth doing. See "Why is extending native objects a bad practice?"
Instead of modifying the native object, you could create a new class that "inherits" the native methods while also giving you the ability to override and add new methods.
function main() {
const ss = new Spreadsheet(SpreadsheetApp.getActive());
console.log(ss._native.getName()); // MySpreadsheet
console.log(ss.getName()); // The name is MySpreadsheet
ss.moveToFolder(FOLDER_ID);
}
class Spreadsheet {
constructor(native) {
this._native = native;
// Copy native's methods to this
Object.getOwnPropertyNames(this._native).forEach(property => {
this[property] = this._native[property];
});
// Override native methods
Object.defineProperties(this, {
'getName': {
value: function() {
return `The name is ${this._native.getName()}`;
}
}
});
}
moveToFolder(folderId) {
const file = DriveApp.getFileById(this.getId());
const destination = DriveApp.getFolderById(folderId);
file.moveTo(destination);
}
}

Frida Casting object to List of Strings

I have been trying to print out the contents of a list when hooking an android app with Frida but am not having any luck.
The object I want to hook in Java looks like this
import com.fasterxml.jackson.annotation.JsonIgnore;
import java.util.List;
public final class Hello extends HelloParent{
#JsonIgnore
public final List sampleList;
}
There aren't any getters for this public object so I have to resort to using another object (Let's call the object "Bye")'s method (byeMethodB) to monitor this value.
This is what my frida-script looks like:
setTimeout(function() {
Java.perform(function(){
Java.use("Bye").byeMethodA.implementation = function(){
try{
//Returns a Hello object
var helloObject = Java.cast(this.byeMethodB(),Java.use("Hello"))
printListContent(Java.cast(helloObject.sampleList,Java.use("java.util.List"))))
}catch(err){
console.log(err)
}
}
})
},1000)
function printListContent(list){
var listIter = list.iterator()
while(listIter.hasNext()){
console.log(listIter.next())
}
}
Without casting the "helloObject.sampleList" object to a list, the output looks like this:
[object Object]
So I am sure it is not null
If I cast using Java.cast(helloObject.sampleList,Java.use("java.util.List")),
I get the following error:
I have also tried:
Java.cast(helloObject.sampleList,Java.use("java.util.List<>"))
(I am pretty sure its a String)
Java.cast(helloObject.sampleList,Java.use("java.util.List<String>"))
Java.cast(helloObject.sampleList,Java.use("java.util.List<java.lang.String>"))
Java.cast(helloObject.sampleList,Java.use("[String"))
Java.cast(helloObject.sampleList,Java.use("[Ljava.lang.String"))
It is not going well at all. Would appreciate some help
In Frida accessing fields is not identical as in Java. If you execute helloObject.sampleList in Frida you are getting the JavaScript object that describes the field, not the field value itself.
If you want the field value you have to execute helloObject.sampleList.value.
Therefore the following code should work:
Java.cast(helloObject.sampleList.value, Java.use("java.util.List"));
Generics only exists at compile time but frida is working at run-time. Therefore java.util.List<> and the other class names with angle bracket will never work.

Is adding another method to a class no longer allowed in JavaScript?

So I was playing around in typescriptlang.org/play, writing a class of Plane with a method of pilot(): void {} and I pasted the JS code inside my Chrome console and played around with that for a minute.
Then I wanted to put into practice the concept of being able to add another method to class Plane {}. So this is what I had on the TypeScript side:
class Plane {
color: string = 'red’;
pilot(): void {
console.log(‘swoosh’);
}
takeoff(): void {
console.log(‘ready for takeoff’);
}
}
This is JS version:
class Plane {
constructor() {
this.color = 'red';
}
pilot() {
console.log(‘swoosh’);
}
takeoff() {
console.log(‘ready for takeoff’);
}
}
When I pasted that into Chrome console I got Uncaught SyntaxError: Identifier 'Plane' has already been declared.
Okay, so how do I add a new method then? I should be able to easily attach as many methods to prototype as I want. Is it because the term prototype does not exist in my JS code?
class functions like const or let in JS-land: it can't be re-declared. When I'm pasting code in the console that uses those terms, I generally refresh the page each time.
But happily, new releases of Chrome are letting you re-declare let and const within the console. I don't know if this will ever extend to class.
Note that you can, indeed, add a line like Plane.prototype.foo = function() {} after Plane has been declared, and this will work as you'd expect.
It seems like you are pasting the JavaScript code into a console that already has your Plane class defined.
If you already pasted the class definition once you cannot redeclare it by pasting an edited version again, you need to refresh your page or just open a console in an empty tab to get a fresh environment.
If though you want to experiment with adding a method to an existing class you can do so like this:
// You start by defining the original class (or picking one of the defined ones like Date)
class Plane {
// Your class definition
getName() { return 'I am a plane'; }
}
// Then somewhere later in your code (or console)
Plane.prototype.sayHello = function() {
return 'Hello ' + this.getName();
}
// And finally
const plane = new Plane();
plane.sayHello(); // Will return Hello I am a plane

Axios generic Post returns wrong type in TypeScript

I am trying to return a typed object using the Axios API. I am using the generic type to declare that I am returning an instance of GetSliceResponse but unfortunately Axios seems to still return an object of type any.
My code looks like this
export class GetSliceResponse
{
Success: boolean;
}
Axios.post<GetSliceResponse>("myurl/Get", request).then(o => {
var expectedResult = (new GetSliceResponse()) instanceof GetSliceResponse;
//expectedResult = true;
var unexpectedResult = o.data instanceof GetSliceResponse;
//unexpectedResult = false;
});
The Http response is exactly what you would expect:
{"Success":false}
As the above code illustrates I can correctly create an instance of my type using the new syntax but the Axios data property appears unaffected by the type declaration.
Just because something has the same properties as the class does not mean it is an instance of the class. In your case the response from the server is probably parsed using JSON.parse which will create simple objects. Only objects created using new GetSliceResponse will actually be instances of the class.
The type parameter to the post method is meant to help describe the shape of the response but will not actually change the runtime behavior (nor could it, genetics are erased during compilation).
This being said, you can still access the properties of the object as if the object was an instance of the class, the only thing that will not work is instanceof and don't expect any method to be present.
If you want to make sure nobody uses instanceof by mistake you can make the type am interface instead.
If you really need the class you can create an instance using new and use Object.assign to assign all fields
export class GetSliceResponse
{
Success: boolean;
}
Axios.post<GetSliceResponse>("myurl/Get", request).then(o => {
o = Object.assign(new GetSliceResponse(), o);
});

Categories

Resources