I'm attempting to use Object.assign()
in an ES6 web app compiled by Babel with webpack, but I'm getting an error:
Uncaught TypeError: Object.assign is not a function
I'm already using babel-loader
to transpile ES6 to ES5, so all my other ES6 code is working. Yet, Object.assign()
only works after I also import "babel-core/polyfill"
in my codebase. I see that I can also fix this by importing babel-runtime, but I'd like to understand why Object.assign()
requires more than what babel-loader
performs — shouldn't babel-loader
preprocess everything, including Object.assign()
?
Babel, via babel-loader
, transpiles differences in ES6 syntax. Babel on its own does absolutely nothing to add in ES6 standard library functionality (like Object.assign
). Loading the polyfill loads a separate polyfill core-js
for you, but you can load any polyfill you want.
Even some syntax conversions rely on specific polyfill functionality to be loads, since some syntax relies on algorithms and behaviors implemented in library code. The ES6 features on http://babeljs.io/docs/learn-es2015/ each list what standard library functionality are assumed to have been loaded.
Object.assign()
is a new API that's part of ES6 spec, so it's not implemented in most browsers yet. See: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
So when you import babel-core/polyfill
, it adds polyfills to this, and other new APIs, so that your ES6 code can use them.
babel-loader
is just the transpiler that converts ES6 syntax to ES5 compatible code.
If you go down to Compatibility you can see IE 11 is not supported in both Web and Mobile for object.assign. It also gives you the pollyfill for that.
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
if (typeof Object.assign != 'function') {
Object.assign = function(target, varArgs) {
'use strict';
if (target == null) { // TypeError if undefined or null
throw new TypeError('Cannot convert undefined or null to object');
}
var to = Object(target);
for (var index = 1; index < arguments.length; index++) {
var nextSource = arguments[index];
if (nextSource != null) { // Skip over if undefined or null
for (var nextKey in nextSource) {
// Avoid bugs when hasOwnProperty is shadowed
if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
to[nextKey] = nextSource[nextKey];
}
}
}
}
return to;
};
}
If using Babel
https://babeljs.io/docs/plugins/transform-object-assign/
If using NPM
https://www.npmjs.com/package/object-assign
I faced the same problem. I thought I'm safe to use all ES2015+ featues when backed by babel. But as it was mentioned above, babel polyfills only syntax, not functions (Object.assign, Array.includes just to name a few).
For Object.assign I prefer not to use polyfill, but use spread operator. In this case babel actually polyfills Object.assign if not found. Take a look at this code:
let obj = {a: 1};
let obj2 = {...obj};
let obj3 = Object.assign({}, obj);
It will be tranpiled by babel to:
"use strict";
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var obj = { a: 1 };
var obj2 = _extends({}, obj);
var obj3 = Object.assign({}, obj);
For spread operator babel tries to used native Object.assign method and use polyfill if it was not found.
But the explicit Object.assign method is left unchanged ¯\_(ツ)_/¯