Why am I getting ".at" is not a function? - javascript

I know how to index an array with [] but I'm trying to display an item from an array based on its index using Array.at() method as described here MDN Docs - Array.at
But I get the following error:
Uncaught TypeError: arr1.at is not a function
I double-checked it, and everything is ok, however I don't know what's going wrong.
Here is my code:
const arr1 = [10, 20, 30, 40, 50];
const res = arr1.at(2);
console.log(res);
Note: This is different than the proposed duplicate of How to get value at a specific index of array In JavaScript?. That question is about methods for accessing an array, this question is why a new API for doing so is unavailable and how to rectify that.

If you get this message, whatever platform you're running the code on does not support the method yet. It's quite new - while the most recent versions of most browsers support it, anything before 2021 definitely won't. This method was only very recently signed off on (end of August 2021) and incorporated into the official specification, so it won't exist in older environments. Either upgrade your environment, or add a polyfill.
Per the proposal document, a "rough polyfill" that should be standards-compliant for most cases is:
function at(n) {
// ToInteger() abstract op
n = Math.trunc(n) || 0;
// Allow negative indexing from the end
if (n < 0) n += this.length;
// OOB access is guaranteed to return undefined
if (n < 0 || n >= this.length) return undefined;
// Otherwise, this is just normal property access
return this[n];
}
const TypedArray = Reflect.getPrototypeOf(Int8Array);
for (const C of [Array, String, TypedArray]) {
Object.defineProperty(C.prototype, "at",
{ value: at,
writable: true,
enumerable: false,
configurable: true });
}
Simply run that before trying to use .at, and you should be able to use it, even on older incompatible environments. You can also install this more exhaustive shim instead if you wish.

One option is to use the core-js library...
Modular standard library for JavaScript. Includes polyfills for
ECMAScript up to 2021: promises, symbols, collections, iterators,
typed arrays, many other features, ECMAScript proposals, some
cross-platform WHATWG / W3C features and proposals like URL. You can
load only required features or use it without global namespace
pollution.
First install it with npm or yarn:
npm install core-js
or
yarn add core-js
Then use it in your JS or TS project like this:
import 'core-js/features/array/at';
let arr = [];
arr.push(42);
console.log(arr.at(0));
Note that the code above only imports the at method for array. To import all polyfills or a subset:
// polyfill all `core-js` features, including early-stage proposals:
import "core-js";
// or:
import "core-js/features";
// polyfill all actual features - stable ES, web standards and stage 3 ES proposals:
import "core-js/actual";
// polyfill only stable features - ES and web standards:
import "core-js/stable";
// polyfill only stable ES features:
import "core-js/es";

If you're using node.js then please check the version of node.
It should be greater than 16.6.0. If not then update the node.js version.
Browser compatibility of Array.prototype.at()

The code is working fine in Stackoverflow code terminal. Your machine might not support the same due to JS versioning. The method is introduced recently.

I ran into this same issue when using Pipedream. I didn't realize that at() wasn't included in the NodeJS version they're using hinted at by Li Ki.
I implemented a similar solution proposed by Bjørnar Hvidsten; however, to get it to work in Pipedream, I simply added the following to the top of my NodeJS code.
import 'core-js'
const myArray = [1,2,3]
console.log(typeof myArray.at) // "function"
P.S. Referencing specific parts of core-js resulted in errors inside Pipedream, at least how I was trying to call it.

Related

Does the Laravel Mix Polyfill extension not include the String.includes method?

