Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Doom Mathematic
Sep 2, 2008

Bob Morales posted:

What's a good way to test if a string contains any of a list of strings?

if (foobar.indexOf('CNN') >= 0) {
doSomething
} else if (foobar.indexOf('MSNBC') >= 0) {
doSomething
} else if(foobar.indexOf('ABCNEWS') >= 0 {
doSomething
} else if(foobar.indexOf('FOXNEWS') >= 0 {
doSomeOtherThing
}

Does something like ifStringContains(foobar, 'CNN', 'MSNBC', 'FOXNEWS') exist or should I write my own?

JavaScript code:
if (['CNN', 'MSNBC', 'ABCNEWS'].some(x => foobar.indexOf(x) !== -1)) {
  doSomething()
}

Adbot
ADBOT LOVES YOU

Doom Mathematic
Sep 2, 2008
Assuming that you are working with a JavaScript number - i.e. a 64-bit float - bitwise operators (potentially lossily) convert/cast/truncate all of their operands to signed 32-bit integers prior to operation, and (losslessly now) convert the result back to a JavaScript number to return.

E: Do not perform bitwise operations on non-numbers and then complain about the results.

Doom Mathematic
Sep 2, 2008

Lumpy posted:

If you're going to mutate, why not go nuts!:

JavaScript code:
Ip(a, b) {

  // your stuff....
  a = a.split('.');
  b = b.split('.');
  if (a.length > b.length) {
     return 1;
  } else if (a.length < b.length) {
    return -1;
  }

  // terrible new stuff!
  while( a.length > 0 ) {
    let _a = parseInt( a.pop() ) ;
    let _b = parseInt( b.pop() );
    if( _a > _b ) return 1;
    if( _b > _a ) return -1;
  }
  return 0;
}

:eng101: Always use an explicit radix with parseInt!

Doom Mathematic
Sep 2, 2008

Knifegrab posted:

Sure, its just a really really simple bit of code to help sort IP addresses.

code:
    Ip(a, b) {
        a = a.split('.');
        b = b.split('.');

        if (a.length > b.length) {
            return 1;
        } else if (a.length < b.length) {
            return -1;
        }

        for (let i = 0; i < a.length; i++) {
            if ((a[i] = parseInt(a[i], 10)) > (b[i] = parseInt(b[i], 10))) {
                return 1;
            } else if (a[i] < b[i]) {
                return -1;
            }
        }
        return 0;
    }


From your code I take it these are IPv4 addresses, which means there's no need to check lengths and the loop can be painlessly unrolled:

JavaScript code:
lp(a, b) {
	const xs = a.split('.').map(x => parseInt(x, 10))
	const ys = b.split('.').map(y => parseInt(y, 10))

	return xs[0] - ys[0] || xs[1] - ys[1] || xs[2] - ys[2] || xs[3] - ys[3]
}

Doom Mathematic
Sep 2, 2008
With JavaScript sorting the comparator needs to return -1, 0 or 1 depending on whether a should come before b, they are the same, or b should come before a respectively. However, your comparator returns false, false and true respectively in these three cases, which coerce to 0, 0 and 1. This causes the sorting algorithm to proceed incorrectly and return unsorted data.

Although, testing manually, it looks as if the algorithm coincidentally returns the right answer for smaller inputs!

Try: .sort((a, b) => a.name.localeCompare(b.name)).

Doom Mathematic
Sep 2, 2008

huhu posted:

So, this works. Thank you so much. Could you clarify though, I don't quite follow how sorting is done incorrectly.

Array.prototype.sort assumes that the function you supply is indeed a comparator function which consistently behaves in the -1/0/1 way which we just discussed. It's not possible for the JavaScript engine to detect/verify that it actually behaves in this way, so unfortunately for us no error gets thrown if, as in your case, it doesn't. What happens instead is that the "comparator" function gets plugged into the sorting algorithm as normal, and the array gets permuted in a fairly unpredictable way.

Doom Mathematic
Sep 2, 2008

duz posted:

One catch I noticed is that jQuery is more graceful about passing in the wrong data type where as that will cause an error in normal JavaScript.

I can't even count the number of times I've been bitten by $('.this-element-sure-as-heck-does-not-exist').click() just silently succeeding when it really, really would have been more helpful if it failed noisily.

I mean, why would anybody want that? To click on nothing? In what universe is that the desired behaviour?

Doom Mathematic
Sep 2, 2008

Roadie posted:

The point in this case is that I want to find some way to use component A in component B without having to manually register component A on the app module.

If component B is in the app's root module, and component B needs to use component A, then component A needs to either be in the root module too, or be in one of the root module's dependency modules.

You've said you don't want to put component A in the root module, that's fine. But you've also said you don't want to declare some new dependency module for component A to be in, because this would break things. So I'm not aware of any way to do what you're asking for. I'm not really sure if I understand what you're asking for.

Doom Mathematic
Sep 2, 2008

fantastic in plastic posted:

Good naming is important, that's why I name all of my functions after pokemon.

Now show me on this whiteboard how you would reverse a Sudowoodo.

Doom Mathematic
Sep 2, 2008

Knifegrab posted:

I've got a dumb question that I really cannot figure out.

There is a package that we are relying on NPM/github. However we have to make proprietary changes to the repo. So naturally I have forked the repo. And no these are not changes that can then be resubmitted to the package as an open source contribution.

However for obvious reasons the new fork cannot then be hosted through npm. So I am pretty dumb when it comes to dependencies and what not. In a sense our project is still a little blackbox in its setup to me (I was not original developer) but we use yarn and npm to build our packages/dependencies.

So basically my question is, how the heck do I use this fork in my project? How do I rely on it similar to how I use node_modules and what not. It is a private forked repo, and it cannot be hosted on npm so I feel stupid but how do I reference this new forked package?

If the package you've forked is relatively stable and you aren't wanting to constantly pull updates from that package into your fork, you might consider just calling your package a different name.

E: And host it internally, if that wasn't clear.

Doom Mathematic
Sep 2, 2008

Dominoes posted:

It's taking my module imports, but not npm ones.

In general, an explicit relative import should only be used to load other source files from elsewhere in your own module. If you're pulling in a dependency, you don't know for sure where that dependency will be installed, so try:

JavaScript code:
import React from 'react'
Also note how we're getting the default (unnamed) import and naming it React, not grabbing a single object containing all the named imports * as React. These are not the same thing.

Doom Mathematic
Sep 2, 2008

FSMC posted:

I'm trying to create a function that traverses all the child nodes but the for loop seems to return early. I'm just getting into js and not sure if I've just made a simple mistake here or if js works differently than I think it should.
code:
/* I think for some reason js has issues with recursive functions and for loops. it just exits the loops after one recursion. 
 */
function recursiveNode(node) {

    children = node.childNodes;

    for (var i = 0; i < children.length; i++) {
        console.log("loop : " + i);
        child = children[i];
        console.log("index: " + i + "/" + children.length + "element: " + child.textContent + " val : " + child.innerHTML);
        recursiveNode(child);
    }
}

Separately from what necrotic said, you should be using some kind of linter. Any linter would instantly have caught this issue. JavaScript has gotchas, and it's highly inadvisable not to use the industry standard tools for avoiding those gotchas.

Doom Mathematic
Sep 2, 2008

FSMC posted:

Here is pseudo code of what I expect a more streamlined syntax to look like.
code:
function recursiveNode(node) {
    var children = node.childNodes;
    for child in children {
        recursiveNode(child);
    }
}
//OR
function recursiveNode(node) {
    var children = node.childNodes;
    children.forEach() {
        recursiveNode(child);
    }
}
The main issue is I don't understand why or where functions are declared. Why are functions are decalred where I would expect a variable to be.

In this case, forEach is no special piece of syntax. It is just a method on children (and on any array, in fact). We call this method passing a single argument, and that single argument is itself a function. In other words forEach is a "higher-order function". The way forEach behaves is that it calls the "inner function" once per element in the array.

Supporting this, JavaScript does, as you say, allow functions to be declared pretty much anywhere you would expect a simple JavaScript value or expression like 5 + 6. You can then bind that value to a variable e.g. var simple = function (child) { ... } and pass the variable to other functions children.forEach(simple), or just cut out the middleman: children.forEach(function (child) { ... }).

You can declare all your functions separately if you like, there are some pros and cons to doing this, but you should get used to people declaring them in-line as well.

Doom Mathematic
Sep 2, 2008

Suspicious Dish posted:

Why this isn't a default is beyond me.

In recent versions of npm it is.

Doom Mathematic
Sep 2, 2008

Obfuscation posted:

Am I expecting too much when I was hoping that VS Code would notify me about stupid small mistakes, like reassigning a const or using = instead of === inside an if? What's the best way to handle this:

-never do mistakes
-attach eslint to every single script separately
-install eslint globally and deal with that hassle?

Install eslint locally, set up a pre-testing step which runs the linter across all your scripts.

Dumb Lowtax posted:

Sometimes if you're code golfing, doing = instead of == in a conditional on purpose is a valid way to combine steps

Code golf is like the exact opposite of linting.

Doom Mathematic
Sep 2, 2008

geeves posted:

edit: Bigger gripe is with package-lock.json. I don't know what it is, but it loving sucks. All devs are on the same image, same version of Node and same version of NPM. Every build package-lock.json gets conflicting changes added / checked in.

Have you considered finding out what it is?

Doom Mathematic
Sep 2, 2008

geeves posted:

Even if everything was global, NPM does not version correctly at all. It means if I switch between branches and one branch has React 16.3 and the other has 16.4 that I'm testing, they constantly overwrite each other when I switch between them.

This is kind of to be expected in any situation where you've checked in your dependencies and different branches use different dependencies. You could consider ignoring node_modules.

Doom Mathematic
Sep 2, 2008

FSMC posted:

Thanks, that makes sense. The error was in the browser console. I added the following line which sorted it out.

code:
if (module == null) var module = {};

Unfortunately, adding this line is probably not the correct solution...

The system of loading which uses module to export things from one source file and require to import them into another file is called "CommonJS". This works fine in an environment like Node.js which actually supports/implements CommonJS. A web browser, though, doesn't. Trying to access module or require in this context should cause an error, as you've seen.

Normally, to get CommonJS source files to work in a browser, you need to bundle them somehow, using a tool like webpack (or, historically, Browserify). The output from this bundling step will be a new single JavaScript file which bundles all your code together with implementations of module and require which do the right thing.

Those implementations have some subtlety to them. Your solution of manually creating a module variable if it doesn't already exist (and then, and I'm just guessing this part, just loading each raw source file one by one?) might work right now, but it's likely to stop working as soon as you have a third source file. Just something to bear in mind... It's worth figuring webpack out. It's a valuable skill.

Doom Mathematic
Sep 2, 2008
I would be more inclined to explicitly use window.KHORNE_GLOBAL, a property on a variable window which you already know to be global.

Doom Mathematic
Sep 2, 2008
A couple of things. Most importantly, arrow functions are not passed this as an "invisible" named argument. Instead it is captured by reference from the surrounding scope.

JavaScript code:
const obj = {
  id: 78,
  method1: function() {
    return this.id
  },
  method2: () => {
    return this.id
  }
}

obj.method1() // returns 78, because `this` was `obj`
obj.method2() // throws an exception, because `this` was `undefined`

Doom Mathematic
Sep 2, 2008
I think you're suggesting something like:

JavaScript code:
const obj = {
  id: 78,
  method2: () => {
    return id
  }
}

obj.method2()
? This would throw an exception because the variable id doesn't exist.

Generally you would simply not use an arrow function as a method on an object. I only did it here to demonstrate the point. In most cases it's okay to replace a regular function with an arrow function. You only have to think twice if this is involved. Or a few other things, described here with good examples.

Doom Mathematic
Sep 2, 2008
Honestly I don't see a serious problem with just running all those promises serially. That's something you might be able to write yourself if you enjoy that kind of thing, or if not you can pull in a slightly more fully-feature promise library like Bluebird and use its built-in serial promise iteration method.

The key thing is what you do in the then block once the 29MB response comes back after the audit is done. Don't save the entire 29MB response. Just grab the relevant 5kB, append it to your small output JSON object, then discard the rest of the response object (i.e. let it drop out of scope, and Node.js will eventually free up the memory it was using). You'll be fine.

But be sure to correctly handle the case where one or more of the audits fails. You'll probably want a way to log that failure but press on with the rest of the batch?

Doom Mathematic
Sep 2, 2008
This happens because the || operator is testing the truthiness of obj, not the truthiness of obj.code.

For a more relaxing solution:

JavaScript code:
let code = obj.code || 'stuff'

Doom Mathematic
Sep 2, 2008

Osmosisch posted:

Anyone who claims to care about performance that much and then uses postfix in/decrement is just weird to me.

The widespread use of postfix operators where the cached value is irrelevant is just so irritating to me (and yeah I know it will usually get compiled into prefix but ugh. Write what you mean).

Are you saying prefix increment/decrement is faster than postfix increment/decrement in that context?

Doom Mathematic
Sep 2, 2008

Osmosisch posted:

Probably not in that context, as I tried to explain with the bit about the compiler. It's just that I'd expect someone who is being anal about performance to not risk it.

Is there any context where there's a difference in performance, though?

Doom Mathematic
Sep 2, 2008

Strong Sauce posted:

Why? On the chance you're parsing some number that begins with "0" then some other digits, and you need to support IE8? then sure... but then you're also not going to be able to use Number.isInteger.

There's that, there's also the famously surprising way that array.map(Number.parseInt) behaves.

Doom Mathematic
Sep 2, 2008
I don't know anything about Vue, but should this.debouncedSetFilters = _.debounce(this.setFilters, 3000); read this.debouncedSetFilters = _.debounce(this.setFilters.bind(this), 3000);? I've seen that kind of thing cause problems many times in the past.

Doom Mathematic
Sep 2, 2008

Kraus posted:

Oh god, this thread has gotten me more into code golfing in JS, and I found a site (https://code-golf.io/) that offered some challenges. I decided to tackle the Fibonacci challenge, where you have to get the Fibonacci sequence to display from 0 to 832,040, each on their own line.

I managed to come up with this 71-character solution:

code:
a=[-1,1];for(i=2;i<33;i++){document.write((a[i]=a[i-2]+a[i-1])+"<br>")}
But, the leaderboards on that site claim that it can be done in as little as 33 characters. Does anyone have any idea how?

You can save a lot of characters by using print(...) to output with a newline instead of document.write(... + '<br>'). This isn't standard JavaScript but it's in the instructions so it works for me.

Declaring and indexing that array is costly since we only need the two most recent entries (and I think a third variable to use as a temporary variable while we step forward...)

Also, cunningly the last entry requested is the last entry before Fibonacci numbers pass a million, which has a very small representation in JavaScript. So, here's what I have currently:

JavaScript code:
a=0;b=1;while(b<1e6){print(b);c=a+b;a=b;b=c}
(44 chars)

Doom Mathematic
Sep 2, 2008

Kraus posted:

Uh, all print did was repeatedly call a dialogue box for physically printing things.

I think you're running your code in your browser console. Try running on https://code-golf.io/fizz-buzz#javascript itself like you mentioned.

Doom Mathematic
Sep 2, 2008

Kraus posted:

Okay. Hmm. That seems a little janky if it doesn't always work, and is just environment-specific. Oh well.

Edit: What I'm saying is that if you wanted to run this code outside of that environment, you'd end up having to write 16 characters more, since "print()" does something else outside of that environment. That means the record is a stealth 49, unless y'all know another way to get stuff to appear on screen, formatted that way.

Yeah, JavaScript environments differ from one another. Not all of them are web browsers. The challenge as stated doesn't require the code to run outside of the environment it provides, which, by the way, isn't a web browser, document.write doesn't work there.

Doom Mathematic
Sep 2, 2008

smackfu posted:

I actually saw some similar code yesterday in a package we are using.
code:
 const improvedSpec = JSON.parse(JSON.stringify(inputSpec));
https://github.com/Surnet/swagger-jsdoc/blob/master/lib/helpers/getSpecificationObject.js

What the heck?

That's an extremely common way to clone a JavaScript object. It can be very lossy but it's also surprisingly fast. It also avoids pulling in a third-party deep cloning library whose behaviour with respect to e.g. circular objects is less well-understood than JSON.parse and JSON.stringify, which are universally known quantities.

Of course, in most cases it should not be necessary to completely clone an object in this way... for example, in this case const improvedSpec = { ...inputSpec } would do the same job much faster still...

Doom Mathematic
Sep 2, 2008

Nolgthorn posted:

What pitfalls

You code does quite surprising things when it clones anything which inherits from Object but is not a plain old Object, such as a function, date, regular expression object, boxed String or typed array. Essentially it ignores the prototype chain. It also doesn't preserve additional string properties of arrays, or symbol properties of objects. Object properties which are read-only, accessor (getter-setter), non-configurable or non-enumerable also do not have these attributes preserved.

Most of these issues can be fixed, but cloning functions is the really insurmountable issue here. Functions are essentially uncloneable because of the old "do this!" problem:

JavaScript code:
const a = {
  val: 6,
  setVal: val => {
    a.val = val
  }
}

const b = clone(a)

b.setVal(7)
Should b.setVal modify a.val, or b.val? If it modifies a.val, that's very surprising behaviour - at first glance, anyway. This question can become much more complicated in the general case. If it should modify b.val instead, how do we even construct b.setVal?

(This is kind of like touching your nose and saying to someone, "Do this!" Should they touch your nose, or touch their own nose?)

And having noted that cloning a function is something which is to be avoided, we then realise that essentially every JavaScript object has methods on it...

Anyway... it's true that JSON.parse(JSON.stringify(...)) also has problems with this kind of input (and it mishandles other, dumber things too, like undefined, Infinity, -Infinity and NaN). The point is that JSON.parse(JSON.stringify(...)) is a universally known quantity, including all of its warts, whereas for any given third-party cloning library it's anybody's guess which of these edge cases are handled well and which are not.

Doom Mathematic
Sep 2, 2008

Roadie posted:

In JS, execution happens in order within a context, but whenever context changes (such as when calling or returning from a function), the engine is allowed to jump around to handle background timers, event listeners, etc.

Anony Mouse posted:

Huh? I've never heard this explanation of execution order. Functions get called all the time, creating new execution contexts, and as far as I know that has nothing to do with execution order or "asynchronous" behavior. Isn't everything tied to the event loop?

Yah, that's because Roadie's initial statement isn't correct. I'm not sure what "context change" is meant to mean, but simply calling a function or returning from a function does not allow the engine to jump around to handle background timers, event listeners, etc.

At the simplest level, a JavaScript engine maintains a queue of messages, and each message essentially says "call this particular function with these parameters". In the event loop, the engine takes a message off the queue, calls the function and waits until the function has done everything it needs to do, posibly including calling many more functions, and returned. Only then, when the call stack has become empty again, does it take the next message. Nothing can interrupt this. More messages may show up on the queue while the engine is dealing with the first message, but they have to wait their turn.

Doom Mathematic
Sep 2, 2008
Yes, I'd avoid writing anything like constructor (args) { ... }, because it confuses matters by giving the first entry in the arguments array (well, array-like object) the name args.

Anyway:

JavaScript code:
const defaults = {
  a: 0,
  b: 1,
  c: 1,
  d: 40
}

class M {
  constructor(props = {})  {
    Object.assign(this, defaults, props)
  }
}

Doom Mathematic
Sep 2, 2008

Dumb Lowtax posted:

Does anyone know why the arguments object is empty there? Maybe es6 object destructuring syntax in parameters is like a new and weird part of the language, and they're phasing out the arguments keyword anyway so maybe they just didn't bother making the two things work together?

This isn't to do with object destructuring, it's more to do with the default parameter syntax. The arguments object you get automatically in any function is apparently derived from what the caller originally passes in, not from what your default parameter syntax creates.

JavaScript code:
const f = function (a, b, c = 7, d = 8) {
  console.log(a, b, c, d) // 1 2 7 8
  console.log(arguments) // [Arguments] { '0': 1, '1': 2 }
}

f(1, 2)
In the case new M() the caller is passing no parameters, so the arguments object is empty.

Doom Mathematic fucked around with this message at 16:05 on Feb 17, 2019

Doom Mathematic
Sep 2, 2008

Dumb Lowtax posted:

Right now the best option seems to be the following. It completely omits object destructuring in parameters, which is really odd since it seems like that syntax was pretty much made for this situation and yet can't do the most useful thing. It also sucks because it's harder for the reader to immediately see what the constructor wants.

code:
class M
{ constructor( options )               // Previously:  constructor( { a = 0, b = 1, c = 1, d = 40 } = {} )
  {  // Now the reader has to find the defaults in the function body instead:
    Object.assign( this, { a = 0, b = 1, c = 1, d = 40 } )
    Object.assign( this, options );
  }
}

For the use case you described, there is no need to destructure the incoming options object, either in parameters or otherwise.

I'm actually a bit puzzled as to why you prefer this solution over the one I suggested. Why two Object.assign calls? Why not keep the defaults as a distinct object? Another variant:

JavaScript code:
class M {
  constructor (options) {
    Object.assign(this, this.constructor.defaults, options)
  }
}

M.defaults = { a: 0, b: 1, c: 1, d: 40 }

Doom Mathematic
Sep 2, 2008
JavaScript code:
if (controlArray.every(function (val, i, controlArray) {
    return val === ""
}))
    return controlArray;

Doom Mathematic
Sep 2, 2008

Fruit Smoothies posted:

JavaScript code:
	async add(func) {
		await Promise.all(this.list);
		let promise = new Promise(async (done,fail) => {
			try {
				await func();
				done();
			} catch(e) {
				fail();
			}
		});
		this.list.push(promise);
	}
Usage is meant to be:

JavaScript code:
obj.add(async () => {
	await thing();
	await otherThing();
});
But they aren't executed in order and I have no idea why.

I suggest removing the async from new Promise(async (done,fail) => {. Honestly I don't have a clue what exactly it would do in that context but I'm reasonably sure it's not meant to be there.

Actually I think you might be able to get away with eliminating that whole wrapping Promise and just writing this.list.push(func());?

Doom Mathematic
Sep 2, 2008
So to be clear, you're doing something like

JavaScript code:
// numbers.js
export const b = 2
export const a = 1
JavaScript code:
// main.js
import * as numbers from './numbers'

console.log(Object.keys(numbers))
and the problem is you're getting ['a', 'b'] (alphabetical order) when you want it to be ['b', 'a'] (source order).

Are there other programming languages/module systems where the source order of the named exports is significant?

Adbot
ADBOT LOVES YOU

Doom Mathematic
Sep 2, 2008

LifeLynx posted:

code:
<script type="text/javascript">

var linktoList = document.getElementsByClassName('linkto'), i;
var ltl = document.getElementsByClassName('linkto').length;
console.log(ltl);

for (i = 0; i < ltl; i++) { 
  console.log(i.html);
}

</script>
Is "i" getting anything related to the current element? It's times like these I miss the $(this) function of jQuery. If anyone can point me in the right direction, I'd appreciate it, because I'm not even sure what to Google, and usually I can solve things through an hour or so of Googling.

You're doing i.html, which will return undefined because i is a number, which has no html property. I think you want something like linktoList[i], which is a DOM element you can do more work with.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply