2016-05-05 20 views
7

Ho studiato algoritmi JavaScript e Big O per interviste. Mi è stato detto che conoscere i tempi di esecuzione dei metodi incorporati, come ad esempio Object.prototype.hasOwnProperty e Array.prototype.map, è importante.Dove posso vedere il codice sorgente per i metodi JavaScript, come hasOwnProperty, in Node.js?

Che cosa è un modo semplice per visualizzare il codice sorgente per queste funzioni in node.js? Ho una copia locale di node.js e ho provato a cercare questi metodi nel mio editor di testo, ma non è così semplice come pensavo.

+1

Non è divertente che tu debba studiare inutili rifiuti che non avresti MAI bisogno in pratica di poter passare un colloquio? – Hill

+0

Vedere anche [Come vedere la fonte delle funzioni javascript integrate?] (Https://stackoverflow.com/q/22300206/1048572) – Bergi

risposta

10

Object.prototype.hasOwnProperty()

Da un punto di vista intervista Javascript, vorrei pensare che solo bisogno di comprendere appieno ciò che obj.hasOwnProperty() fa a livello di Javascript, non come è implementato all'interno di V8.

Per fare questo, è necessario comprendere pienamente questo piccolo frammento:

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 

Questo perché .hasOwnProperty() guarda solo sull'oggetto stesso e non sulla catena di prototipi. Quindi le proprietà che si trovano solo sulla catena del prototipo o che non esistono affatto restituiranno false e le proprietà direttamente sull'oggetto restituiranno true.


Array.prototype.map()

Un ovatta in Javascript per Array.prototype.map() è here on MDN che vi mostrerà esattamente come funziona. Naturalmente, puoi anche fare lo stesso tipo di ricerca che ho fatto sopra nel repository Github per trovare l'implementazione .map(), se lo desideri.

Array.prototype.map() è davvero semplice. Iterare su un array, chiamando una funzione per ogni elemento nell'array. Ogni valore restituito di tale funzione verrà utilizzato per costruire un nuovo array che verrà restituito dalla chiamata a .map(). Quindi, concettualmente, è usato per "mappare" un array ad un altro chiamando una funzione di trasformazione su ogni elemento dell'array originale.

Nell'incarnazione più semplice, si aggiunge 1 ad ogni elemento di un array:

var origArray = [1,2,3]; 

var newArray = origArray.map(function(item, index, array) { 
    return item + 1; 
}); 

console.log(newArray); // [2,3,4] 

effettivo codice sorgente V8:

Se si vuole veramente vedere come viene implementato all'interno di V8, qui ci sono snippet di codice e collegamenti ai file di codice attuali rilevanti. Come puoi vedere, la maggior parte è in C++ e per capirlo, devi capire come gli oggetti sono strutturati in memoria e quali sono i metodi C++ che hanno internamente in V8. Questa è una conoscenza di Javascript molto specifica V8, non generale.

Ho incluso anche i collegamenti ai file sorgente rilevanti, quindi se vuoi vedere altro contesto in questi file, puoi fare clic sui collegamenti per vederlo.

In 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); 

In 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); 
} 

In v8natives.js:

// ES6 7.3.11 
function ObjectHasOwnProperty(value) { 
    var name = TO_NAME(value); 
    var object = TO_OBJECT(this); 
    return %HasOwnProperty(object, name); 
} 

In 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); 
} 

In 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(); 
} 

Questa è la node.js Github repository. Se sai cosa cercare e hai abbastanza pazienza per guadare tutti i risultati di ricerca, puoi generalmente trovare tutto ciò di cui hai bisogno. La cosa sfortunata della ricerca su Github è che non ho trovato alcun modo per rimuovere tutte le sottodirectory di test dalla ricerca in modo da ottenere il 95% dei risultati di ricerca nel codice di test, non nel codice di implementazione effettivo. Ma, con sufficiente persistenza, puoi finalmente trovare ciò di cui hai bisogno.

+0

Ricerca utile. Grazie per i link. – TGrif

+0

Aggiunti snippet di codice effettivi da V8 alla risposta. – jfriend00

+0

Questo dovrebbe essere contrassegnato come la risposta "giusta". Al di là e al di là ... –

Problemi correlati