this, This and this
How To Wrap A Native Object
May 30th, 2014
Lu Yuan
The meaning of title
1. this
In JavaScript
what is "this" ?
CONTEXT
RUNTIME
DYNAMIC
The meaning of title
2. This
In V8 API
v8::Arguments::This()
v8::AccessorInfo::This()
Represent "this" in JavaScript
The meaning of title
3. this
In native
This object
The wrapped objects we met
In web browser:
DOM Elements
BOM Elements
Plugins
In Node.js:
Objects in native modules
Native extensions
A Compatibility Issue
SD9005: IE 中一个对象的 native 方法是跟该对象绑定的
<!DOCTYPE html> <html> <head> </head> <body> <div id="d1">Div Element</div> <script type="text/javascript"> var $1 = function(id){return document.getElementById(id);}; var $2 = document.getElementById; alert($1('d1')); alert($2('d1')); </script> </body> </html>
TypeError: undefined is not a function
丢失的 this 引用
————周爱民
document.getElementById = (function(fn){ return function(){ return fn.apply(document, arguments); }; })(document.getElementById); var $2 = document.getElementById;
Why?
"document" object is wrapped in non-IE browsers.
How to wrap it?
KEYWORDS:
SetAlignedPointerInInternalField
void v8::Object::SetAlignedPointerInInternalField(int index, void* value)
GetAlignedPointerInInternalField
v8::Object::V8_INLINE(void * GetAlignedPointerFromInternalField(int index))
A Wrapper
node_object_wrap.h
class NODE_EXTERN ObjectWrap {
public:
ObjectWrap ( ) {
refs_ = 0;
}
virtual ~ObjectWrap ( ) {
if (!handle_.IsEmpty()) {
assert(handle_.IsNearDeath());
handle_.ClearWeak();
handle_->SetPointerInInternalField(0, 0);
handle_.Dispose();
handle_.Clear();
}
}
template
static inline T* Unwrap (v8::Handle<:object> handle) {
assert(!handle.IsEmpty());
assert(handle->InternalFieldCount() > 0);
return static_cast(handle->GetPointerFromInternalField(0));
}
v8::Persistent<:object> handle_; // ro
protected:
inline void Wrap (v8::Handle<:object> handle) {
assert(handle_.IsEmpty());
assert(handle->InternalFieldCount() > 0);
handle_ = v8::Persistent<:object>::New(handle);
handle_->SetPointerInInternalField(0, this);
MakeWeak();
}
inline void MakeWeak (void) {
handle_.MakeWeak(this, WeakCallback);
handle_.MarkIndependent();
}
/* Ref() marks the object as being attached to an event loop.
* Refed objects will not be garbage collected, even if
* all references are lost.
*/
virtual void Ref() {
assert(!handle_.IsEmpty());
refs_++;
handle_.ClearWeak();
}
/* Unref() marks an object as detached from the event loop. This is its
* default state. When an object with a "weak" reference changes from
* attached to detached state it will be freed. Be careful not to access
* the object after making this call as it might be gone!
* (A "weak reference" means an object that only has a
* persistant handle.)
*
* DO NOT CALL THIS FROM DESTRUCTOR
*/
virtual void Unref() {
assert(!handle_.IsEmpty());
assert(!handle_.IsWeak());
assert(refs_ > 0);
if (--refs_ == 0) { MakeWeak(); }
}
int refs_; // ro
private:
static void WeakCallback (v8::Persistent<:value> value, void *data) {
v8::HandleScope scope;
ObjectWrap *obj = static_cast(data);
assert(value == obj->handle_);
assert(!obj->refs_);
assert(value.IsNearDeath());
delete obj;
}
};
A Demo
this.cc
#include <node.h>
#include <v8.h>
#include <string>
using namespace v8;
class This : public node::ObjectWrap {
public:
This() : node::ObjectWrap(), str_("This is a test.") {}
~This() {}
static Handle New(const Arguments& args) {
HandleScope scope;
This* _this_ = new This;
_this_->Wrap(args.This());
return Undefined();
}
static Handle Test(const Arguments& args) {
HandleScope scope;
This* _this_ = node::ObjectWrap::Unwrap(args.This());
if (!_this_) {
return ThrowException(Exception::TypeError(String::New("Illegal invocation")));
}
return scope.Close(String::New(_this_->Test().c_str()));
}
private:
std::string Test() {
return str_;
}
std::string str_;
};
void init(Handle
A Demo
Edit binding.gyp script
{
"targets": [
{
"target_name": "this",
"sources": [ "this.cc" ]
}
]
}
Compile with node-gyp
$ node-gyp configure
$ node-gyp build
Test
$ node
> var t = require('./build/Release/this');
> t.ThisInstance.test(); // "This is a test."
Reproduce the issue
$ node
> var t = require('./build/Release/this');
> var a = t.ThisInstance.test;
> a();
"this" in C++ native is a null pointer.
Thanks
this, This and this
By luyuan
this, This and this
this, This and this - How to wrap a native object
- 1,283