myObj.hasOwnProperty (prop) 대신 Object.prototype.hasOwnProperty.call (myObj, prop)을 사용하는 이유는 무엇입니까?


104

내가 올바르게 이해한다면 Javascript의 모든 객체는 Object 프로토 타입에서 상속됩니다. 즉, Javascript의 모든 객체는 프로토 타입 체인을 통해 hasOwnProperty 함수에 액세스 할 수 있습니다.

require.js의 소스 코드를 읽는 동안이 함수를 발견했습니다.

function hasProp(obj, prop) {
    return hasOwn.call(obj, prop);
}

hasOwn에 대한 참조 Object.prototype.hasOwnProperty입니다. 이 함수를 작성하는 데 실질적인 차이가 있습니까?

function hasProp(obj, prop) {
    return obj.hasOwnProperty(prop);
}

그리고 우리가 그것을하고 있기 때문에 우리는 왜이 함수를 정의해야합니까? (약간의) 성능 향상을 위해 바로 가기 및 속성 액세스의 로컬 캐싱에 대한 질문입니까, 아니면이 메서드가없는 개체에 hasOwnProperty를 사용할 수있는 경우를 놓치고 있습니까?

답변:


109

[제 예간에] 실질적인 차이가 있습니까?

사용자는으로 생성 된 JavaScript 객체를 가지고있을 수 있습니다.이 객체 Object.create(null)에는 null [[Prototype]]체인이 있으므로 hasOwnProperty()사용할 수 없습니다 . 이러한 이유로 두 번째 양식을 사용하면 작동하지 않습니다.

또한 더 안전한 참조입니다 Object.prototype.hasOwnProperty()(또한 더 짧습니다).

누군가가 한 일을 상상할 수 있습니다 ...

var someObject = {
    hasOwnProperty: function(lol) {
        return true;
    }
};

hasProp(someObject)두 번째 예제와 같이 구현 된 경우 실패 할 수 있습니다 (객체에서 해당 메서드를 직접 찾아서 위임하는 대신 호출합니다 Object.prototype.hasOwnProperty).

그러나 누군가가 Object.prototype.hasOwnProperty참조를 무시할 가능성은 적습니다 .

그리고 우리가 그것을하고 있기 때문에 우리는 왜이 함수를 정의해야합니까?

위 참조.

(약간) 성능 향상을 위해 속성 액세스의 바로 가기 및 로컬 캐싱 문제 일 뿐입니 까?

체인을 따를 필요가 없기 때문에 이론적으로 더 빨리 만들 수 [[Prototype]]있지만 구현이 그 이유가 아니라 무시할 수 있다고 생각합니다 .

... 또는 hasOwnProperty이 방법이없는 객체에 사용될 수있는 경우가 누락 되었습니까?

hasOwnProperty()에 존재 Object.prototype하지만 재정의 할 수 있습니다. 모든 네이티브 JavaScript 객체 (호스트 객체가이를 따르지 않을 수 있음 , RobG의 심층 설명 참조 )는 Object.prototype이전에 체인에서 마지막 객체로 사용됩니다 null(물론에서 반환 된 객체 제외 Object.create(null)).


당신의 논리는 아마 정확하지만 당신이 친절하다고 생각합니다. require.js의 작성자가 hasOwnProperty 가 재정의되었을 수 있다고 생각하는 경우 (극히 드뭅니다), 모든 내장 메서드를 그런 방식으로 호출해야합니다 (아마도 그렇습니다).
RobG

@Periback 정말? 나는 그것이 그것을 지원한다고 확신했습니다.
alex

자주 사용하는 경우 ES6 단축키. const hasProp = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop)
Richard Ayotte 2017

15

내가 올바르게 이해하면 Javascript의 모든 객체는 Object 프로토 타입에서 상속됩니다.

머리카락을 쪼개는 것처럼 보일 수 있지만 javascript (ECMAScript 구현의 일반 용어)와 ECMAScript (JavaScript 구현에 사용되는 언어 ) 간에 차이가 있습니다. 자바 스크립트가 아닌 상속 체계를 정의하는 것은 ECMAScript이므로 네이티브 ECMAScript 개체 만 해당 상속 체계를 구현하면됩니다.

실행중인 자바 스크립트 프로그램은 최소한 내장 된 ECMAScript 객체 (Object, Function, Number 등)와 일부 네이티브 객체 (예 : 함수)로 구성됩니다. 또한 일부 호스트 개체 (예 : 브라우저의 DOM 개체 또는 다른 호스트 환경의 다른 개체)가있을 수 있습니다.

내장 및 네이티브 객체는 ECMA-262에 정의 된 상속 체계를 구현해야하지만 호스트 객체는 그렇지 않습니다. 따라서 자바 스크립트 환경의 모든 개체가 Object.prototype 에서 상속 되어야 하는 것은 아닙니다 . 예를 들어, ActiveX 개체로 구현 된 IE의 호스트 개체는 네이티브 개체로 취급되면 오류를 발생시킵니다 (따라서 try..catch가 MS XMLHttpRequest 개체를 초기화하는 데 사용되는 이유). 일부 DOM 개체 (예 : 쿼크 모드의 IE의 NodeLists)는 Array 메서드에 전달되면 오류가 발생하고 IE 8 이하의 DOM 개체에는 ECMAScript와 같은 상속 체계가없는 등의 문제가 발생합니다.

