What sets the statements of ( for... in ) and ( for... of ) apart from each other?

Although I am familiar with the for... in loop (which iterates over keys), I recently came across the for... of loop for the first time, which apparently iterates over values.

I find myself confused by this for... of loop.

var arr = [3, 5, 7];
arr.foo = "hello";
    
for (var i in arr) {
  console.log(i); // logs "0", "1", "2", "foo"
}
    
for (var i of arr) {
  console.log(i); // logs "3", "5", "7"
  // it doesn't log "3", "5", "7", "hello"
}

My understanding is that for... of should iterate over property values. So why does it only log

"3", "5", "7"
instead of
"3", "5", "7", "hello"
?

Unlike the for... in loop, which goes through each key (

"0", "1", "2", "foo"
) including the foo key, the for... of loop specifically excludes the value of the foo property, "hello". But why is that?

While testing the code using the for... of loop, I expected it to log

"3", "5", "7", "hello"
, but it only displayed
"3", "5", "7"
. What could be the reason behind this behavior?

Example Link

Answer №1

for in iterates through the enumerable property names of an object.

for of (introduced in ES6) uses a specific iterator for objects to loop through the generated values.

In the provided example, the array iterator produces all values within the array, excluding non-index properties.

Answer №2

I stumbled upon a thorough explanation on Iterators and Generators (Even though it pertains to TypeScript, the concepts are applicable to JavaScript as well)

When using for..of and for..in statements for iteration, they operate on lists but return different results. While for..in gives keys of the object being iterated, for..of provides values of numeric properties from the object.

The following example illustrates this distinction:

let list = [4, 5, 6];

for (let i in list) {
   console.log(i); // "0", "1", "2",
}

for (let i of list) {
   console.log(i); // 4, 5, 6
}

Furthermore, for..in can be used with any object to inspect its properties, whereas for..of is designed for iterating through iterable objects. Certain built-in objects like Map and Set have a Symbol.iterator property that grants access to stored values.

let pets = new Set(["Cat", "Dog", "Hamster"]);
pets["species"] = "mammals";

for (let pet in pets) {
   console.log(pet); // "species"
}

for (let pet of pets) {
    console.log(pet); // "Cat", "Dog", "Hamster"
}

Answer №3

Differences between for..in and for..of:

Both for..in and for..of are looping mechanisms used to traverse through data structures. Their key distinction lies in the entities they iterate over:

  1. for..in iterates over all enumerable property keys of an object
  2. for..of iterates over the values of an iterable object. These iterable objects can include arrays, strings, and NodeLists.

Illustrative Example:

let arr = ['el1', 'el2', 'el3'];

arr.addedProp = 'arrProp';

// elKey represents property keys
for (let elKey in arr) {
  console.log(elKey);
}

// elValue depicts property values
for (let elValue of arr) {
  console.log(elValue)
}

In this instance, we can see that the for..in loop processes the keys within the object, which is an array object here. The keys comprise of 0, 1, 2 (linked to array elements), and addedProp. Below is a visualization of the arr array object in chrome devtools:

https://i.sstatic.net/In5A2.png

The for..in loop essentially cycles through these keys without any complication.


Conversely, the for..of loop in our example navigates through the values of a data structure. In this specific scenario, the values consist of 'el1', 'el2', 'el3'. The values yielded by an iterable data structure using for..of vary based on the type of iterable object. For instance, an array outputs all its elemental values while a string produces individual characters from the string.

Answer №4

Using For...in Loop

The for...in loop offers a solution to the limitations of traditional for loops by eliminating the need for counting logic and exit conditions.

For example:

const numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

for (const idx in numbers) {
  console.log(numbers[idx]);
}

However, one drawback is that you still rely on indices to access array values, which can be confusing and cumbersome.

Another downside is that using for...in loops can lead to unexpected results when additional properties are added to an array's prototype, as these properties will also be included in the loop iteration.

Array.prototype.convertToDecimal = function() {
  for (let i = 0; i < this.length; i++) {
    this[i] = this[i].toFixed(2);
  }
};

const numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

for (const idx in numbers) {
  console.log(numbers[idx]);
}

This particular scenario highlights why for...in loops are discouraged for iterating over arrays.

Exploring For...of Loop

The for...of loop presents a versatile solution for iterating over any iterable data type.

