Odpowiednik isset () JavaScript


552

W PHP możesz to zrobić if(isset($array['foo'])) { ... }. W JavaScript często if(array.foo) { ... }robisz to samo, ale nie jest to dokładnie to samo zdanie. Warunek oceni również na false, jeśli array.fooistnieje, ale jest falselub 0(i prawdopodobnie również inne wartości).

Jaki jest idealny odpowiednik PHP issetw JavaScript?

W szerszym sensie wygodny byłby ogólny, kompletny przewodnik po JavaScript w obsłudze zmiennych, które nie istnieją, zmiennych bez wartości itp.


1
Napisałem funkcję, która przetestuje istnienie właściwości obiektu bez względu na głębokość zapytania: stackoverflow.com/a/12681101/1268003 Używając mojego kodu w połączeniu z pewną wiedzą udostępnioną przez @CMS w tym wątku, możesz łatwo napisać globalny funkcja, która działa bardzo podobnie do isset PHP: s.
Martin Andersson

3
Jeśli używasz Underscore.js, spróbuj_.isUndefined(arr.foo)
Vitalii Fedorenko

Odpowiedzi:


938

Ogólnie używam typeofoperatora:

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

Zwróci "undefined"albo, jeśli właściwość nie istnieje, albo jej wartość to undefined.

(Zobacz także: Różnica między undefinedbrakiem zdefiniowania ).

Istnieją inne sposoby ustalenia, czy właściwość istnieje na obiekcie, takie jak hasOwnPropertymetoda:

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

A inoperator:

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

Różnica między dwoma ostatnimi polega na tym, że hasOwnPropertymetoda sprawdzi, czy właściwość istnieje fizycznie na obiekcie (właściwość nie jest dziedziczona).

inOperator sprawdzi na wszystkich właściwości osiągalny w łańcuchu prototypów, np:

var obj = { foo: 'bar'};

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

Jak widać, hasOwnPropertyzwraca falsei inoperator wraca truepodczas sprawdzania toStringmetody, metoda ta jest zdefiniowana w łańcuchu prototypów, ponieważ objdziedziczy formę Object.prototype.


23
Dlaczego używać typeofzamiast if( obj.foo !== undefined )?
Matt Ball

7
Ach Pewnego dnia napiszę fragment prawdziwie przeglądarkowego Javascript. Do tego czasu ...
Matt Ball

37
Problem polega na tym, że podczas próby sprawdzenia głębszych właściwości pojawia się błąd, na przykład: obj.thisdoesntexist.foo! == undefined. W PHP możesz używać isset lub pustych i bezpiecznie na dowolnej głębokości.
Enrique,

6
IE8 nie ma „hasOwnPropery”
max4ever

12
Dokładnie, PHP pozwala isset($abc->def->ghi->jkl)bez zgłaszania wyjątku i zatrzymywania skryptu, w przeciwieństwie do typeofoperatora JavaScript . Musisz użyć czegoś takiego jak try{ abc.def.ghi.jkl; isset=true } catch(e){ isset=false }
Steven Pribilinskiy

43

Staroświecki wątek, ale istnieją nowe sposoby prowadzenia odpowiednika isset() .

ESNext (etap 4 grudnia 2019 r.)

Dwie nowe składnie pozwalają nam znacznie uprościć korzystanie z isset()funkcjonalności:

Przeczytaj dokumenty i pamiętaj o zgodności przeglądarki.

Poprzednia odpowiedź

Wyjaśnienia poniżej. Uwaga Używam składni StandardJS

Przykładowe użycie

// 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

Funkcja odpowiedzi

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

Wyjaśnienie

PHP

Zauważ, że w PHP możesz odwoływać się do dowolnej zmiennej na dowolnej głębokości - nawet próbując uzyskać dostęp do nie-tablicy, ponieważ tablica zwróci prosty truelub false:

// 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

JS

W JavaScript nie mamy tej swobody, zawsze otrzymamy błąd, jeśli zrobimy to samo, ponieważ JS natychmiast próbuje uzyskać dostęp do wartości, deeper zanim będziemy mogli zawinąć ją w naszą isset()funkcję, aby ...