따라서 자바 스크립트 환경의 모든 객체가 Object.prototype에서 상속한다고 가정해서는 안됩니다.

즉, Javascript의 모든 객체는 프로토 타입 체인을 통해 hasOwnProperty 함수에 액세스 할 수 있습니다.

최소한 쿼크 모드 (및 IE 8 이하에서는 항상)의 IE의 특정 호스트 개체에는 해당되지 않습니다.

위의 내용을 감안할 때 객체에 자체 hasOwnProperty 메서드 가있는 이유와 그것이 좋은 생각인지 아닌지 먼저 테스트하지 않고 대신 다른 hasOwnProperty 메서드 를 호출 하는 것이 좋습니다.

편집하다

사용하는 이유 Object.prototype.hasOwnProperty.call는 일부 브라우저에서 호스트 개체에 hasOwnProperty 메서드 가없고 call 을 사용하고 기본 제공 메서드가 대안이라는 것입니다. 그러나 일반적으로 그렇게하는 것은 위에서 언급 한 이유 때문에 좋은 생각이 아닌 것 같습니다.

호스트 개체와 관련하여 in 연산자를 사용하여 일반적으로 속성을 테스트 할 수 있습니다.

var o = document.getElementsByTagName('foo');

// false in most browsers, throws an error in IE 6, and probably 7 and 8
o.hasOwnProperty('bar');

// false in all browsers
('bar' in o);

// false (in all browsers? Do some throw errors?)
Object.prototype.hasOwnProperty.call(o, 'bar');

대안 (IE6 및 기타에서 테스트 됨) :

function ownProp(o, prop) {

  if ('hasOwnProperty' in o) {
    return o.hasOwnProperty(prop);

  } else {
    return Object.prototype.hasOwnProperty.call(o, prop);
  }
}

이렇게 하면 객체에 상속 또는 기타 항목이없는 내장 hasOwnProperty 만 구체적으로 호출 됩니다.

그러나 객체에 hasOwnProperty메서드 가없는 경우 객체 에 상속 체계가없고 모든 속성이 객체에있을 가능성이 높기 때문에 in 연산자 를 사용하는 것이 적절할 것입니다 (단지 가정 일뿐입니다). in 연산자는 속성에 대한 DOM 개체 지원을 테스트하는 일반적인 (그리고 성공적으로 보이는) 방법입니다.


감사. Object.prototype.hasOwnProperty.call (o, 'bar')는 FF 18.0에서 작동하지 않습니다 (적어도 제 경우에는). 그래서 저는 (o의 'bar')를 사용하기로 결정했습니다.
Max

@Max inhasOwnProperty()조회를 수행하지 않습니다. 찾고 있던 속성이 프로토 타입 체인에 존재한다고 생각합니다.
alex

이것은 eslint.org/docs/rules/no-prototype-builtins 의 흥미로운 예입니다 . 예를 들어, 웹 서버가 클라이언트의 JSON 입력을 구문 분석 hasOwnProperty하고 결과 객체를 직접 호출하는 것은 안전하지 않습니다. JSON 값을 보내면 {"hasOwnProperty": 1}서버가 충돌합니다.
naught101

물론입니다.하지만 문제가 데이터 품질에 불과하더라도 이러한 문제를 방지하기 위해 JSON 스키마를 사용하여 클라이언트 제공 JSON을 테스트하거나 유효성을 검사하는 것이 좋습니다. 그리고 서버가 충돌하지 않아야합니다. :-)
RobG

8

JavaScript는 속성 이름 hasOwnProperty를 보호하지 않습니다.

객체에이 이름의 속성이있을 가능성이있는 경우 올바른 결과를 얻으려면 외부 hasOwnProperty를 사용해야합니다.

더 나은 이해를 위해 아래 코드 스 니펫을 브라우저 콘솔에 복사하여 붙여 넣을 수 있습니다.

var foo = {
  hasOwnProperty: function() {
    return false;
  },
  bar: 'I belong to foo'
};

항상 false를 반환합니다.

foo.hasOwnProperty('bar'); // false

다른 Object의 hasOwnProperty를 사용하고 이것을 foo로 설정하여 호출하십시오.

({}).hasOwnProperty.call(foo, 'bar'); // true

이러한 목적으로 Object 프로토 타입 의 hasOwnProperty 속성을 사용할 수도 있습니다.

Object.prototype.hasOwnProperty.call(foo, 'bar'); // true

1
당신이 만들고있는 요점은 이미 받아 들여진 대답 에서 만들어 졌지만 , hasOwnProperty반환 의 무시 가 true있습니다.
Louis

1

기존의 두 답변에 제공된 정보는 정확합니다. 그러나 다음을 사용합니다.

('propertyName' in obj)

몇 번 언급됩니다. 주목해야한다 hasOwnProperty속성이 직접 개체가 테스트되고에 포함 된 경우에만 구현이 true를 돌려줍니다.

in운영자는 너무 프로토 타입 체인을 통해 아래로 검사 할 것입니다.

hasOwnProperty, 프로토 타입 속성이 false를 반환 하는 위치로 전달되면 인스턴스 속성이 true를 반환합니다 .

in인스턴스 및 프로토 타입 속성 모두 연산자를 사용하면 true가 반환됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.