如何在JavaScript中创建CoffeeScript样式存在操作符?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在JavaScript中创建CoffeeScript样式存在操作符?相关的知识,希望对你有一定的参考价值。
CoffeeScript将user?.id
变成了
if (typeof user !== "undefined" && user !== null) {
user.id;
}
是否有可能创建一个类似的javascript函数exists
?即
exists(user).id
会导致user.id
或null
如果函数接受另一个参数,即exists(user, 'id')
会更容易,但这看起来不太好。
不,你不能产生这样的功能。问题是这个:
any_function(undeclared_variable)
如果没有在任何地方声明undeclared_variable
,将产生ReferenceError。例如,如果您运行此独立代码:
function f() { }
f(pancakes);
你会得到一个ReferenceError,因为pancakes
没有在任何地方声明。演示:http://jsfiddle.net/ambiguous/wSZaL/
但是,typeof
operator可用于尚未声明的内容,如下所示:
console.log(typeof pancakes);
只需在控制台中记录一个undefined
。演示:http://jsfiddle.net/ambiguous/et2Nv/
如果您不介意可能的ReferenceErrors,那么您已经在问题中拥有了必要的功能:
function exists(obj, key) {
if (typeof obj !== "undefined" && obj !== null)
return obj[key];
return null; // Maybe you'd want undefined instead
}
或者,因为您不需要在未声明的变量上使用typeof
,您可以将其简化为:
function exists(obj, key) {
if(obj != null)
return obj[key];
return null;
}
注意!=
,undefined == null
的变化是真的,即使undefined === null
不是。
很老的问题,但让我思考这个解决方案。
exists = (obj) => obj || {}
exists(nullableObject).propName;
我认为这种功能方法可能很有趣,直到JavaScript (State 1 of TC39)中包含可选链接:
使用代理和Maybe
monad,您可以实现可选链接,并在发生故障时使用默认值返回。
wrap()
函数用于包装要应用可选链接的对象。在内部,wrap
在您的对象周围创建一个代理,并使用Maybe
包装器管理缺失值。
在链的末尾,您通过将getOrElse(default)
链接到默认值来解包该值,该默认值在链无效时返回:
const obj = {
a: 1,
b: {
c: [4, 1, 2]
},
c: () => 'yes'
};
console.log(wrap(obj).a.getOrElse(null)) // returns 1
console.log(wrap(obj).a.b.c.d.e.f.getOrElse(null)) // returns null
console.log(wrap(obj).b.c.getOrElse([])) // returns [4, 1, 2]
console.log(wrap(obj).b.c[0].getOrElse(null)) // returns 4
console.log(wrap(obj).b.c[100].getOrElse(-1)) // returns -1
console.log(wrap(obj).c.getOrElse(() => 'no')()) // returns 'yes'
console.log(wrap(obj).d.getOrElse(() => 'no')()) // returns 'no'
wrap(obj).noArray.getOrElse([1]).forEach(v => console.log(v)) // Shows 1
wrap(obj).b.c.getOrElse([]).forEach(v => console.log(v)) // Shows 4, 1, 2
完整的例子:
class Maybe {
constructor(value) {
this.__value = value;
}
static of(value){
if (value instanceof Maybe) return value;
return new Maybe(value);
}
getOrElse(elseVal) {
return this.isNothing() ? elseVal : this.__value;
}
isNothing() {
return this.__value === null || this.__value === undefined;
}
map(fn) {
return this.isNothing()
? Maybe.of(null)
: Maybe.of(fn(this.__value));
}
}
function wrap(obj) {
function fix(object, property) {
const value = object[property];
return typeof value === 'function' ? value.bind(object) : value;
}
return new Proxy(Maybe.of(obj), {
get: function(target, property) {
if (property in target) {
return fix(target, property);
} else {
return wrap(target.map(val => fix(val, property)));
}
}
});
}
const obj = { a: 1, b: { c: [4, 1, 2] }, c: () => 'yes' };
console.log(wrap(obj).a.getOrElse(null))
console.log(wrap(obj).a.b.c.d.e.f.getOrElse(null))
console.log(wrap(obj).b.c.getOrElse([]))
console.log(wrap(obj).b.c[0].getOrElse(null))
console.log(wrap(obj).b.c[100].getOrElse(-1))
console.log(wrap(obj).c.getOrElse(() => 'no')())
console.log(wrap(obj).d.getOrElse(() => 'no')())
wrap(obj).noArray.getOrElse([1]).forEach(v => console.log(v)) // Shows 1
wrap(obj).b.c.getOrElse([]).forEach(v => console.log(v)) // Shows 4, 1, 2
以上是关于如何在JavaScript中创建CoffeeScript样式存在操作符?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 JavaScript 中创建哈希或字典对象 [重复]
javascript 如何在JavaScript中创建对象或数组的副本?