Javascript里有个C:Part 3 - 深入对象

2023-11-11

http://cnodejs.org/topic/4f16442ccae1f4aa270010bd

<em>Javascript里有个C </em>系列文章:<br/><ol><br/> <li><a title=“编辑“Javascript里有个C:Part 1 – 基础”” href=“http://cnodejs.org/blog/?p=1621”>Javascript里有个C:Part 1 – 基础</a></li><br/> <li><a href=“http://cnodejs.org/blog/?p=1804”>Javascript里有个C:Part 2 – 对象</a></li><br/> <li><a href=“http://cnodejs.org/blog/?p=1833”>Javascript里有个C:Part 3 - 深入对象</a></li><br/> <li>Javascript里有个C:Part 4 - 异步</li><br/> <li>Javascript里有个C:Part 5 - node.js</li><br/> <li>Javascript里有个C:Part 6 - 实战node.js Module</li><br/></ol><br/>书至第三回。前两回当啷结束,C++里怎么摆弄Javascript,相信大家已略有所知。在本文,我们将更进一步。怎么从上帝视角玩弄Javascript?怎么把C++强力插入Javascript?这里都将一一解惑。<br/><h4>External</h4><br/>首先我们需要了解一种特殊的Value,v8::External,它的作用是把C++的对象包装成Javascript中的变量。External::New接受一个C++对象的指针作为初始化参数,然后返回一个包含这个指针的Handle<External>对象供v8引擎使用。在使用这个Handle<External>对象时可以通过External::Value函数来得到C++对象的指针,接口定义如下:<br/><pre escaped=“true” lang=“c” class=“brush: c;”>/**<br/> * A JavaScript value that wraps a C++ void*. This type of value is<br/> * mainly used to associate C++ data structures with JavaScript<br/> * objects.<br/> *<br/> * The Wrap function V8 will return the most optimal Value object wrapping the<br/> * C++ void*. The type of the value is not guaranteed to be an External object<br/> * and no assumptions about its type should be made. To access the wrapped<br/> * value Unwrap should be used, all other operations on that object will lead<br/> * to unpredictable results.<br/> /<br/>class External : public Value {<br/>public:<br/> V8EXPORT static Local<Value> Wrap(void data);<br/> static inline void* Unwrap(Handle<Value> obj);<br/><br/> V8EXPORT static Local<External> New(void* value);<br/> static inline External* Cast(Value* obj);<br/> V8EXPORT void* Value() const;<br/> private:<br/> V8EXPORT External();<br/> V8EXPORT static void CheckCast(v8::Value* obj);<br/> static inline void* QuickUnwrap(Handlev8::Value obj);<br/> V8EXPORT static void* FullUnwrap(Handlev8::Value obj);<br/>};</pre><br/>需要注意的是,External::Wrap会尝试把指针作为数值进行处理,若不支持则等同于New。<br/><br/>和Handle不同,External并不会托管C++对象的生命期,所以你必须手动构造、释放用来包装的C++对象。比较常用的手段是,在C++的栈上建立对象,然后再用External进行托管。下面是一个例子[<a href=“https://github.com/zcbenz/there-is-a-c-in-javascript/blob/master/external.cc” target="_blank">完整代码</a>]:<br/><pre escaped=“true” lang=“c” class=“brush: c;”> std::string str (“Hello World!”);<br/> Local<External> external = External::New (&str);<br/> cout << static_caststd::string* (external->Value());</pre><br/><h4>Template</h4><br/>怎么把Javascript的对象和C++的对象联系起来?v8::Object并未提供从C++对象构造的方法,而Javascript的函数v8::Function甚至没有提供初始化::New函数!这就需要一种特殊的类型,v8::Template。<br/><br/>Template是介于Javascript和C++变量间的中间层,你首先由C++对象生成一个Template,然后再由Template生成Javascript函数的对象。你可以事先在Template中准备好一些预备属性,然后生成的Javascript对象都将具备这些属性。<br/><br/>一个例子就是Google Chrome的DOM,DOM就是先用ObjectTemplate预先封装好对应的C++节点,最后再为每一个标签生成DOM对象。<br/><h4>FunctionTemplate</h4><br/>首先介绍FunctionTemplate,顾名思义,就是用来生成函数的Template。之前函数一直在文章里缺席,原因之一就是Javascript函数和C++函数的绑定必须仰赖Template。<br/><br/>FunctionTemplate的接口如下:<br/><pre escaped=“true” lang=“c” class=“brush: c;”>class V8EXPORT FunctionTemplate : public Template {<br/>public:<br/> /* Creates a function template./<br/> static Local<FunctionTemplate> New(<br/> InvocationCallback callback = 0,<br/> Handle<Value> data = Handle<Value>(),<br/> Handle<Signature> signature = Handle<Signature>());<br/> /* Returns the unique function instance in the current execution context./<br/> Local<Function> GetFunction();<br/><br/> /*<br/> * Set the call-handler callback for a FunctionTemplate. This<br/> * callback is called whenever the function created from this<br/> * FunctionTemplate is called.<br/> /<br/> void SetCallHandler(InvocationCallback callback,<br/> Handle<Value> data = Handle<Value>());<br/>/* Causes the function template to inherit from a parent function template./<br/> void Inherit(Handle<FunctionTemplate> parent);<br/><br/> /*<br/> * A PrototypeTemplate is the template used to create the prototype object<br/> * of the function created by this template.<br/> /<br/> Local<ObjectTemplate> PrototypeTemplate();<br/><br/> /*<br/> * Set the class name of the FunctionTemplate. This is used for<br/> * printing objects created with the function created from the<br/> * FunctionTemplate as its constructor.<br/> /<br/> void SetClassName(Handle<String> name);<br/>};</pre><br/>你可以使用FunctionTemplate::New ()生成一个空函数,然后用FunctionTemplate::SetCallHandler ()将其和C++函数绑定,或者直接靠FunctionTemplate::New (InvocationCallback callback)来用C++函数初始化一个FunctionTemplate。<br/><br/>用来生成FunctionTemplate的C++函数必须满足InvocationCallback的条件,即函数签名必须如下:<br/><pre escaped=“true” lang=“c” class=“brush: c;”>typedef Handle<Value> (InvocationCallback)(const Arguments& args);</pre><br/>此后,你可以使用FunctionTemplate::GetFunction()来获取对应的v8::Function。但是一个FunctionTemplate只能生成一个Function,FunctionTemplate::GetFunction()返回的都是同一个实体。这是因为Javascript里显式声明的全局函数只有一个实例。<br/><br/>不过,得到生成的函数后,你可以使用Function::NewInstance返回一个函数对象,等同于Javascript中的var tmp = new func;。<br/><br/>下面是一个使用FunctionTemplate的简单例子[<a href=“https://github.com/zcbenz/there-is-a-c-in-javascript/blob/master/function1.cc”>完整代码</a>]:<br/><pre escaped=“true” lang=“c” class=“brush: c;”>Handle<Value> print (const Arguments& args) {<br/> HandleScope scope;<br/><br/> for (int i = 0; i< args.Length(); ++i) {<br/> cout << String::Utf8Value (args[i]) << " ";<br/> }