I'm using the Laravel Mix Polyfill extension (https://laravel-mix.com/extensions/polyfill) with a Laravel and Vue.js project.
When I import vue-select into a Vue file, I get the following error in IE11:
Object doesn't support property or method 'includes'
This seems weird to me, as I assumed that the Polyfill extension was explicitly designed to polyfill these types of things in IE11, etc.
If I add the following block above my import statement for vue-select (credit to: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/includes#Polyfill), then everything works fine, but I would ideally not like to do this and just rely on the Polyfill extension to manage all of this for me:
if (!String.prototype.includes) {
String.prototype.includes = function(search, start) {
'use strict';
if (search instanceof RegExp) {
throw TypeError('first argument must not be a RegExp');
}
if (start === undefined) {
start = 0;
}
return this.indexOf(search, start) !== -1;
};
}
The Polyfill extension is working properly for promises in IE11, so I'm assuming that it is installed and set up correctly in my project, but I'm wondering what's up with the String.includes method specifically.
Does anyone know? Thanks.
Edit #1: Here's what I have set for the polyfill method in the webpack.mix.js file:
.polyfill({
enabled: true,
useBuiltIns: 'usage'
});

IE11 Object doesn't support property or method 'Symbol(Symbol.iterator)_a.2p3bca3ct9h

I am using Angular 8, tslint 5.15 & typescript v3
I am reading file as ArryaBuffer using below code
const reader = new FileReader();
reader.readAsArrayBuffer(<FileObject>);
reader.onload = () => {
this.uploadedData= new Uint8Array(reader.result as ArrayBuffer);
}
Now when i pass this uploadedData into API, I am converting into byteArray using below fucntion.
convertLicenseToByteArray(uploadedData) {
const bytesArray = [];
for (const i of uploadedData) {
bytesArray.push(i);
}
return bytesArray;
}
The above code is giving error in ie11,
ERROR TypeError: Object doesn't support property or method
'Symbol(Symbol.iterator)_a.srxqdvyfxlx'
I tried to search on net and found that may be i need to add babel-polyfill but it's not working for me.
Any help?
add 'core-js' into you package.json and add import into your polyfills.ts
import 'core-js/es6/symbol';
IE11 doesn't support virtually any of ES2015+, so that means no arrow functions, no Symbol, and no iterables and iterators. (IE9-IE11 do support const and let, but not properly. They support an early version that isn't what was standardized. The biggest discrepancy is in regard to for loops.)
If you want to run that code on IE11, you'll need to transpile it to ES5 and add some polyfills. Symbol and iterability can't be properly polyfilled, but Babel and others provide something partially functional. I see here that Babel now recommends not using their own #babel/polyfill and instead using core-js directly (and regenerator runtime if you need to transpile generator functions).
The issue is relates to the uploadedData parameter, when we call the convertLicenseToByteArray method and use the uploadedData variable, if the data is not populated or undefined, it will display this error.
You could try to call the convertLicenseToByteArray method in the reader onload function.
const reader = new FileReader();
reader.onload = (_event) => {
this.uploadedData= new Uint8Array(reader.result as ArrayBuffer);
console.log(this.convertLicenseToByteArray(this.uploadedData).length);
}
For anyone that might be having this problem in an Aurelia project without typescript, I was able to solve it by installing core-js which included the polyfills needed to make this work.
npm install --save core-js#3.6.5
I then added the import in the .js file where I was having the issue and it started working.
import "core-js"

Missing module exports in IE11/Edge

