Object.prototype.hasOwnProperty()
Z Javascript punktu widzenia wywiadu, to myślę, że wystarczy, aby w pełni zrozumieć, co obj.hasOwnProperty()
robi na poziomie JavaScript, a nie jak to jest realizowane wewnątrz V8.
Aby to zrobić, należy w pełni zrozumieć ten mały fragment:
function MyConstructor() {
this.methodB = function() {}
}
MyConstructor.prototype = {
methodA: function() {}
};
var o = new MyConstructor();
log(o.hasOwnProperty("methodA")); // false
log(o.hasOwnProperty("methodB")); // true
o.methodA = function() {}; // assign "own" property, overrides prototype
log(o.hasOwnProperty("methodA")); // true
To dlatego .hasOwnProperty()
wygląda tylko na samego obiektu, a nie na łańcuchu prototypów. Więc właściwości, które są tylko w łańcuchu prototypów lub w ogóle nie istnieją, zwrócą false
, a właściwości bezpośrednio na obiekcie zwrócą true
.
Array.prototype.map()
polyfill w JavaScript dla Array.prototype.map()
jest here on MDN który pokaże Ci dokładnie jak to działa. Możesz oczywiście zrobić to samo, co powyżej, w repozytorium Githuba, aby znaleźć implementację .map()
, jeśli chcesz.
Array.prototype.map()
jest naprawdę bardzo prosty. Iteruj po tablicy, wywołując funkcję dla każdego elementu w tablicy. Każda zwracana wartość tej funkcji zostanie użyta do skonstruowania nowej tablicy, która zostanie zwrócona z połączenia do .map()
. Więc, koncepcyjnie, jest używany do "mapowania" jednej tablicy do drugiej przez wywołanie funkcji transformacji na każdym elemencie oryginalnej tablicy.
W najprostszym wcieleniu dodać 1
do każdego elementu tablicy:
var origArray = [1,2,3];
var newArray = origArray.map(function(item, index, array) {
return item + 1;
});
console.log(newArray); // [2,3,4]
Rzeczywisty kod źródłowy V8:
Jeśli naprawdę chcesz zobaczyć, jak to jest realizowane wewnątrz V8, tutaj znajdują się fragmenty kodu i odnośniki do odpowiednich rzeczywistych plików kodu. Jak widać, większość z nich znajduje się w C++ i aby ją zrozumieć, musisz zrozumieć, jak obiekty są uporządkowane w pamięci i jakie metody C++ mają wewnętrznie w V8. Jest to bardzo specyficzna dla V8, a nie ogólna wiedza JavaScript.
Dołączyłem także linki do odpowiednich plików źródłowych, więc jeśli chcesz zobaczyć inny kontekst w tych plikach, możesz kliknąć linki, aby to zobaczyć.
W v8.h:
V8_DEPRECATED("Use maybe version", bool HasOwnProperty(Local<String> key));
V8_WARN_UNUSED_RESULT Maybe<bool> HasOwnProperty(Local<Context> context, Local<Name> key);
W api.cc:
Maybe<bool> v8::Object::HasOwnProperty(Local<Context> context,
Local<Name> key) {
PREPARE_FOR_EXECUTION_PRIMITIVE(context, "v8::Object::HasOwnProperty()",
bool);
auto self = Utils::OpenHandle(this);
auto key_val = Utils::OpenHandle(*key);
auto result = i::JSReceiver::HasOwnProperty(self, key_val);
has_pending_exception = result.IsNothing();
RETURN_ON_FAILED_EXECUTION_PRIMITIVE(bool);
return result;
}
bool v8::Object::HasOwnProperty(Local<String> key) {
auto context = ContextFromHeapObject(Utils::OpenHandle(this));
return HasOwnProperty(context, key).FromMaybe(false);
}
W v8natives.js:
// ES6 7.3.11
function ObjectHasOwnProperty(value) {
var name = TO_NAME(value);
var object = TO_OBJECT(this);
return %HasOwnProperty(object, name);
}
W objects-inl.h:
Maybe<bool> JSReceiver::HasOwnProperty(Handle<JSReceiver> object,
Handle<Name> name) {
if (object->IsJSObject()) { // Shortcut
LookupIterator it = LookupIterator::PropertyOrElement(
object->GetIsolate(), object, name, LookupIterator::HIDDEN);
return HasProperty(&it);
}
Maybe<PropertyAttributes> attributes =
JSReceiver::GetOwnPropertyAttributes(object, name);
MAYBE_RETURN(attributes, Nothing<bool>());
return Just(attributes.FromJust() != ABSENT);
}
W runtime-object.cc:
static Object* HasOwnPropertyImplementation(Isolate* isolate,
Handle<JSObject> object,
Handle<Name> key) {
Maybe<bool> maybe = JSReceiver::HasOwnProperty(object, key);
if (!maybe.IsJust()) return isolate->heap()->exception();
if (maybe.FromJust()) return isolate->heap()->true_value();
// Handle hidden prototypes. If there's a hidden prototype above this thing
// then we have to check it for properties, because they are supposed to
// look like they are on this object.
if (object->map()->has_hidden_prototype()) {
PrototypeIterator iter(isolate, object);
DCHECK(!iter.IsAtEnd());
// TODO(verwaest): The recursion is not necessary for keys that are array
// indices. Removing this.
// Casting to JSObject is fine because JSProxies are never used as
// hidden prototypes.
return HasOwnPropertyImplementation(
isolate, PrototypeIterator::GetCurrent<JSObject>(iter), key);
}
RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
return isolate->heap()->false_value();
}
RUNTIME_FUNCTION(Runtime_HasOwnProperty) {
HandleScope scope(isolate);
DCHECK(args.length() == 2);
CONVERT_ARG_HANDLE_CHECKED(Object, object, 0)
CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
uint32_t index;
const bool key_is_array_index = key->AsArrayIndex(&index);
// Only JS objects can have properties.
if (object->IsJSObject()) {
Handle<JSObject> js_obj = Handle<JSObject>::cast(object);
// Fast case: either the key is a real named property or it is not
// an array index and there are no interceptors or hidden
// prototypes.
// TODO(jkummerow): Make JSReceiver::HasOwnProperty fast enough to
// handle all cases directly (without this custom fast path).
Maybe<bool> maybe = Nothing<bool>();
if (key_is_array_index) {
LookupIterator it(js_obj->GetIsolate(), js_obj, index,
LookupIterator::HIDDEN);
maybe = JSReceiver::HasProperty(&it);
} else {
maybe = JSObject::HasRealNamedProperty(js_obj, key);
}
if (!maybe.IsJust()) return isolate->heap()->exception();
DCHECK(!isolate->has_pending_exception());
if (maybe.FromJust()) {
return isolate->heap()->true_value();
}
Map* map = js_obj->map();
if (!key_is_array_index && !map->has_named_interceptor() &&
!map->has_hidden_prototype()) {
return isolate->heap()->false_value();
}
// Slow case.
return HasOwnPropertyImplementation(isolate, Handle<JSObject>(js_obj),
Handle<Name>(key));
} else if (object->IsString() && key_is_array_index) {
// Well, there is one exception: Handle [] on strings.
Handle<String> string = Handle<String>::cast(object);
if (index < static_cast<uint32_t>(string->length())) {
return isolate->heap()->true_value();
}
} else if (object->IsJSProxy()) {
Maybe<bool> result =
JSReceiver::HasOwnProperty(Handle<JSProxy>::cast(object), key);
if (!result.IsJust()) return isolate->heap()->exception();
return isolate->heap()->ToBoolean(result.FromJust());
}
return isolate->heap()->false_value();
}
To node.js Github repository. Jeśli wiesz, czego szukać i masz dość cierpliwości, by przebić się przez wszystkie trafienia wyszukiwania, możesz zazwyczaj znaleźć wszystko, czego potrzebujesz. Niefortunną rzeczą przy wyszukiwaniu w Githubie jest to, że nie znalazłem żadnego sposobu na usunięcie wszystkich podkatalogów testowych z wyszukiwania, więc skończysz z 95% wyników wyszukiwania w kodzie testowym, a nie w samym kodzie implementacji. Ale z wystarczającą wytrwałością możesz w końcu znaleźć to, czego potrzebujesz.
Czy to nie jest zabawne, że musisz badać bezużyteczne śmieci, których NIGDY nie potrzebujesz w praktyce, aby móc przeprowadzić wywiad? – Hill
Zobacz także [Jak wyświetlić źródło wbudowanych funkcji javascript?] (Https://stackoverflow.com/q/22300206/1048572) – Bergi