Asked  7 Months ago    Answers:  5   Viewed   35 times

Is there a null-safe property access (null propagation / existence) operator in ES6 (ES2015/JavaScript.next/Harmony) like ?. in CoffeeScript for example? Or is it planned for ES7?

var aThing = getSomething()
...
aThing = possiblyNull?.thing

This will be roughly like:

if (possiblyNull != null) aThing = possiblyNull.thing

Ideally the solution should not assign (even undefined) to aThing if possiblyNull is null

 Answers

23

Update (2020-01-31): Seems people are still finding this, here's the current story:

  • Optional Chaining specification (Stage 4): https://github.com/tc39/proposal-optional-chaining
  • babel-preset-env: This is probably what you want https://babeljs.io/docs/en/babel-preset-env
  • Babel v7 Plugin: https://babeljs.io/docs/en/babel-plugin-proposal-optional-chaining

Update (2017-08-01): If you want to use an official plugin, you can try the alpha build of Babel 7 with the new transform. Your mileage may vary

https://www.npmjs.com/package/babel-plugin-transform-optional-chaining

Original:

A feature that accomplishes that is currently in stage 1: Optional Chaining.

https://github.com/tc39/proposal-optional-chaining

If you want to use it today, there is a Babel plugin that accomplishes that.

https://github.com/davidyaha/ecmascript-optionals-proposal

Tuesday, June 1, 2021
 
Savageman
answered 7 Months ago
89

According to my reading of the spec, this should be parseable, but it doesn't mean what you think. It would be parsed from right-to-left as

const env = ({ENV_VAR_X, ENV_VAR_Y, ENV_VAR_Z} = process.env);

where the production

({ENV_VAR_X, ENV_VAR_Y, ENV_VAR_Z} = process.env)

is defined, like all other assignments, as evaluating to the RHS, which is process.env.

Therefore, your code is equivalent to

const {ENV_VAR_X, ENV_VAR_Y, ENV_VAR_Z} = process.env;
const env = process.env;

It's quite easy to validate this:

const foo = {a: 1, b: 2};
const bar = {a} = foo;

results in a new constant a being declared with the value 1, as you would expect. However, the value of bar is not an "alias to the deconstructed object", which would be {a: 1}; it's the same as foo, which is {a: 1, b: 2}. bar === foo.


What you are trying to do has been discussed many times here on SO and also in the ES discuss group. The bottom line is that there is no way to do this. All you can do is:

const {ENV_VAR_X, ENV_VAR_Y, ENV_VAR_Z} = process.env;
const env = {ENV_VAR_X, ENV_VAR_Y, ENV_VAR_Z};

In other words, there is no way to "deconstruct from an object into an object", or "pick from an object into an object". You can only deconstruct from an object into variables.

You could fall back to the old-fashioned way:

const env = {ENV_VAR_X: process.env.ENV_VAR_X, ...

which I know is horrible.

You could use the pick function from underscore or write your own, but that requires you to say

const env = _.pick(process.env, 'ENV_VAR_X', "ENV_VAR_Y', 'ENV_VAR_Z');

which is only slightly less horrible.

We have "rest properties" and "spread properties" proposed for ES7, but they do not seem to help us here.


What we need is a new syntax for picking properties into another object. There have been various proposals made for this, none of which has gained much traction. One is the "extended dot notation", which allows a curly-bracketed construct to be put after a dot. In your case, you would write

const env = process.env.{ENV_VAR_X, ENV_VAR_Y, ENV_VAR_Z};
                       ^^

You can find out more about this proposal here.

Tuesday, June 15, 2021
 
Drazisil
answered 6 Months ago
56

I was having the exact same problem before myself... As Qantas mentioned in the comments, Babel (formerly 6to5) will convert syntax, but it won't do module loading or polyfills.

I've found the easiest workflow is using browserify with gulp. This takes care of transpiling, adding polyfills, bundling, minification, and source map generation in one hit. This question has a pretty nice example: Gulp + browserify + 6to5 + source maps.

This version adds minification and polyfills. An example for your case would look like this:

let gulp = require('gulp');
let browserify = require('browserify');
let babelify = require('babelify');
let util = require('gulp-util');
let buffer = require('vinyl-buffer');
let source = require('vinyl-source-stream');
let uglify = require('gulp-uglify');
let sourcemaps = require('gulp-sourcemaps');

gulp.task('build:demo', () => {
    browserify('./demo/app.js', { debug: true })
    .add(require.resolve('babel-polyfill/dist/polyfill.min.js'))
    .transform(babelify.configure({ presets: ['es2015', 'es2016', 'stage-0', 'stage-3'] }))
    .bundle()
    .on('error', util.log.bind(util, 'Browserify Error'))
    .pipe(source('demo.js'))
    .pipe(buffer())
    .pipe(sourcemaps.init({ loadMaps: true }))
    .pipe(uglify({ mangle: false }))
    .pipe(sourcemaps.write('./'))
    .pipe(gulp.dest('./demo'));
});

gulp.task('default', ['build:demo']);

It's important that uglify has mangle set to false; it really doesn't seem to play nice with the transformed code.

If you don't have all the dependencies installed, you may want to create a package.json file, and ensure that following packages are defined in the dependencies object:

"devDependencies": {
    "babel-polyfill": "^6.13.0",
    "babel-preset-es2015": "^6.13.0",
    "babel-preset-es2016": "^6.11.0",
    "babel-preset-stage-0": "^6.5.0",
    "babel-preset-stage-3": "^6.11.0",
    "babelify": "^7.3.0",
    "browserify": "^13.1.0",
    "gulp": "^3.9.0",
    "gulp-sourcemaps": "^1.6.0",
    "gulp-uglify": "^2.0.0",
    "gulp-util": "^3.0.0",
    "vinyl-buffer": "^1.0.0",
    "vinyl-source-stream": "^1.1.0"
}

Most of these won't work if installed with -g, so consider yourself warned :P

Then, just run npm install to install all the dependencies, and gulp to run the default task and transpile all of your code.

Your other files look good, you have the right idea with importing at the beginning of each file and exporting your defaults :) If you want some examples of babelified ES6 in the wild, I have a couple of projects on GitHub that might help.

Tuesday, August 10, 2021
 
nhunston
answered 4 Months ago
99

Yep:

context.getPackageManager().getPackageInfo (context.getPackageName(), 0).versionName;
context.getPackageManager().getPackageInfo (context.getPackageName(), 0).versionCode;
Wednesday, August 18, 2021
 
Ujjawal Khare
answered 4 Months ago
71

Sure, you can use tf.where to conditionally set values:

b = tf.Variable(a)
tf.where(b >= 3, 199, b)
# <tf.Tensor: shape=(6,), dtype=int64, numpy=array([  1,   2, 199, 199, 199, 199])>
Tuesday, August 31, 2021
 
wenjiehu
answered 4 Months ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :  
Share