I'm having trouble getting an npm module to work since it was changed to ES2015.
I have an ES2015 app that is bundled by browserify and transformed with babelify. I am trying to upgrade an npm module named credit-card for credit card validation, which was changed from ES5 to ES6 in the current version. The problem starts with IE11/Edge. The code works fine on Chrome. Here's how the module is imported in the transformed app (babel'd code):
var _this = this;
var _creditCard = require('credit-card');
var _creditCard2 = _interopRequireDefault(_creditCard);
Here's a piece of code calling it:
this.validateCreditCard = function () {
var ccNumber = _this.account_number_credit_card.value.replace(/\D/, '');
_this.creditCardValidation = {
accountHolder: _this.account_holder_credit_card.value.replace(/\W/g, '').length >= 2,
cvc: _this.account_cvc_credit_card.value.replace(/\D/g, '').length > 2,
accountNumber: _creditCard2.default.isValidCardNumber(ccNumber, _creditCard2.default.determineCardType(ccNumber, { allowPartial: true }))
};
return _underscore2.default.all(_underscore2.default.values(_this.creditCardValida tion));
};
Now on Chrome this works without a problem. On IE however, the exported functions of the credit card module are missing.
Here's a printscreen of a console log of the module in IE
And here's Chrome
It looks like defaults is completely missing in IE. Is this a known issue? Do any of you have encountered this problem before and can give me some hints? Any pointers on how I could investigate this issue to understand what is going wrong and how I could fix it?
Stepping through the require() in IE11 Debugger i found out that there was a problem with Object.assign being undefined in IE11. After some searching I found this thread. The answer in this thread worked out in the end. I needed to add polyfill to my browserify bundle and enable the "transform-es2015-classes" plugin with the opt loose: true (See this thread for code).

Object.assign is not a function

I'm using babel with gulp and create a simple DOM library in ES6. But after running and when i'm going to use it, I got the Object.assign is not a function in chrome console.
this is the gulp code
gulp.task('scripts', function() {
return gulp.src(src + 'js/*.js')
.pipe(babel())
.pipe(concat('main.js'))
.pipe(gulp.dest(dest + 'js'));
});
this is the class file
class DOM {
constructor( selector ) {
var elements = document.querySelectorAll(selector);
this.length = elements.length;
Object.assign(this, elements);
}
...
}
const dom = selector => new DOM(selector);
and I'm using it in client side like dom('#elId');
As I suspect you already know, Google Chrome uses V8, which supports ECMAScript 5th edition. Object.assign is introduced in ECMAScript 6th edition.
In order to use these additions, you need to include the ES6 polyfill provided by Babel:
This will emulate a full ES6 environment. [...]
Available from the browser-polyfill.js file within a babel-core npm release. This needs to be included before all your compiled Babel code. You can either prepend it to your compiled code or include it in a <script> before it.
Install babel-core:
$ npm install babel-core --save-dev
Import polyfill module into your js:
import 'babel-core/polyfill';
Use babel to compile your code!

Use window.crypto in nodejs code

I am trying to use the window.crypto.getRandomValues method in a nodejs script. From my understanding there is no window element when I run a simple code like this in node:
var array = new Uint32Array(10);
window.crypto.getRandomValues(array);
Which is why I get this error:
ReferenceError: window is not defined
How can I use this method in my code?
Thanks
You can use the built-in crypto module instead. It provides both a crypto.randomBytes() as well as a crypto.pseudoRandomBytes().
However it should be noted that these methods give you a Buffer object, you cannot pass in a Uint32Array or similar, so the API is a bit different.
const crypto = require('crypto').webcrypto;
let a = new Uint8Array(24);
console.log(crypto.getRandomValues(a));
This works almost exactly like the one in the browser, by adding webcrypto to the end of requrie('crypto');.
You can use this module which is the same as the window element: get-random-values
Install it:
npm install get-random-values --save
Use it:
var getRandomValues = require('get-random-values');
var array = new Uint32Array(10);
getRandomValues(array);
Here is how to use it in Node 16 with TypeScript. I'm hijacking the web types and overriding the #types/node type, which are missing webcrypto.
import { webcrypto } from 'crypto'
const crypto = webcrypto as unknown as Crypto
const random = crypto.getRandomValues(new Uint8Array(24))
This sandbox will work in Node 16, but stackblitz won't release node 16 for another couple months. https://stackblitz.com/edit/koa-starter-wychx9?file=package.json
Issue: github.com/denoland/node_deno_shims/issues/56
I had this problem too, I solved it this way
import * as crypto from 'node:crypto'
export function randomChar() {
return crypto.webcrypto.getRandomValues(new BigUint64Array(1))[0].toString(36)
}
reference:
How to use getRandomValues() in nodejs?

Categories