最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Where can I see the source code for JavaScript methods, such as hasOwnProperty, in Node.js? - Stack Overflow

programmeradmin1浏览0评论

I have been studying JavaScript algorithms and Big O for interviews. I was told that knowing the runtimes of built-in methods, such as Object.prototype.hasOwnProperty and Array.prototype.map, is important.

What is a simple way to view the source code for these functions in node.js? I have a local copy of node.js, and I tried to search for these methods in my text editor, but it's not as straightforward as I thought.

I have been studying JavaScript algorithms and Big O for interviews. I was told that knowing the runtimes of built-in methods, such as Object.prototype.hasOwnProperty and Array.prototype.map, is important.

What is a simple way to view the source code for these functions in node.js? I have a local copy of node.js, and I tried to search for these methods in my text editor, but it's not as straightforward as I thought.

Share Improve this question edited May 6, 2016 at 17:40 Kara 6,22616 gold badges53 silver badges58 bronze badges asked May 5, 2016 at 20:29 davidattheparkdavidatthepark 1,3651 gold badge13 silver badges28 bronze badges 2
  • 6 Isn't it fun that you have to study useless garbage you would NEVER need in practice to be able to pass an interview? – Christine Commented Feb 11, 2017 at 0:12
  • 1 See also How to see the source of Built-in javascript functions? – Bergi Commented May 23, 2017 at 10:16
Add a comment  | 

1 Answer 1

Reset to default 32

Object.prototype.hasOwnProperty()

From a Javascript interview point of view, I would think you just need to fully understand what obj.hasOwnProperty() does at the Javascript level, not how it's implemented inside of V8.

To do that, you should fully understand this little snippet:

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

This is because .hasOwnProperty() looks only on the object itself and not on the prototype chain. So properties which are only on the prototype chain or do not exist at all will return false and properties which are directly on the object will return true.


Array.prototype.map()

A polyfill in Javascript for Array.prototype.map() is here on MDN which will show you exactly how it works. You can, of course, do the same type of search I did above in the Github repository to find the .map() implementation too if you want.

Array.prototype.map() is pretty simple really. Iterate over an array, calling a function for each item in the array. Each return value of that function will be used to construct a new array that will be returned from the call to .map(). So, conceptually, it's used to "map" one array to another by calling some transform function on each element of the original array.

In the simplest incarnation, you add 1 to each element of an array:

var origArray = [1,2,3];

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

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

Actual V8 source code:

If you really want to see how it is implemented inside of V8, here are code snippets and links to the relevant actual code files. As you can see, most of it is in C++ and to understand it, you have to understand how objects are structured in memory and what C++ methods they have internally in V8. This is very V8-specific, not general Javascript knowledge.

I've included links to the relevant source files too so if you want to see other context in those files, you can click on the links to see that.

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

This is the node.js Github repository. If you know what to search for and have enough patience to wade through all the search hits, you can generally find anything you need. The unfortunate thing about searching on Github is I have not found any way to remove all the test sub-directories from the search so you end up with 95% of the search hits in the test code, not in the actual implementation code. But, with enough persistence, you can eventually find what you need.

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论