Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/jquery/83.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
javascript中是否有空合并(Elvis)运算符或安全导航运算符?_Javascript_Jquery_Groovy_Safe Navigation Operator - Fatal编程技术网

javascript中是否有空合并(Elvis)运算符或安全导航运算符?

javascript中是否有空合并(Elvis)运算符或安全导航运算符?,javascript,jquery,groovy,safe-navigation-operator,Javascript,Jquery,Groovy,Safe Navigation Operator,我将举例说明: 埃尔维斯算子(?) “Elvis运算符”是一个缩写 Java的三元运算符。一个 这个方便的例子是 返回“合理默认”值 如果表达式解析为false或 无效的一个简单的例子可能是这样的 这: 安全导航操作员(?) 使用安全导航操作器 以避免NullPointerException。 通常,当您引用 可能需要验证的对象 它在访问之前不为null 对象的方法或属性。 为了避免这种情况,安全导航 运算符只返回null 而不是抛出异常,比如 因此: 这通常称为空合并运算符。Javascrip

我将举例说明:

埃尔维斯算子(?)

“Elvis运算符”是一个缩写 Java的三元运算符。一个 这个方便的例子是 返回“合理默认”值 如果表达式解析为false或 无效的一个简单的例子可能是这样的 这:

安全导航操作员(?)

使用安全导航操作器 以避免NullPointerException。 通常,当您引用 可能需要验证的对象 它在访问之前不为null 对象的方法或属性。 为了避免这种情况,安全导航 运算符只返回null 而不是抛出异常,比如 因此:


这通常称为空合并运算符。Javascript没有。Javascript是并可以替换“Elvis”操作符:

var displayName = user.name || "Anonymous";

但是,据我所知,没有与您的
?。
运算符等效的运算符。

您可以通过以下方式实现大致相同的效果:

var displayName = user.name || "Anonymous";

对于前者,可以使用
|
。Javascript“logical or”操作符不是简单地返回固定的真值和假值,而是遵循以下规则:如果左参数为真,则返回左参数,否则计算并返回右参数。当您只对真值感兴趣时,结果是一样的,但这也意味着
foo | | bar | baz
返回包含真值的foo、bar或baz中最左边的一个


但是,您找不到可以区分false和null的值,并且0和空字符串都是false值,因此请避免使用
值| |默认值
结构,其中
值可以合法地为0或
您可以使用逻辑“或”运算符代替Elvis运算符:

var displayName = user.name || "Anonymous";
例如
displayname=user.name | |“匿名”

但是Javascript目前没有其他功能。我建议您看看是否需要其他语法。它有一些速记,类似于你正在寻找的

例如存在算子

zip = lottery.drawWinner?().address?.zipcode
功能快捷方式

()->  // equivalent to function(){}
性感函数调用

func 'arg1','arg2' // equivalent to func('arg1','arg2')

还有多行注释和类。显然,您必须将其编译为javascript或作为
插入到页面中我有一个解决方案,根据您自己的需要进行定制,摘自我的一个LIB:

    elvisStructureSeparator: '.',

    // An Elvis operator replacement. See:
    // http://coffeescript.org/ --> The Existential Operator
    // http://fantom.org/doc/docLang/Expressions.html#safeInvoke
    //
    // The fn parameter has a SPECIAL SYNTAX. E.g.
    // some.structure['with a selector like this'].value transforms to
    // 'some.structure.with a selector like this.value' as an fn parameter.
    //
    // Configurable with tulebox.elvisStructureSeparator.
    //
    // Usage examples: 
    // tulebox.elvis(scope, 'arbitrary.path.to.a.function', fnParamA, fnParamB, fnParamC);
    // tulebox.elvis(this, 'currentNode.favicon.filename');
    elvis: function (scope, fn) {
        tulebox.dbg('tulebox.elvis(' + scope + ', ' + fn + ', args...)');

        var implicitMsg = '....implicit value: undefined ';

        if (arguments.length < 2) {
            tulebox.dbg(implicitMsg + '(1)');
            return undefined;
        }

        // prepare args
        var args = [].slice.call(arguments, 2);
        if (scope === null || fn === null || scope === undefined || fn === undefined 
            || typeof fn !== 'string') {
            tulebox.dbg(implicitMsg + '(2)');
            return undefined;   
        }

        // check levels
        var levels = fn.split(tulebox.elvisStructureSeparator);
        if (levels.length < 1) {
            tulebox.dbg(implicitMsg + '(3)');
            return undefined;
        }

        var lastLevel = scope;

        for (var i = 0; i < levels.length; i++) {
            if (lastLevel[levels[i]] === undefined) {
                tulebox.dbg(implicitMsg + '(4)');
                return undefined;
            }
            lastLevel = lastLevel[levels[i]];
        }

        // real return value
        if (typeof lastLevel === 'function') {
            var ret = lastLevel.apply(scope, args);
            tulebox.dbg('....function value: ' + ret);
            return ret;
        } else {
            tulebox.dbg('....direct value: ' + lastLevel);
            return lastLevel;
        }
    },