// 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

Więcej nieudanych alternatyw:

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

Object.hasOwnProperty('value', some.nested.deeper) // Error
//                                  ^^^^^^ undefined

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

I niektóre działające alternatywy, które mogą szybko stać się zbędne:

// Wrap everything in try...catch
try { isset(some.nested.deeper) } catch (e) {}
try { typeof some.nested.deeper !== 'undefined' } 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

Wniosek

Wszystkie pozostałe odpowiedzi - choć większość jest wykonalna ...

  1. Załóżmy, że sprawdzasz tylko, czy zmienna nie jest niezdefiniowana, co jest odpowiednie w niektórych przypadkach użycia, ale nadal może generować błąd
  2. Załóżmy, że próbujesz uzyskać dostęp tylko do właściwości najwyższego poziomu, co znowu jest w porządku w niektórych przypadkach użycia
  3. Zmusza cię do zastosowania mniej niż idealnego podejścia w stosunku do PHP isset()
    npisset(some, 'nested.deeper.value')
  4. Użyj, eval()który działa, ale ja osobiście go unikam

Myślę, że dużo tego omówiłem. W mojej odpowiedzi zwracam uwagę na pewne kwestie, których nie dotykam, ponieważ - choć istotne - nie są częścią pytania. W razie potrzeby mogę zaktualizować swoją odpowiedź za pomocą linków do niektórych bardziej technicznych aspektów opartych na zapotrzebowaniu.

Spędziłem nad tym dużo czasu, więc mam nadzieję, że to pomaga ludziom wyjść.

Dziękuję za przeczytanie!


25

Odniesienie do ŹRÓDŁA

    module.exports = function isset () {
  //  discuss at: http://locutus.io/php/isset/
  // original by: Kevin van Zonneveld (http://kvz.io)
  // improved by: FremyCompany
  // improved by: Onno Marsman (https://twitter.com/onnomarsman)
  // improved by: Rafał Kukawski (http://blog.kukawski.pl)
  //   example 1: isset( undefined, true)
  //   returns 1: false
  //   example 2: isset( 'Kevin van Zonneveld' )
  //   returns 2: true

  var a = arguments
  var l = a.length
  var i = 0
  var undef

  if (l === 0) {
    throw new Error('Empty isset')
  }

  while (i !== l) {
    if (a[i] === undef || a[i] === null) {
      return false
    }
    i++
  }

  return true
}

phpjs.org jest w większości na emeryturze na rzecz locutus Oto nowy link http://locutus.io/php/var/isset


6
Spowoduje to wyjątek podczas dzwonienia isset(abc.def.ghi)w przypadku, gdy abc.defjest niezdefiniowany. Jednak łącząc to rozwiązanie z tym, które akceptuje nazwę zmiennej w postaci łańcucha, będzie ona identyczna z wersją PHP.
Steven Pribilinskiy


8
//
//  tring to reference non-existing variable throws ReferenceError 
//  before test function is even executed
//
//  example, if you do:
//    
//     if ( isset( someVar ) ) 
//        doStuff( someVar );
//   
//  you get a ReferenceError ( if there is no someVar... ) 
//  and isset fn doesn't get executed.
//
//  if you pass variable name as string, ex. isset( 'novar' );, 
//  this might work:
//
function isset ( strVariableName ) { 

    try { 
        eval( strVariableName );
    } catch( err ) { 
        if ( err instanceof ReferenceError ) 
           return false;
    }

    return true;

 } 
//
//


6

Zawsze używam tej funkcji ogólnej, aby uniknąć błędów w prymitywnych zmiennych, a także tablicach i obiektach.

isset = function(obj) {
  var i, max_i;
  if(obj === undefined) return false;
  for (i = 1, max_i = arguments.length; i < max_i; i++) {
    if (obj[arguments[i]] === undefined) {
        return false;
    }
    obj = obj[arguments[i]];
  }
  return true;
};