For instance:

const numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

for (const num of numbers) {
  console.log(num);
}

This concise loop structure ensures straightforward iteration through the values without the complications of index management.

In addition, the for...of loop allows for easier control over loop execution with the ability to stop or break the loop conveniently.

const numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

for (const num of numbers) {
  if (num % 2 === 0) {
    continue;
  }
  console.log(num);
}

Moreover, concerns related to extra properties being inadvertently included in the iteration process are eliminated, as the for...of loop solely focuses on traversing the values within the object.

Answer №5

Don't forget this handy mnemonic to distinguish between the for...in Loop and for...of Loop.

"index in, object of"

for...in Loop => goes through the index in the array.

for...of Loop => travels through the object of objects.

Answer №6

Using for of is a method to loop through iterables and for in is utilized for cycling through object properties

A helpful tip to keep in mind:

When using for of, remember it's not for Objects (it's specifically for iterables)

When using for in, remember it's not for Iterables (it's designed for objects)

One more hint:

For in gives back keys from the object indices, while for of provides values

Answer №7

//When using 'for in', it loops through keys in an object and indexes in an array

 let obj={a:1, b:2}
    
    for( const key in obj)
      console.log(obj[key]); //This will output 1 and 2
      console.log(key);      //This will output a and b

 let arr = [10, 11, 12, 13];

  for (const item in arr) 
    console.log(item);   //This will output 0 1 2 3

//When using 'for of', it iterates over values in an array or any iterable object

let arr = [10, 11, 12, 13];

for (const item of arr )
  console.log(item);  //This will output 10  11  12  13

Answer №8

Simply put: for...in loops through the keys, while for...of loops through the values.

