如何在JavaScript中创建CoffeeScript风格的存在运算符
How to create a CoffeeScript style existential operator in JavaScript?
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
运算符可以用于尚未声明的内容,因此:
console.log(typeof pancakes);
将简单地在控制台中记录一个CCD_ 9。演示: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中包含可选链接之前,这种功能性方法可能会很有趣(TC39的状态1):
使用代理和Maybe
monad,您可以实现可选的链接,并在失败时返回默认值。
wrap()
函数用于包装要应用可选链接的对象。在内部,wrap
围绕对象创建一个Proxy,并使用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-如何读取json文件中的列并将其保存在Javascript数组中
- 如果使用 lodash 将属性存在于另一个对象中,则向对象添加属性
- Jquery菜单操作不稳定,定位不正确,存在一般错误
- 为什么Airbnb风格指南说不鼓励依赖函数名称推断
- CKEditor-我在editor.css中的风格是't
- 如何使用Spring MVC将Facebook返回的响应数据保存在Java类中
- 用于检查数组中是否存在元素的javascript自定义方法
- 未捕获的类型错误:无法读取属性'name'即使它存在,也无法定义
- 正在将事件处理程序添加到不存在的类
- 是否存在React Native“;WEB代码安全防护”;
- 一个密码测试程序,如果存在空格,它会提醒用户
- 验证会话中是否存在对象's数组
- javascript如果图像不存在don't加载它
- 如何查找值是否存在于二叉树中
- IE9的HTML5 Canvas getImageData()函数存在问题
- 由于响应中不存在“Access Control Allow Origin”标头,跨域请求停止工作
- onclick风格的整个李不想要
- 如何在JavaScript中创建CoffeeScript风格的存在运算符
- Javascript语言中是否存在python风格的占位符
- 最有效(或最风格)的检查JS可选属性是否存在的方法