elvisStructureSeparator:',
//Elvis操作员的更换。见:
// http://coffeescript.org/ -->存在算子
// http://fantom.org/doc/docLang/Expressions.html#safeInvoke
//
//fn参数具有特殊语法。例如。
//some.structure['带有如下']这样的选择器。值转换为
//“some.structure.with a selector this.value”作为fn参数。
//
//可配置tulebox.elvisStructureSeparator。
//
//用法示例:
//elvis(作用域,'arbitral.path.to.a.function',fnParamA,fnParamB,fnParamC);
//elvis(这是“currentNode.favicon.filename”);
elvis:功能(范围,fn){
tulebox.dbg('tulebox.elvis('+scope+','+fn+',args…);
var implicitMsg='..隐式值:未定义';
if(arguments.length<2){
tulebox.dbg(隐式msg+'(1');
返回未定义;
}
//准备args
var args=[].slice.call(参数,2);
如果(范围===null | | fn===null | |范围===未定义| | fn==未定义
||typeof fn!=“字符串”){
tulebox.dbg(隐式msg+'(2');
返回未定义;
}
//检查水平
风险值水平=fn.分割(tulebox.elvisStructureSeparator);
if(levels.length<1){
tulebox.dbg(隐式msg+'(3');
返回未定义;
}
var lastLevel=范围;
对于(变量i=0;i

工作起来很有魅力。享受更少的痛苦

您可以自己制作:

function resolve(objectToGetValueFrom, stringOfDotSeparatedParameters) {
    var returnObject = objectToGetValueFrom,
        parameters = stringOfDotSeparatedParameters.split('.'),
        i,
        parameter;

    for (i = 0; i < parameters.length; i++) {
        parameter = parameters[i];

        returnObject = returnObject[parameter];

        if (returnObject === undefined) {
            break;
        }
    }
    return returnObject;
};

*如果a、b、c或d中的任何一个未定义,则结果未定义。

这里有一个简单的等效elvis运算符:

function elvis(object, path) {
    return path ? path.split('.').reduce(function (nestedObject, key) {
        return nestedObject && nestedObject[key];
    }, object) : object;
}

> var o = { a: { b: 2 }, c: 3 };
> elvis(o)

{ a: { b: 2 }, c: 3 }

> elvis(o, 'a');

{ b: 2 }

> elvis(o, 'a.b');

2

> elvis(o, 'x');

undefined

我认为以下内容相当于安全导航操作器,虽然有点长:

var streetName = user && user.address && user.address.street;
streetName
将是
user.address.street
未定义的值

const myVariable = a?.b?.c ?? 'Some other value';

// Evaluates to 'Some other value'
const myVariable2 = null ?? 'Some other value';

// Evaluates to ''
const myVariable3 = '' ?? 'Some other value';
如果希望它默认为其他内容,可以与上述快捷方式结合使用,或提供:

var streetName = (user && user.address && user.address.street) || "Unknown Street";

我认为lodash在这里会有所帮助,比如在
.get(user,'name')
和更复杂的任务中,比如
.get(o,'a[0].b.c','default value')
我偶尔发现以下习惯用法很有用:

a?.b?.c
可以重写为:

((a||{}).b||{}).c

这利用了一个事实,即获取对象上的未知属性会返回undefined,而不是像在
null
undefined
上那样抛出异常,因此,在导航之前,我们将null和undefined替换为空对象。

对于安全导航操作员来说,这是一个有趣的解决方案,它使用了一些mixin

我个人使用

function e(e,expr){try{return eval(expr);}catch(e){return null;}};
例如,安全获取:

var a = e(obj,'e.x.y.z.searchedField');

目前有一个规范草案:

不过现在,我喜欢使用or

更新(截至2019年12月23日): 可选链接已移至第4阶段

我阅读了本文()并使用代理修改了解决方案

function safe(obj) {
    return new Proxy(obj, {
        get: function(target, name) {
            const result = target[name];
            if (!!result) {
                return (result instanceof Object)? safe(result) : result;
            }
            return safe.nullObj;
        },
    });
}

safe.nullObj = safe({});
safe.safeGet= function(obj, expression) {
    let safeObj = safe(obj);
    let safeResult = expression(safeObj);

    if (safeResult === safe.nullObj) {
        return undefined;
    }
    return safeResult;
}
var a = e(obj,'e.x.y.z.searchedField');
function safe(obj) {
    return new Proxy(obj, {
        get: function(target, name) {
            const result = target[name];
            if (!!result) {
                return (result instanceof Object)? safe(result) : result;
            }
            return safe.nullObj;
        },
    });
}

safe.nullObj = safe({});
safe.safeGet= function(obj, expression) {
    let safeObj = safe(obj);
    let safeResult = expression(safeObj);

    if (safeResult === safe.nullObj) {
        return undefined;
    }
    return safeResult;
}
safe.safeGet(example, (x) => x.foo.woo)
Object.prototype.getSafe = function (expression) {
    return safe.safeGet(this, expression);
};

example.getSafe((x) => x.foo.woo);
// this will create the object/array if null
Object.prototype.__ = function (prop) {
    if (this[prop] === undefined)
        this[prop] = typeof prop == 'number' ? [] : {}
    return this[prop]
};

// this will just check if object/array is null
Object.prototype._ = function (prop) {
    return this[prop] === undefined ? {} : this[prop]
};
let student = {
    classes: [
        'math',
        'whatev'
    ],
    scores: {
        math: 9,
        whatev: 20
    },
    loans: [
        200,
        { 'hey': 'sup' },
        500,
        300,
        8000,
        3000000
    ]
}

// use one underscore to test

console.log(student._('classes')._(0)) // math
console.log(student._('classes')._(3)) // {}
console.log(student._('sports')._(3)._('injuries')) // {}
console.log(student._('scores')._('whatev')) // 20
console.log(student._('blabla')._('whatev')) // {}
console.log(student._('loans')._(2)) // 500 
console.log(student._('loans')._(1)._('hey')) // sup
console.log(student._('loans')._(6)._('hey')) // {} 

// use two underscores to create if null

student.__('loans').__(6)['test'] = 'whatev'

console.log(student.__('loans').__(6).__('test')) // whatev

// `undefined` if either `a` or `b` are `null`/`undefined`. `a.b.c` otherwise.
const myVariable = a?.b?.c;
const myVariable = a && a.b && a.b.c;
const myVariable = a?.b?.c ?? 'Some other value';

// Evaluates to 'Some other value'
const myVariable2 = null ?? 'Some other value';

// Evaluates to ''
const myVariable3 = '' ?? 'Some other value';
const myVariable = a?.b?.c || 'Some other value';

// Evaluates to 'Some other value'
const myVariable2 = null || 'Some other value';

// Evaluates to 'Some other value'
const myVariable3 = '' || 'Some other value';