console.log(isset(obj));                   // returns false
var obj = 'huhu';
console.log(isset(obj));                   // returns true
obj = {hallo:{hoi:'hoi'}};
console.log(isset(obj, 'niet'));           // returns false
console.log(isset(obj, 'hallo'));          // returns true
console.log(isset(obj, 'hallo', 'hallo')); // returns false
console.log(isset(obj, 'hallo', 'hoi'));   // returns true


4

Jest to dość kuloodporne rozwiązanie do testowania, czy istnieje zmienna:

var setOrNot = typeof variable !== typeof undefined ? true : false;

Niestety nie można po prostu hermetyzować go w funkcji.

Możesz pomyśleć o zrobieniu czegoś takiego:

function isset(variable) {
    return typeof variable !== typeof undefined ? true : false;
}

Spowoduje to jednak wygenerowanie błędu odniesienia, jeśli zmienna variablenie została zdefiniowana, ponieważ nie można przekazać funkcji do nieistniejącej zmiennej:

Uncaught ReferenceError: foo nie jest zdefiniowane

Z drugiej strony pozwala przetestować, czy parametry funkcji są niezdefiniowane:

var a = '5';

var test = function(x, y) {
    console.log(isset(x));
    console.log(isset(y));
};

test(a);

// OUTPUT :
// ------------
// TRUE
// FALSE

Mimo że ydo funkcji nie jest przekazywana żadna wartość test, nasza issetfunkcja działa idealnie w tym kontekście, ponieważ yjest znana w funkcji testjako undefinedwartość.