<br/><br/> cout << endl;<br/><br/> return Undefined ();<br/>}<br/><br/>// main函数中<br/><br/> // Generate Function<br/> Local<FunctionTemplate> func_tpl = FunctionTemplate::New (print);<br/> func_tpl->SetClassName (String::NewSymbol (“print”));<br/> Local<Function> func = func_tpl->GetFunction ();<br/> cout << String::Utf8Value (func) << endl;<br/><br/> // Generate parameters<br/> Local<Value> args[4] = {<br/> String::New (“I”),<br/> String::New (“Love”),<br/> String::New (“C++”),<br/> String::New ("!")<br/> };<br/><br/> // Call Function<br/> func->Call (Object::New (), 4, args);</pre><br/>首先,我们定义了一个print函数,这个函数接受Arguments作为参数,Arguments实际上是一个包含了传进进来的参数的数组。接着我们建立了FunctionTemplate func_tpl,然后通过func_tpl->GetFunction得到函数实体,最后对这个函数实体进行调用。<br/><br/>那么,如果我们想要在Javascript代码中调用这个函数,应该怎么做呢,下面是一个演示[<a href=“https://github.com/zcbenz/there-is-a-c-in-javascript/blob/master/function2.cc”>完整代码</a>]:<br/><pre escaped=“true” lang=“c” class=“brush: c;”> // Generate Function<br/> Local<FunctionTemplate> func_tpl = FunctionTemplate::New (print);<br/> context->Global()->Set (String::NewSymbol (“print”),<br/> func_tpl->GetFunction ());<br/><br/> // Call in javascript<br/> Local<String> source = String::New (“print (‘I’, ‘Love’, ‘C++’, ‘!’);”);<br/> Script::Compile(source)->Run ();</pre><br/>修改之处主要是在全局作用域中加入我们的函数对象。<br/><h4>Function Instance</h4><br/>Javascript常用new Function ();的形式来创建对象,而C++中,Function::NewInstance可以返回一个函数的Instance。<br/><br/>比如下面的代码:<br/><pre escaped=“true” lang=“javascript” class=“brush: js;”>function girl (name) {<br/> this.name = name;<br/>}<br/><br/>var alice = new girl (“Alice”);<br/>alice.age = 21;</pre><br/>对应到C++中则是[<a href=“https://github.com/zcbenz/there-is-a-c-in-javascript/blob/master/function4.cc” target="_blank">完整代码</a>]:<br/><pre escaped=“true” lang=“c” class=“brush: c;”>Handle<Value> girl (const Arguments& args) {<br/> HandleScope scope;<br/><br/> if (args.Length() != 1 && !args[0]->IsString ())<br/> return ThrowException(v8::String::New(“Unexpected arguments”));<br/><br/> args.This()->Set (String::New (“name”), args[0]);<br/><br/> return Undefined ();<br/>}<br/><br/>// 在main函数中<br/> Local<FunctionTemplate> func_tpl = FunctionTemplate::New (girl);<br/><br/> Handle<Value> args[1] = { String::New (“Alice”) };<br/> Handle<Object> alice = func_tpl->GetFunction()->NewInstance (1, args);<br/> alice->Set (String::New (“age”), Integer::New (21));</pre><br/>其中有两点需要新的注意,首先Javascript中的this指针可以通过Arguments::This ()得到,其次C++中抛出Javascript的异常时,需要返回一个ThrowException对象。<br/><h4>ObjectTemplate</h4><br/>既然有生成函数的Template,自然也可以想到会有生成对象的Template,ObjectTemplate的目的就是根据包装起来的C++对象生成v8::Object。接口与Template也大致相当,通过ObjectTemplate::New返回新的ObjectTemplate,通过ObjectTemplate::NewInstance。<br/><br/>但是,C++对象应该存放在哪里呢?ObjectTemplate提供了一种Internal Field,也就是内部储存空间,我们可以通过External类型把C++对象储存在ObjectTemplate中相关接口如下:<br/><pre escaped=“true” lang=“c” class=“brush: c;”> /<br/> * Gets the number of internal fields for objects generated from<br/> * this template.<br/> /<br/> int InternalFieldCount();<br/><br/> /<br/> * Sets the number of internal fields for objects generated from<br/> * this template.<br/> /<br/> void SetInternalFieldCount(int value);</pre><br/>v8::Object中也有关于Internal Field的接口:<br/><pre escaped=“true” lang=“c” class=“brush: c;”> / Gets the number of internal fields for this Object. /<br/> V8EXPORT int InternalFieldCount();<br/> /* Gets the value in an internal field. /<br/> inline Local GetInternalField(int index);<br/> /* Sets the value in an internal field. */<br/> V8EXPORT void SetInternalField(int index, Handle<value>);</pre><br/>建立了ObjectTemplate后,我们可以通过ObjectTemplate::SetInternalFieldCount设定内部储存多少个内部变量。然后通过ObjectTemplate::NewInstance建立新的Object,再在v8::Object中通过SetInternalField和SetInternalField来对内部变量进行操作。<br/><br/>前文中我们提过Accessors,一种用来把C++中的变量返回到Javascript中的机制。那时我们操作的是全局变量,下面的例子里我们将为Object绑定一个C++对象,然后在Javascript中获取它的数据成员[<a href=“ https://github.com/zcbenz/there-is-a-c-in-javascript/blob/master/object1.cc” target="_blank">完整代码</a>]。<br/><br/>首先我们建立一个C++对象:<br/><pre escaped=“true” lang=“c” class=“brush: c;”>class Point {<br/> public:<br/> Point (int x, int y)<br/> :x (x), y (y)<br/> {<br/> }<br/><br/> int x, y;<br/>};</pre><br/>然后在main函数中生成并设置Object:<br/><pre escaped=“true” lang=“c” class=“brush: c;”> // 建造ObjectTemplate<br/> Handle<ObjectTemplate> obj_tpl = ObjectTemplate::New ();<br/> obj_tpl->SetInternalFieldCount (1);<br/><br/> // 建立Object,并与C++对象绑定<br/> Point point (10, 10);<br/> Handle<Object> obj = obj_tpl->NewInstance ();<br/> obj->SetInternalField (0, External::New (&point));<br/> obj->SetAccessor(String::New(“x”), XGetter, XSetter);<br/> obj->SetAccessor(String::New(“y”), YGetter, YSetter);<br/><br/> // 打印结果<br/> cout << *String::AsciiValue (obj->Get (String::New (“x”))) << endl;<br/> cout << *String::AsciiValue (obj->Get (String::New (“y”))) << endl;</pre><br/>最后是用来将C++对象中的数据成员传递到Javascript中的函数:<br/><pre escaped=“true” lang=“c” class=“brush: c;”>Handle<Value> XGetter (Local<String> property, const AccessorInfo& info) {<br/> Handle<Object> obj = info.This ();<br/> Point& point = static_cast<Point> (<br/> Local<External>::Cast(obj->GetInternalField(0))->Value ());<br/><br/> return Integer::New (point.x);<br/>}<br/><br/>void XSetter (Local<String> property, Local<Value> value,<br/> const AccessorInfo& info) {<br/> Handle<Object> obj = info.This ();<br/> Point& point = static_cast<Point> (<br/> Local<External>::Cast(obj->GetInternalField(0))->Value ());<br/><br/> point.x = value->Int32Value();<br/>}</pre><br/>简单说明一下代码,AccessorInfo::This ()可以返回调用该函数的v8::Object,由于C++对象作为External储存在Object的Internal Field中,我们需要使用Object::GetInternalField和External::Value最终得到这个对象。<br/><br/>最后,顺带一提,ObjectTemplate对应于Object也有相应的Set、SetAccssor函数,在ObjectTemplate设置好相应的属性后,生成的Object会自动继承它们。比如上面的代码有一处可以改成这样[<a href=“ https://github.com/zcbenz/there-is-a-c-in-javascript/blob/master/object2.cc” target="_blank">完整代码</a>]:<br/><pre escaped=“true” lang=“c” class=“brush: c;”> // 建造ObjectTemplate<br/> Handle<ObjectTemplate> obj_tpl = ObjectTemplate::New ();<br/> obj_tpl->SetInternalFieldCount (1);<br/> obj_tpl->SetAccessor(String::New(“x”), XGetter, XSetter);<br/> obj_tpl->SetAccessor(String::New(“y”), YGetter, YSetter);</pre><br/><h4>PrototypeTemplate</h4><br/>咦,为什么会突然冒出来个PrototypeTemplate?难道Javascript里有Prototype这种类型吗?非也非也,PrototypeTemplate专为Funtion.prototype而生,FunctionTemplate::PrototypeTemplate返回的是一个ObjectTemplate,用来供用户设定生成函数的prototype,一个例子如下[<a href=“ https://github.com/zcbenz/there-is-a-c-in-javascript/blob/master/function5.cc” target="_blank">完整代码</a>]:<br/><pre escaped=“true” lang=“c” class=“brush: c;”> Local<FunctionTemplate> func_tpl = FunctionTemplate::New ();<br/> Local<ObjectTemplate> prototype = func_tpl->PrototypeTemplate ();<br/> prototype->Set (String::New (“proto_const”), Integer::New (2));<br/> prototype->Set (String::New (“proto_method”), FunctionTemplate::New (print));</pre><br/><h4>More and more…</h4><br/>那么,到这里,Javascript的对象和函数就讲完了吗?冰山一角。虽然题为深入,但内容仍是v8基础概念和用法,更多细节,还需要在v8.h中深挖,这篇文章点到为止。下文我将描述node.js异步的机理。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Javascript里有个C:Part 3 - 深入对象 的相关文章

