Node.js是一个强大的平台,理想状态下一切都都可以用javascript写成。然而,你可能还会用到许多遗留的库和系统,这样的话使用c++编写Node.JS扩展会是一个不错的注意。
以下所有例子的源代码可在node扩展示例中找到 。
编写Node.js C + +扩展很大程度上就像是写V8的扩展; Node.js增加了一些接口,但大部分时间你都是在使原始的V8数据类型和方法,为了理解以下的代码,你必须首先阅读V8引擎嵌入指南。
Javascript版本的Hello World
在讲解C++版本的例子之前,先让我们来看看在Node.js中用Javascript编写的等价模块是什么样子。这是一个最简单的Hello World,也不是通过HTTP,但它展示了node模块的结构,而其接口也和大多数C++扩展要提供的接口差不多:
HelloWorldJs = function() {
this.m_count = 0
}
HelloWorldJs.prototype.hello = function()
{
this.m_count++
return “Hello World”
}
exports.HelloWorldJs = HelloWorldJs
正如你所看到的,它使用prototype为HelloWorldJs类创建了一个新的方法。请注意,上述代码通过将HelloWorldJS添加到exports变量来暴露构造函数。
要在其他地方使用该模块,请使用如下代码:
var helloworld = require(‘helloworld_js’)
var hi = new helloworld.HelloWorldJs()
console.log(hi.hello())// prints “Hello World” to stdout
C++版本的Hello World
要开始编写C++扩展,首先要能够编译Node.js(请注意,我们使用的是Node.js 2.0版本)。本文所讲内容应该兼容所有未来的0.2.x版本。一旦编译安装完node,编译模块就不在需要额外的东西了。
完整的源代码可以在这里找到 。在使用Node.js或V8之前,我们需要包括相关的头文件:
#include <v8.h>
#include <node.h>
using namespace node
using namespace v8
在本例子中我直接使用了V8和node的命名空间,使代码更易于阅读。虽然这种用法和谷歌的自己的C++编程风格指南相悖,但由于你需要不停的使用V8定义的类型,所以目前为止的大多数node的扩展仍然使用了V8的命名空间。
接下来,声明HelloWorld类。它继承自node::ObjectWrap类 ,这个类提供了几个如引用计数、在V8内部传递contex等的实用功能。一般来说,所有对象应该继承ObjectWrap:
class HelloWorld: ObjectWrap
{
private:
int m_count
public:
声明类之后,我们定义了一个静态成员函数,用来初始化对象并将其导入Node.js提供的target对象中。设个函数基本上是告诉Node.js和V8你的类是如何创建的,和它将包含什么方法:
static Persistent<FunctionTemplate>s_ct
static void Init(Handle<Object>target)
{
HandleScope scope
Local<FunctionTemplate>t = FunctionTemplate::New(New)
s_ct = Persistent<FunctionTemplate>::New(t)
s_ct->InstanceTemplate()->SetInternalFieldCount(1)
s_ct->SetClassName(String::NewSymbol(“HelloWorld”))
NODE_SET_PROTOTYPE_METHOD(s_ct, “hello”, Hello)
target->Set(String::NewSymbol(“HelloWorld”),
s_ct->GetFunction())
}
在上面这个函数中target参数将是模块对象,即你的扩展将要载入的地方。(译著:这个函数将你的对象及其方法连接到
这个模块对象,以便外界可以访问)首先我们为New方法创建一个FunctionTemplate,将于稍后解释。我们还为该对象添加一个内部字段,并命
名为HelloWorld。然后使用NODE_SET_PROTOTYPE_METHOD宏将hello方法绑定到该对象。最后,一旦我们建立好这个函数模板后,将他分配给target对象的HelloWorld属性,将类暴露给用户。
接下来的部分是一个标准的C++构造函数:
HelloWorld() :
m_count(0)
{
}
~HelloWorld()
{
}
接下来,在::New 方法中V8引擎将调用这个简单的C++构造函数:
static Handle<Value>New(const Arguments&args)
{
HandleScope scope
HelloWorld* hw = new HelloWorld()
hw->Wrap(args.This())
return args.This()
}
此段代码相当于上面Javascript代码中使用的构造函数。它调用new HelloWorld
创造了一个普通的C++对象,然后调用从ObjectWrap继承的Wrap方法,
它将一个C++HelloWorld类的引用保存到args.This()的值中。在包装完成后返回args.This(),整个函数的行为和
javascript中的new运算符类似,返回this指向的对象。
现在我们已经建立了对象,下面介绍在Init函数中被绑定到hello的函数:
static Handle<Value>Hello(const Arguments&args)
window.location 对象
window.location 对象用于获得当前页面的地址 (URL),并把浏览器重定向到新的页面。window.location 对象在编写时可不使用 window 这个前缀。
location.hostname 返回 web 主机的域名
location.pathname 返回当前页面的路径和文件名
location.port 返回 web 主机的端口 (80 或 443)
location.protocol 返回所使用的 web 协议(http:// 或 https://)
window.location.href= "http://www.xxxxxxxx.net" 跳转后有后退功能
window.location.replace("http://www.xxxxxxxx.net") 跳转后没有后退功能
window.open("http://www.xxxxxxxx.net") 在新的窗口打开链接,一般用于简单的弹出页面,现在基本上都被屏蔽掉
window.location.reload( )刷新当前页面.
parent.location.reload( )刷新父亲对象(用于框架)
opener.location.reload( )刷新父窗口对象(用于单开窗口)
top.location.reload( )刷新最顶端对象(用于多开窗口)
window.history 对象
window.history 对象包含浏览器的历史。window.history对象在编写时可不使用 window 这个前缀。
window.history.back() - 加载历史列表中的前一个 URL,与在浏览器点击后退按钮相同,
window.history.forward() -加载历史列表中的下一个 URL。 与在浏览器中点击按钮向前相同
window.navigator 对象
window.navigator 对象包含有关访问者浏览器的信息,来自 navigator 对象的信息具有误导性,不应该被用于检测浏览器版本,这是因为:
navigator 数据可被浏览器使用者更改
一些浏览器对测试站点会识别错误
浏览器无法报告晚于浏览器发布的新操作系统
window.navigator 对象在编写时可不使用 window 这个前缀。
window.navigator.appCodeName返回浏览器的代码名。
window.navigator.appName返回代表浏览器名的字符串。
window.navigator.appMinorVersion返回浏览器的次版本号。该属性是一个只读的字符串。仅IE有效。
window.navigator.userAgent返回代表浏览器名和版本号的字符串。
window.navigator.platform返回浏览器平台的字符串("Win32", "Win16", "WinCE", "Mac68k", "MacPPC", "HP-UX", "SunOS" 等)。
window.navigator.cpuClass 返回CPU的信息("x86", "68K", "Alpha", "PPC" 等)。仅IE有效。
window.navigator.browserLanguage返回浏览器的语言种类。仅IE有效。
window.navigator.systemLanguage返回系统的语言种类。仅IE有效。
window.navigator.userLanguage userLanguage 返回用户环境的语言种类。仅IE有效。
window.navigator.cookieEnabled返回 cookie 是否可用的真伪值。
window.navigator.onLine返回是否能连上网络的真伪值。
window.navigator.javaEnabled()返回 Java 是否可用的真伪值。
window.navigator.userProfile保存着用户信息的对象。拥有 addReadRequest() doReadRequest() getAttribute() clearRequest() 等方法。
window.navigator.taintEnabled() 是否可以加密数据的真伪值。仅IE有效。
window对象的一些其它方法
setInterval() 和 setTimeout() 是 HTML DOM Window对象的两个方法。
window.setInterval() - 间隔指定的毫秒数不停地执行指定的代码。
window.setTimeout() - 暂停指定的毫秒数后执行指定的代码
window.clearInterval() 方法用于停止 setInterval() 方法执行的函数代码。
window.clearTimeout() 方法用于停止执行setTimeout()方法的函数代码。
window.alert()- 警告框经常用于确保用户可以得到某些信息。当警告框出现后,用户需要点击确定按钮才能继续进行操作。
window.prompt()- 确认框用于使用户可以验证或者接受某些信息。当确认框出现后,用户需要点击确定或者取消按钮才能继续进行操作。如果用户点击确认,那么返回值为 true。如果用户点击取消,那么返回值为 false。
window.confirm()- 提示框经常用于提示用户在进入页面前输入某个值。当提示框出现后,用户需要输入某个值,然后点击确认或取消按钮才能继续操纵。如果用户点击确认,那么返回值为输入的值。如果用户点击取消,那么返回值为 null。
window.open() - 打开新窗口
window.close() - 关闭当前窗口
window.moveTo() - 移动当前窗口
window.resizeTo() - 调整当前窗口的尺寸
window.frameElement 获取当前文档的宿主节点iframe元素
window.execScript() execScript函数与eval的功能相同,不同的是eval函数执行后的脚本的作用域是当前执行上下文,而execScript则总是针对全局作用域。