Drobne nit: `? prawda: fałsz jest zbędny. Wynik !==jest już wartością logiczną.
ToolmakerSteve

4
(typeof SOMETHING) !== 'undefined'

Przy użyciu jest zbyt długo, aby pisać. Ale nie możemy spakować typeofsłowa kluczowego do funkcji, ponieważ błąd zostanie wygenerowany przed wywołaniem funkcji, tak jak poniżej:

function isdef($var) {
    return (typeof $var) !== 'undefined';
}

isdef(SOMETHING); ///// thrown error: SOMETHING is not defined

Więc wymyśliłem sposób:

function isdef($type) {
    return $type !== 'undefined';
}

isdef(typeof SOMETHING);

Może pracować zarówno z pojedynczymi zmiennymi (zmiennymi, które w ogóle nie istnieją), jak i właściwościami obiektów (właściwości nieistniejące). I tylko 7 znaków więcej niż PHP isset.


To działa dla mnie, użyłem go do sprawdzenia, czy istnieje konkretna odpowiedź JSON.
Julius

3

To rozwiązanie działało dla mnie.

function isset(object){
    return (typeof object !=='undefined');
}

5
Wywoływanie isset(var)z varrozbrojeniem:ReferenceError: var is not defined
Gui Imamura

3
function isset(variable) {
    try {
        return typeof eval(variable) !== 'undefined';
    } catch (err) {
        return false;
    }
}

4
dodaj też opis.
Shree Krishna

Jak wspomniano kilka wcześniejszych odpowiedzi, spowoduje to wywołanie błędu ReferenceError, jeśli zostanie wywołany ze zmienną, która nigdy nie została zadeklarowana. Np. isset(someVar)Gdzie someVarnigdy nie został zadeklarowany. Jednak biorąc pod uwagę to eval, prawdopodobnie zamierzasz przekazać ciąg znaków . Pokaż użycie. Czy zamierzasz używać isset('someVar')? Jeśli tak, wygląda to podobnie do wcześniejszej odpowiedzi - co z twoją odpowiedzią jest nowa?
ToolmakerSteve


3

Aby sprawdzić, czy blok HTML istnieje, czy nie, używam tego kodu:

if (typeof($('selector').html()) != 'undefined') {
    // $('selector') is existing
    // your code here
}

2

Podaj ścieżkę obiektu jako ciąg, a następnie możesz podzielić ten ciąg na ścieżkę i rozwiązać hasOwnPropertyna każdym kroku, zastępując sam obiekt przy każdej iteracji.

Jeśli kodujesz w środowisku ES6, spójrz na pytania dotyczące przepełnienia stosu .

var a;

a = {
    b: {
        c: 'e'
    }
};

function isset (obj, path) {
    var stone;

    path = path || '';

    if (path.indexOf('[') !== -1) {
        throw new Error('Unsupported object path notation.');
    }

    
    path = path.split('.');
    
    do {
        if (obj === undefined) {
            return false;
        }

        stone = path.shift();
        
        if (!obj.hasOwnProperty(stone)) {
            return false;
        }
        
        obj = obj[stone];
        
    } while (path.length);

    return true;
}

console.log(
    isset(a, 'b') == true,
    isset(a, 'b.c') == true,
    isset(a, 'b.c.d') == false,
    isset(a, 'b.c.d.e') == false,
    isset(a, 'b.c.d.e.f') == false
);


2

Używam funkcji, która może sprawdzać zmienne i obiekty. bardzo wygodny w pracy z jQuery

    function _isset (variable) {
        if(typeof(variable) == "undefined" || variable == null)
            return false;
        else
            if(typeof(variable) == "object" && !variable.length) 
                return false;
            else
                return true;
    };

Jak wspomniano kilka wcześniejszych odpowiedzi, spowoduje to wywołanie błędu ReferenceError, jeśli zostanie wywołany ze zmienną, która nigdy nie została zadeklarowana.
ToolmakerSteve

1

To był dla mnie naprawdę problem, kiedy uzyskiwałem dostęp do głębszej właściwości obiektu, więc utworzyłem funkcję, która zwróci wartość właściwości, jeśli istnieje, w przeciwnym razie zwróci fałsz. Możesz go użyć, aby zaoszczędzić czas,

//Object on which we want to test
var foo = {
    bar: {
        bik: {
            baz: 'Hello world'
        }
    }
};


/*
USE: To get value from the object using it properties supplied (Deeper),
    if found it will return the property value if not found then will return false

You can use this function in two ways
WAY - 1:
Passing an object as parameter 1 and array of the properties as parameter 2
EG: getValueFromObject(foo, ['bar', 'bik', 'baz']);
WAY - 2: (This will work only if, your object available in window object)
Passing an STRING as parameter 1(Just similarly how we retrieve value form object using it's properties - difference is only the quote)
EG: getValueFromObject('foo.bar.bik.baz');
*/
function getValueFromObject(object, properties) {
    if(typeof(object) == 'string') {            //Here we extract our object and it's properties from the string
        properties = object.split('.');
        object = window[properties[0]];
        if(typeof(object) == 'undefined') {
            return false;
        }
        properties.shift();
    }
    var property = properties[0];
    properties.shift();
    if(object != null && typeof(object[property]) != 'undefined') {
        if(typeof(object[property]) == 'object') {
            if(properties.length != 0) {
                return getValueFromObject(object[property], properties);    //Recursive call to the function
            } else {
                return object[property];
            }
        } else {
            return object[property];
        }
    } else {
        return false;
    }
}
console.log(getValueFromObject('fooo.bar.bik.baz'));        //false
console.log(getValueFromObject('foo.bar.bik.baz'));         //Hello world
console.log(getValueFromObject('foo'));                     //false
console.log(getValueFromObject('foo.bar.bik'));             //returns an object { baz: 'Hello World' }
console.log(getValueFromObject(foo, ['bar', 'bik']));       //returns an object { baz: 'Hello World' }
console.log(getValueFromObject(foo, ['bar', 'bik', 'baz']));//Hello world

1

Jeśli chcesz sprawdzić, czy element istnieje, użyj następującego kodu:

if (object) {
  //if isset, return true
} else {
  //else return false
}

To jest przykład:

function switchDiv() {
    if (document.querySelector("#divId")) {
        document.querySelector("#divId").remove();
    } else {
        var newDiv = document.createElement("div");
        newDiv.id = "divId";
        document.querySelector("body").appendChild(newDiv);
    }
}

document.querySelector("#btn").addEventListener("click", switchDiv);
#divId {
    background: red;
    height: 100px;
    width: 100px;
    position: relative;
    
}
<body>
  <button id="btn">Let's Diiiv!</button>
</body>



0

Podręcznik PHP mówi:

isset - Określ, czy zmienna jest ustawiona i nie ma wartości NULL

I interfejs coś takiego:

bool isset ( mixed $var [, mixed $... ] )

Ten parametr $varjest zmienną do sprawdzenia. może mieć jednak dowolną liczbę parametrów.

isset () zwraca, TRUEjeśli var istnieje i ma wartość inną niż NULL. FALSEInaczej.

Jakiś przykład:

$foo = 'bar';
var_dump(isset($foo));        -> true

$baz = null;
var_dump(isset($baz));        -> false

var_dump(isset($undefined));  -> false

Mając to na uwadze, Najwyraźniej nie jest możliwe napisanie dokładnego odpowiednika isset()funkcji php . Na przykład, gdy dzwonimy w ten sposób:

if (isset(some_var)) {

}

function issset() {
    // function definition
}

Spust JavaScript Uncaught ReferenceError: some_var is not defined at (file_name):line_number. Ważną i niezwykłą rzeczą w tym zachowaniu jest to, że podczas próby przekazania nieistniejących zmiennych do normalnych funkcji wywoływany jest błąd.

Ale w PHP isset()nie są tak naprawdę zwykłe funkcje, ale konstrukcje językowe. Oznacza to, że są częścią samego języka PHP, nie działają zgodnie z normalnymi regułami funkcji i dlatego mogą uniknąć błędu w przypadku nieistniejących zmiennych. Jest to ważne przy próbie ustalenia, czy zmienna istnieje, czy nie. Ale w javscript powoduje błąd, w pierwszej kolejności powiedz wywołanie funkcji z nieistniejącymi zmiennymi.

Chodzi mi o to, że nie możemy napisać tego jako równoważnej funkcji javscript, ale możemy zrobić coś takiego

if (typeof some_var !== 'undefined') {
   // your code here
}

Jeśli chcesz dokładnie ten sam efekt PHP również sprawdź zmienna nie jest NULL

Na przykład

$baz = null;
var_dump(isset($baz));        -> false

Możemy więc włączyć to do javascript, a następnie wygląda to tak:

if (typeof some_var !== 'undefined' && some_var !== null) {
   // your code here
}

0

javascript isset

let test = {
  a: {
    b: [0, 1]
  }
};

console.log(test.isset('a.b'))   // true
console.log(test.isset('a.b.1')) // true
console.log(test.isset('a.b.5')) // false
console.log(test.isset('a.c'))   // false
console.log('abv'.isset('0'))    // true

0

Uważaj w ES6 , wszystkie poprzednie rozwiązania nie działają, jeśli chcesz sprawdzić deklarację zmiennej let i zadeklarować ją, jeśli nie jest

przykład

let myTest = 'text';

if(typeof myTest === "undefined") {
    var myTest = 'new text'; // can't be a let because let declare in a scope
}

zobaczysz błąd

Uncaught SyntaxError: Identyfikator „myTest” został już zadeklarowany

Rozwiązaniem było zmienić to przez var

var myTest = 'text'; // I replace let by a var

if(typeof myTest === "undefined") {
    var myTest = 'new text';
}

innym rozwiązaniem, jeśli możesz zmienić let przez var, musisz usunąć swój var

let myTest = 'text';

if(typeof myTest === "undefined") {
    myTest = 'new text'; // I remove the var declaration
}

-1
    isset('user.permissions.saveProject', args);

    function isset(string, context) {
        try {
            var arr = string.split('.');
            var checkObj = context || window;

            for (var i in arr) {
                if (checkObj[arr[i]] === undefined) return false;
                checkObj = checkObj[arr[i]];
            }

            return true;
        } catch (e) {
            return false;
        }
    }
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.