随机推荐

  • 2021组队训练赛第11场

    我们的终极目标不是AC 而是获取经验 2021组队训练赛第11场 我们的终极目标不是AC 而是获取经验 问题 A ABB 题意 考点 问题 C Bob in Wonderland 题意 考点 问题 F Zeldain Garden 题意 考
  • Spring框架之注解编程

    代码和配置 代码结构 maven依赖
  • Xshell连接不上虚拟机的问题和解决办法

    第一次用xshell 一直连不上linux 搞了好久 也查了很多办法 但是最后也终于解决了 在这里我分享一下自己的解决办法 再列举网上的办法 希望可以帮助其他人 1 你的linux ip地址没有配置 ip地址没有配置 你需要自己配置 配置的
  • 转行IT:网络工程师VS网络安全工程师,哪个能带你走上人生巅峰?

    记得曾经有人说过这样一个俗语 三百六十行 行行转IT 或许听到这个话的时候会觉得是一句玩笑话 但是浏览到网络上一些关于就业的文章 就能够明白这句话的真正意义所在 随着互联网的发展 越来越多人选择 甚至转行到IT行业 今天就带大家了解 网络工
  • AI实战营第二期 第五节 《目标检测与MMDetection》——笔记6

    文章目录 摘要 主要特性 常用概念 框 边界框 交并比 loU 感受野 有效感受野 置信度 目标检测的基本思路 难点 滑框 在特征图进行密集计算 边界框回归 基于锚框VS无锚框 NMS 非极大值抑制 使周密集预测模型进行推理步骤 如何训练
  • 在Ubuntu里面.AppImage格式安装

    具体而言 直接运行appimage就可以实现 安装 先给软件包可执行权限 chmod u x
  • CS5263芯片 DP转HDMI视频转换芯片 适用于HDMI单转线

    应用 DP转HDMI 视频芯片 分辨率可达到4K 60HZ 产品描述 Capstone CS5263AN是一款高性能DP1 4到HDMI2 0b转换器 设计用于将DP1 4源连接到HDMI2 0b接收器 CS5263AN集成了DP1 4兼容
  • Basic 1047 编程团体赛 (20分)

    题目 编程团体赛的规则为 每个参赛队由若干队员组成 所有队员独立比赛 参赛队的成绩为所有队员的成绩和 成绩最高的队获胜 现给定所有队员的比赛成绩 请你编写程序找出冠军队 输入格式 输入第一行给出一个正整数 N 1 0 4
  • STM32学习笔记—SPI通信

    1 SPI简介 2 函数配置 1 SPI简介 SPI通信是一种高速的 全双工的同步通信总线 通讯时 只占用四条线 MISO MOSI CS SCLK 其中cs为片选线 sclk为时钟线 一般同步通讯带有时钟线 像uart异步通信的就不带 m
  • Python:入门到放弃之基础篇(一)

    文章目录 前言 一 python的标识符 二 python变量类型 1 Number 2 String 3 List 4 Tuple 5 Set 6 Dictionary 三 python流程控制 1 顺序流程控制 2 分支流程控制 3 循
  • EMC电磁兼容测试项目简介

    EMC电磁兼容测试项目简介 一般来说 电气 电力设备产品要做的EMC电磁兼容测试主要包含浪涌 冲击 抗扰度 振铃波浪涌抗扰度 电快速瞬变脉冲群抗扰度 电压暂降 短时中断和电压变化抗扰度 工频电源谐波抗扰度 静电抗扰度 射频电磁场辐射抗扰度
  • TQ2440移植u-boot2016.11全过程记录-【4】LCD驱动移植并显示

    TQ2440移植u boot2016 11 LCD驱动移植并显示 LCD初始化流程分析 u boot的LCD初始化代码是在common lcd c中 我们找到lcd init函数 该函数功能流程为 lcd ctrl init初始化了LCD的
  • ipv6 socket编程实践

    Table of Contents 1 ipv6 socket编程实践 2 示例程序 ipv6 socket编程实践 ip地址长度变化 按照ipv4 255 255 255 255的地址格式 最长为15 加上结束符16字节长度 ipv6 的
  • FormData的详解

    转自 https blog csdn net yezitoo article details 78339201 FormData 1 概述 FormData类型其实是在XMLHttpRequest 2级定义的 它是为序列化表以及创建与表单格
  • 三相桥式全控整流电路

    三相桥式全控整流电路原理图 原理图 阴极连接在一起的3个晶闸管 VT1 VT3 VT5 称为共阴极组 阳极连接在一起的3个晶闸管 VT4 VT6 VT2 称为共阳极组 共阴极组中与a b c三相电源相接的3个晶闸管分别为VT1 VT3 VT
  • Swift 枚举与结构体

    Swift 枚举 枚举简单的说也是一种数据类型 只不过是这种数据类型只包含自定义的特定数据 它是一组有共同特性的数据的集合 Swift 的枚举类似于 Objective C 和 C 的结构 枚举的功能为 它声明在类中 可以通过实例化类来访问
  • PyTorch中实现数据集的自定义读取

    一 创作缘由 数据集呈现的方式有很多种 今天和大家仔细谈一谈当我们要读取的数据集信息存储在文本文件时 我们如何读取数据集 最近在实现一个垃圾分类的任务 数据集中每张图片的名称和数据标签都记录在了文本文件中 垃圾分类数据集介绍 一共有6种不同
  • mybatis3 mysql自动生成主键_mybatis自动生成主键

    mysql 使用useGeneratedKey属性 INSERT INTO STUDENTS NAME EMAIL PHONE VALUES name email phone 其他的方式 使用selectKey子标签 属性 order be
  • [优化篇]OpenStack的Cinder后端存储技术——GlusterFS(1)

    题记 上一篇已经介绍了OpenStack的Cinder后端使用NFS存储技术 为什么要使用NFS呢 一般情况下 如果你的网络是千兆网络 在如果你考虑性能的要求 存储设置到宿主机本地硬盘效率会更好 例如我们可以在计算节点上安装cinder v
  • Javascript里有个C:Part 3 - 深入对象

    http cnodejs org topic 4f16442ccae1f4aa270010bd em Javascript里有个C em 系列文章 br ol br li a title 编辑 Javascript里有个C Part hre