JavaScript isset() equivalent答解释结论

2022-08-29 22:39:11

在PHP中,你可以做.在JavaScript中,你经常用它来做同样的事情,但这并不是完全相同的语句。如果确实存在,则该条件的计算结果也将为 false,但 is 是 或(可能还有其他值)。if(isset($array['foo'])) { ... }if(array.foo) { ... }array.foofalse0

JavaScript中PHP的完美等价物是什么?isset

从更广泛的意义上说,关于JavaScript处理不存在的变量,没有值的变量等的一般,完整的指南将很方便。


更新:11年零11个月前,我发布了这个问题,哇,它仍然有很多活动。现在,我很确定当我写这篇文章时,我只想知道如何检查关联数组(又名字典)中是否存在属性,因此正确的(对我来说)答案涉及或运算符。我对检查局部或全局变量不感兴趣。hasOwnPropertyin

但是,虽然我记得很清楚,但在所写的问题中,这种意图并不是很明确,甚至与它直接矛盾!我从来没有提到过关联数组,PHP也做其他事情。让我们所有人都能成为一个教训,让我们了解在一个问题中正确陈述您的要求是多么重要,以及全局变量,局部变量,对象属性,字典键和您拥有的东西如何不是休伊,杜威和路易。isset

与此同时(嘿嘿),许多人也提供了这个问题的答案,所以对于那些通过谷歌找到这个问题的人来说,好吧,我很高兴我的模糊性在某种程度上有所帮助。无论如何,只是想澄清一下。


答案 1

我通常使用typeof运算符:

if (typeof obj.foo !== 'undefined') {
  // your code here
}

如果属性不存在或其值为 .,它将返回。"undefined"undefined

(另请参阅:未定义和未定义之间的区别。

还有其他方法可以确定对象上是否存在属性,例如 hasOwnProperty 方法:

if (obj.hasOwnProperty('foo')) {
  // your code here
}

和运算符:in

if ('foo' in obj) {
  // your code here
}

最后两者之间的区别在于,该方法将检查该属性是否实际存在于对象上(该属性未被继承)。hasOwnProperty

操作员将检查原型链中可访问的所有属性,例如:in

var obj = { foo: 'bar'};

obj.hasOwnProperty('foo'); // true
obj.hasOwnProperty('toString'); // false
'toString' in obj; // true

如您所见,返回,运算符在检查方法时返回,此方法在原型链中定义,因为继承形式 。hasOwnPropertyfalseintruetoStringobjObject.prototype


答案 2

古老的线程,但有新的方法来运行等效的.isset()

ESNext(2019年12月4日阶段)

两种新的语法使我们能够大大简化功能的使用:isset()

请阅读文档并注意浏览器兼容性。

有关说明,请参见下文。注意:我使用标准JS语法

用法示例

// IMPORTANT pass a function to our isset() that returns the value we're
// trying to test(ES6 arrow function)
isset(() => some) // false

// Defining objects
let some = { nested: { value: 'hello' } }

// More tests that never throw an error
isset(() => some) // true
isset(() => some.nested) // true
isset(() => some.nested.value) // true
isset(() => some.nested.deeper.value) // false

// Less compact but still viable except when trying to use `this` context
isset(function () { return some.nested.deeper.value }) // false

应答功能

/**
 * Checks to see if a value is set.
 *
 * @param   {Function} accessor Function that returns our value
 * @returns {Boolean}           Value is not undefined or null
 */
function isset (accessor) {
  try {
    // Note we're seeing if the returned value of our function is not
    // undefined or null
    return accessor() !== undefined && accessor() !== null
  } catch (e) {
    // And we're able to catch the Error it would normally throw for
    // referencing a property of undefined
    return false
  }
}

NPM 软件包

此应答功能可作为 NPM 上的软件包使用。该包包含一些改进,例如类型检查和支持多个参数。isset-php

npm install --save isset-php

文件中提供了完整的文档。

const isset = require('isset-php')
let val = ''

// This will evaluate to true so the text will be printed.
if (isset(() => val)) {
  console.log('This val is set so I will print.')
}

解释

菲律宾比索

请注意,在 PHP 中,您可以引用任何深度的任何变量 - 即使尝试访问非数组作为数组,也会返回简单或:truefalse

// Referencing an undeclared variable
isset($some); // false

$some = 'hello';

// Declared but has no depth(not an array)
isset($some); // true
isset($some['nested']); // false

$some = ['nested' => 'hello'];

// Declared as an array but not with the depth we're testing for
isset($some['nested']); // true
isset($some['nested']['deeper']); // false

JavaScript

在JavaScript中,我们没有这种自由;如果我们做同样的事情,我们总是会得到一个错误,因为引擎正在立即尝试访问的值,然后我们才能将其包装在我们的函数中,所以...deeperisset()

// Common pitfall answer(ES6 arrow function)
const isset = (ref) => typeof ref !== 'undefined'

// Same as above
function isset (ref) { return typeof ref !== 'undefined' }

// Referencing an undeclared variable will throw an error, so no luck here
isset(some) // Error: some is not defined

// Defining a simple object with no properties - so we aren't defining
// the property `nested`
let some = {}

// Simple checking if we have a declared variable
isset(some) // true

// Now trying to see if we have a top level property, still valid
isset(some.nested) // false

// But here is where things fall apart: trying to access a deep property
// of a complex object; it will throw an error
isset(some.nested.deeper) // Error: Cannot read property 'deeper' of undefined
//         ^^^^^^ undefined

更多失败的替代方案:

// Any way we attempt to access the `deeper` property of `nested` will
// throw an error
some.nested.deeper.hasOwnProperty('value') // Error
//   ^^^^^^ undefined

// Similar to the above but safe from objects overriding `hasOwnProperty`
Object.prototype.hasOwnProperty.call(some.nested.deeper, 'value') // Error
//                                        ^^^^^^ undefined

// Same goes for typeof
typeof some.nested.deeper !== 'undefined' // Error
//          ^^^^^^ undefined

以及一些可以快速冗余的工作替代方案:

// Wrap everything in try...catch
try {
  if (isset(some.nested.deeper)) {
    // ...
  }
} catch (e) {}

try {
  if (some.nested.deeper !== undefined && some.nested.deeper !== null) {
    // ...
  }
} catch (e) {}

// Or by chaining all of the isset which can get long
isset(some) && isset(some.nested) && isset(some.nested.deeper) // false
//                        ^^^^^^ returns false so the next isset() is never run

结论

所有其他答案 - 尽管大多数都是可行的...

  1. 假设您只是检查变量是否未定义,这对于某些用例来说很好,但仍可能引发错误
  2. 假设您只是尝试访问顶级属性,这对于某些用例来说也很好。
  3. 强制您使用相对于PHP的
    不太理想的方法,例如isset()isset(some, 'nested.deeper.value')
  4. 使用哪个有效,但我个人避免eval()

我想我涵盖了很多。我在回答中提出的一些观点我没有触及,因为它们虽然相关,但不是问题的一部分(例如短路)。但是,如果需要,我可以根据需要使用指向一些更技术性方面的链接来更新我的答案。

我花了很多时间在这上面,所以希望它能帮助人们。

感谢您的阅读!