for (let item in ['apple', 'banana', 'cherry', 'date'] {
    console.log(item); 
}

// Result
0
1
2
3


for (let fruit of ['apple', 'banana', 'cherry', 'date'] {
    console.log(fruit); 
}

// Result
apple
banana
cherry
date

Answer №9

One more distinction between the pair of loops that hasn't been brought up previously:

It's worth noting that deconstructing with for...in is no longer recommended. It's better to use for...of instead.

Source

If we intend to apply destructuring within a loop to extract both the index and value of each array element, utilizing the for...of loop along with the Array method entries() is the way to go:

for (const [idx, el] of arr.entries()) {
    console.log( idx + ': ' + el );
}

Answer №10

Always keep in mind that when it comes to looping, for in is suitable for objects, while for of works well with arrays, strings, and similar data structures.

Moreover, you can simplify your code by using for of instead of for in. For example:

const person = {name: 'John', age: 31};

for (let key in person) {
   console.log(key, ': ', person[key]);  // name: John
}                                        // age: 31

for (let [key, value] of Object.entries(person)) {
   console.log(key, ': ', value); // The same output
}

Answer №11

In programming, the for...in statement is used to iterate over the enumerable properties of an object in a non-specific order. These enumerable properties are those with an internal [[Enumerable]] flag set to true, including any enumerable properties found in the prototype chain.

On the other hand, the for...of statement is used to iterate over data defined by an iterable object.

To illustrate:

Object.prototype.objCustom = function() {}; 
Array.prototype.arrCustom = function() {};

let iterable = [3, 5, 7];

for (let i in iterable) {
  console.log(i); // outputs: 0, 1, 2, "arrCustom", "objCustom"
}

for (let i in iterable) {
  if (iterable.hasOwnProperty(i)) {
    console.log(i); // outputs: 0, 1, 2,
  }
}

for (let i of iterable) {
  console.log(i); // outputs: 3, 5, 7
}

Just like before, there's no need to include hasOwnProperty within for...of loops.

Answer №12

The for-in statement loops through an object's enumerable properties in a non-specific order.

It will iterate over all the enumerable properties of the object itself and those inherited from its constructor's prototype

In simpler terms, "for in" iterates over and displays all the keys.

var str = 'abc';
var arrForOf = [];
var arrForIn = [];

for(value of str){
  arrForOf.push(value);
}

for(value in str){
  arrForIn.push(value);
}

console.log(arrForOf); 
// ["a", "b", "c"]
console.log(arrForIn); 
// ["0", "1", "2", "formatUnicorn", "truncate", "splitOnLast", "contains"]

Answer №13

Various data types have been predefined to make iteration easier, including Array, Map, and String Objects.

The traditional for in loop iterates over the keys of an iterator in the order of insertion, as demonstrated below:

  const numbers = [1,2,3,4,5];
   for(let number in numbers) {
     console.log(number);
   }

   // result: 0, 1, 2, 3, 4

In contrast, the for of loop provides values instead of keys when iterating over an object, as shown here:

  const numbers = [1,2,3,4,5];
   for(let number of numbers) {
    console.log(number);
  }

  // result: 1, 2, 3, 4, 5

By comparing both iterators, it is easy to see their distinctions.

Note:- For of only works with the Symbol.iterator

If an attempt is made to iterate over a regular object, an error occurs as illustrated below:

const Room = {
   area: 1000,
   height: 7,
   floor: 2
 }

for(let prop in Room) {
 console.log(prop);
 } 

// Result area, height, floor

for(let prop of Room) {
  console.log(prop);
 } 

Room is not iterable

To enable iteration over such objects, an ES6 Symbol.iterator must be defined, as shown below:

  const Room= {
    area: 1000, height: 7, floor: 2,
   [Symbol.iterator]: function* (){
    yield this.area;
    yield this.height;
    yield this.floors;
  }
}


for(let prop of Room) {
  console.log(prop);
 } 

//Result 1000, 7, 2

This explains the distinction between For in and For of. Hopefully, this clarifies the difference.

Answer №14

The concept of the for-in loop

In programming, the for-in loop serves as a mechanism to iterate through the enumerable properties of a collection in an unspecified order. A collection refers to a type of container object where items can be accessed using either an index or a key.

var myObject = {a: 1, b: 2, c: 3};
var myArray = [1, 2, 3];
var myString = "123";

console.log( myObject[ 'a' ], myArray[ 1 ], myString[ 2 ] );

The for-in loop essentially retrieves all enumerable properties (keys) of a collection at once and then proceeds to iterate over them individually. An enumerable property is one that can be included in a for-in loop iteration.

While by default all properties of an Array and Object are included in the for-in loop, it is possible to use the Object.defineProperty method to manually set the configuration of properties within a collection.

var myObject = {a: 1, b: 2, c: 3};
var myArray = [1, 2, 3];

Object.defineProperty( myObject, 'd', { value: 4, enumerable: false } );
Object.defineProperty( myArray, 3, { value: 4, enumerable: false } );

for( var i in myObject ){ console.log( 'myObject:i =>', i ); }
for( var i in myArray ){ console.log( 'myArray:i  =>', i ); }

For instance, in the example above, the property d of myObject and the index 3 of myArray will not be included in the for-in loop due to their specific configuration with enumerable: false.

Understanding the for-of loop

There exists a common misconception regarding the functionality of the for-of loop—it does not merely iterate over the values of a collection. Rather, the for-of loop operates on an Iterable object. An iterable object contains a method known as Symbol.iterator situated directly either on itself or within one of its prototypes.

The Symbol.iterator method should provide an Iterator, another form of object featuring a next method. Whenever this next method is invoked during the iteration process via a for-of loop, it returns both a value and a done property.

Through utilizing the for-of loop on an iterable object, the Symbol.iterator method will be called initially to acquire an iterator object. Subsequently, each iteration executed by the for-of loop entails calling the next method of this iterator object until the result returned by the done property triggers the termination of the loop. The value received by the for-of loop for every iteration corresponds to the value outputted by the next() call.

var myObject = { a: 1, b: 2, c: 3, d: 4 };

// Implementing `Symbol.iterator` function directly onto `myObject` to make it iterable
myObject[ Symbol.iterator ] = function(){
  console.log( `LOG: called 'Symbol.iterator' method` );
  var _myObject = this; // Refers to `myObject`
  
  // Generating an iterator object
  return {
    keys: Object.keys( _myObject ), 
    current: 0,
    next: function() {
      console.log( `LOG: called 'next' method: index ${ this.current }` );
      
      if( this.current === this.keys.length ){
        return { done: true, value: null }; // Not making use of `value` in `for-of` loop
      } else {
        return { done: false, value: _myObject[ this.keys[ this.current++ ] ] };
      }
    }
  };
}

// Employing `for-of` loop on `myObject`
for( let value of myObject ) {
  console.log( 'myObject: value => ', value );
}

The introduction of the for-of loop alongside the concepts of Iterable and Iterables occurred with the arrival of ES6. Specifically, the Array constructor type features a Symbol.iterator method within its prototype chain. Conversely, the absence of such a method in the Object constructor prompts tools like Object.keys(), Object.values(), and Object.entries() to supply iterable outputs (you may assess the prototype methods using console.dir(obj)). One major advantage associated with the for-of loop pertains to the fact that any object can now be rendered iterable—be it custom classes like Dog and Animal.

In regards to making an object iterable, implementing an ES6 Generator proves more expedient than crafting a bespoke iterator implementation.

A significant divergence from the behavior of the for-in loop lies in the capability of the for-of loop to accommodate asynchronous tasks throughout each iteration. This functionality materializes through the utilization of the await keyword following the for statement; additional information can be found within the corresponding documentation.

An added benefit inherent to the for-of loop revolves around its Unicode support. Per ES6 specifications, strings conform to UTF-16 encoding standards wherein individual characters require either 16-bit or 32-bit allocations. Earlier formats like UCS-2 encoding limited character representations to a 16-bit threshold only. Consequently, while String.length measures string lengths in terms of 16-bit units, modern characters like emojis necessitate 32 bits—a factor complicating tracking via the for-in loop due to its focus on 16-bit segments. In contrast, the for-of loop navigates through characters based on UTF-16 guidelines.

var emoji = "😊🤣";

console.log( 'emoji.length', emoji.length );

for( var index in emoji ){ console.log( 'for-in: emoji.character', emoji[index] ); }
for( var character of emoji ){ console.log( 'for-of: emoji.character', character ); }

Answer №15

To put it simply, the forIN loop goes through the KEYS within the array(index) or object(key),
while the forOF loop goes through the VALUES OF the array(value).

Answer №16

The for...of loop is specifically designed to work with iterable objects. In JavaScript, iterables refer to objects that can be iterated over.

String, Array, TypedArray, Map, and Set are examples of built-in iterables because each of their prototype objects includes an @@iterator method. Therefore, the for...of loop can be used with these object types.

By default, objects in JavaScript are not iterable, so the for...of loop cannot be applied to them.

In essence, the for...of loop is compatible with strings and arrays but not with objects.

On the other hand, for...in loop works specifically with properties that have their enumerable flag set to true.

Properties created through simple assignment or property initializer automatically have their enumerable flag set to true. Meanwhile, properties created using Object.defineProperty have their enumerable flag set to false by default.

To learn more about the differences between for...of and for...in loops in JavaScript, check out this informative post: https://dev.to/swastikyadav/difference-between-forof-and-forin-loop-in-javascript-j2o

Answer №17

After reviewing numerous well-crafted responses, I have decided to contribute my perspective for the sake of providing a good example:

Exploring the For in Loop

This loop iterates through all enumerable properties

let nodes = document.documentElement.childNodes;

for (var key in nodes) {
  console.log( key );
}

Unveiling the For of Loop

This loop navigates through all iterable values

let nodes = document.documentElement.childNodes;

for (var node of nodes) {
  console.log( node.toString() );
}

Answer №18

As I delved into learning the concepts of the for in and of loop, initially, I found myself perplexed by the output. However, after conducting some research and gaining a deeper understanding, I began to visualize the individual loops differently:

  1. The for...in loop returns the indexes of the object's properties without affecting or altering their values. It focuses on looping through and providing information about the properties rather than their values. E.g

let profile = {
    name : "Naphtali",
    age : 24,
    favCar : "Mustang",
    favDrink : "Baileys"
    }

The above code simply defines an object named profile. This object will be utilized for both examples in this context, so when you encounter references to the profile object in examples, understand that it was previously created.

Let's now explore the for...in loop below

for(let myIndex in profile){
    console.log(`The index of my object property is ${myIndex}`)
}
 // Outputs : 
        The index of my object property is 0
        The index of my object property is 1
        The index of my object property is 2
        The index of my object property is 3

The reason behind this output is that we have Four(4) properties in our profile object. Indexing in JavaScript starts from 0...n, hence, we obtain indexes 0,1,2,3 due to the usage of the for..in loop.

  1. The for...of loop* can retrieve either the property, value, or both. Let's delve deeper into its functionality. In JavaScript, looping through objects differs from arrays. Various methods are available to access specific elements within an object.

    • Object.keys(object-name-goes-here) >>> Returns the keys or properties of an object.

    • Object.values(object-name-goes-here) >>> Retrieves the values of an object.

    • Object.entries(object-name-goes-here) >>> Provides both the keys and values of an object.

Below are examples illustrating their practical applications, with focus on Object.entries() :

Step One: Extract the desired content (key, value, or both) from the object.
Step Two: Iterate through the extracted data.

// Accessing the keys/properties

   Step One: let myKeys = ***Object.keys(profile)***
   Step Two: for(let keys of myKeys){
             console.log(`The key of my object property is ${keys}`)
           }

// Accessing the property values

    Step One: let myValues = ***Object.values(profile)***
    Step Two : for(let values of myValues){
                 console.log(`The value of my object property is ${values}`)
               }

When utilizing Object.entries(), you essentially fetch two entries from the object - both the keys and values simultaneously. This productive approach allows you to access either or both components effortlessly. Refer to the example below.

Step One: Retrieve the object's entries using ***Object.entries(object-name)***
Step Two: Deconstruct the entries object to extract the keys and values effectively using **[keys, values]**.

    // Accessing the keys/properties

       Step One: let myKeysEntry = ***Object.entries(profile)***
       Step Two: for(let [keys, values] of myKeysEntry){
                 console.log(`The key of my object property is ${keys}`)
               }

    // Retrieving the property values

        Step One: let myValuesEntry = ***Object.entries(profile)***
        Step Two : for(let [keys, values] of myValuesEntry){
                     console.log(`The value of my object property is ${values}`)
                   }

    // Obtaining both keys and values

        Step One: let myBothEntry = ***Object.entries(profile)***
        Step Two : for(let [keys, values] of myBothEntry){
                     console.log(`The keys of my object are ${keys} along with their corresponding value which is ${values}`)
                   }

Kindly provide feedback on any unclear sections within this narrative.

Answer №19

Although the problem has been explained by everyone, it is still easy to overlook and end up puzzled as to why you are getting incorrect results. This tends to happen especially when dealing with large sets of data where everything may appear to be correct at first glance.

By utilizing Object.entries, you can ensure that you are accessing all properties:

var arr = [3, 5, 7];
arr.foo = "hello";

for ( var [key, val] of Object.entries( arr ) ) {
   console.log( val );
}

/* Result:

3
5
7
hello

*/

Answer №20

These unique data constructors serve a variety of purposes, from obfuscation techniques to creating hidden content. Fascinating!

var arr = [3, 5, 7];
arr.foo = "hello";

console.log(typeof arr) // object
console.log(Object.keys(arr)) // ["0", "1", "2", "foo"]
console.log(Object.values(arr)) // ["3", "5", "7", "hello"]
// console.log(Object.entries(arr))
for (var index in arr) { 
  console.log(index); // logs "0", "1", "2", "foo"
}
for (var value of arr) {
  console.log(value); // logs "3", "5", "7"
}
for (var objValue of Object.values(arr)) {
  console.log(objValue); // logs "3", "5", "7", "hello"
}

Answer №21

The explanation boils down to the fact that async can be utilized within a for..of loop, but not in a for..in loop.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Eliminating unwanted hash symbols in URLs while utilizing the $routeProvider feature in AngularJS

Upon starting my application, it automatically opens the following URL: http://localhost:8080/#/. I am attempting to have it open this URL instead: http://localhost:8080/ when the application loads, but I haven't been successful in doing so. I am usi ...

Unsubscribing from a socket io connection in Angular can be done

This is how I establish a connection between the client and server using socket io. export class OverviewService { socket:any; readonly uri:string='http://localhost:4000'; constructor(private http: HttpClient) { this.socket = io(t ...

Looking for help understanding a basic piece of code

$('#ID').on('click', function() { if(!CommonUtil.compareDateById('startDt','endDt',false, false, true)) { return false; } var cnt = 0; if(!CommonUtil.isNullOrEmptyById('startD ...

How to add vertical bars within ng-repeat in AngularJS

I attempted to retrieve values from an array variable using ng-repeat within unordered lists. Although the values are displaying correctly and everything is functioning properly, I added vertical bars after each value to represent sub-categories on my page ...

The react form fails to properly store user input within a formik fieldarray

I have encountered an issue with sending data from text boxes within a field array using Formik. The buttons for adding and deleting fields are working correctly, and data can be entered into the text boxes. However, when the form is submitted, the data en ...

What is the best way to convert a Nextjs page into a PDF file?

I am currently working on a page structure that looks like this: export default function FichaTecnica(props) { const data = props.data; return ( <> <Container> <TopData info={data} /> <DataSheet datasheet= ...

Mastering the Art of Utilizing Templates

As a newbie to nodejs/ejs, I am exploring the world of coding and stumbled upon Argon Dashboard by creativetim. With database setup, files unpacked, and redis configured, I followed the documentation to create an index.html for the dashboard. <!DOCTYPE ...

Change the class of the div when the first div is selected

My goal is to switch the class of the #klapp element (from .klapp to .klappe) whenever a click event happens inside the #label-it container, including when the #klapp element itself is clicked. The challenge is that I am not able to use unique IDs for each ...

Option list malfunctioning in Safari, Mozilla, as well as Chrome browsers

I encountered some issues while working on the front-end of my web app. Here are a few problems: I need to truncate text if it's too long, so I use the following CSS: .suggestion-box-text { white-space: nowrap; overflow: hidden; text-overfl ...

`What are the best techniques for utilizing Selenium with a desktop application?`

I am currently involved in testing a retail software, specifically focusing on automating the desktop application using Selenium. I am also required to test a portal where details are regularly updated. This means I will be conducting tests on both the d ...

Error: Unhandled promise rejection: [object Boolean]

I am encountering an issue while trying to secure a route in my Angular application. Despite what I believe to be the correct implementation, I am facing an error message when the negative scenario is triggered: ERROR Error: Uncaught (in promise): [object ...

Unable to precisely reach the very bottom of the scrollbar

When trying to move to the bottom of the scrollbar, I seem to reach a bit higher than the actual bottom. https://i.stack.imgur.com/Vt83t.png Here is my code: ws.onmessage = function (event) { var log = document.getElementById('log') ...

Conceal the inactive cursor on a webpage in Google Chrome

Imagine a unique HTML5 video player with a control bar that automatically hides when idle in fullscreen mode. But what if you also want the cursor to disappear? You might try adding .cursor = 'none' to the body's style, but be warned - Chrom ...

Issue with comparing equality to zero

function compare() { var value1 = parseInt(document.getElementById("box3").value); var value2 = parseInt(document.getElementById("box4").value); var display = document.getElementById("box5"); if (value1 === 0 || value2 === 0) { display.value = ...

Seeking assistance with the manipulation of divs based on the width of the screen for hiding

Recently, I encountered an issue with changing a 3x3 image gallery layout to an image slider when the screen size was less than 768px (mobile). Thanks to the help of everyone and particularly Danilo, who provided solutions in the comments, I was able to id ...

Exploring the World of Angular JS Services

Following the recommended practices, I am working on encapsulating my global functions into reusable factory services. In the provided code snippet, my objective is to execute a function that takes the string value of "Qprogress" from my JSON data, perform ...

Convert list of information into an array using PHP

Hi there! I have a link that holds a massive amount of data. You can find it here: This data consists of approximately 50,000 sets of information separated by commas. Is there a way for me to convert these 50,000 entries into an array? Below is an exampl ...

working with JSON arrays in JavaScript when field names are not known

After browsing through various threads on StackOverflow discussing parsing json arrays, I am struggling to extract specific data. Here is a snippet of my code... $('#keyword_form').submit(function(e){ var gj = $.post('employee ...

Stretching the limits: Combining and expanding your Styled Components theme

I am facing a situation where I have a component library built using Styled Components that has its own theme settings which are not meant to be overridden. Now, I need to incorporate this component library into another project that also uses Style Compone ...

The sinuous waveform in JavaScript

track : function(x, y, top, ampl) { return { top : top + 2, x : x + ampl * Math.sin(top / 20), y : (top / this.screenHeight < 0.65) ? y + 2 : 1 + y + ampl * Math.cos(top / 25) }; } This specif ...