V8引擎能夠被嵌入在任何C++程序中使用。瀏覽器
V8的APIs提供了對JavaScript代碼的編譯和執行功能、與C++函數互掉、訪問數據結構、錯誤處理、及安全檢查等功能。在應用程序中可將V8當作一個C++庫來使用,訪問V8的APIs須要包含V8的頭文件v8.h。緩存
使用V8很是簡單,首先看一個簡單示例程序:安全
#include <stdio.h> #include <stdlib.h> #include <string.h> #include "include/libplatform/libplatform.h" #include "include/v8.h" using namespace v8; class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator { public: virtual void* Allocate(size_t length) { void* data = AllocateUninitialized(length); return data == NULL ? data : memset(data, 0, length); } virtual void* AllocateUninitialized(size_t length) { return malloc(length); } virtual void Free(void* data, size_t) { free(data); } }; int main(int argc, char* argv[]) { // 初始化V8 V8::InitializeICU(); V8::InitializeExternalStartupData(argv[0]); Platform* platform = platform::CreateDefaultPlatform(); V8::InitializePlatform(platform); V8::Initialize(); // 建立一個新的Isolate ArrayBufferAllocator allocator; Isolate::CreateParams create_params; create_params.array_buffer_allocator = &allocator; Isolate* isolate = Isolate::New(create_params); { Isolate::Scope isolate_scope(isolate); // 建立一個分配在棧上的handle scope. HandleScope handle_scope(isolate); // 建立一個context. Local<Context> context = Context::New(isolate); // 關聯context Context::Scope context_scope(context); // 建立一個包含JavaScript代碼的字符串 Local<String> source = String::NewFromUtf8(isolate, "'Hello' + ', World!'", NewStringType::kNormal).ToLocalChecked(); // 編譯JavaScript代碼 Local<Script> script = Script::Compile(context, source).ToLocalChecked(); // 運行代碼併產生結果 Local<Value> result = script->Run(context).ToLocalChecked(); String::Utf8Value utf8(result); printf("%s\n", *utf8); } // 釋放資源 isolate->Dispose(); V8::Dispose(); V8::ShutdownPlatform(); delete platform; return 0; }
一個handle提供了一個對堆上對象地址的引用,V8垃圾回收器經過對釋放再也不使用的對象來達到回收內存的做用。在垃圾回收週期期間,對象的位置可能發生移動,當一個對象發生移動後,全部指向它的handle都會被更新。數據結構
生命週期由其所在的handle scope決定,當handle scope被刪除後,垃圾回收器將會回收其中的全部handle。這類handle典型使用在一個函數中。函數
能夠像這樣聲明一個局部對象類:Local<Class>。工具
*注意:一個handle的棧不是C++調用棧的一部分,但handle scope是嵌入在C++調用棧中的。Handle scope只能經過棧內存來分配,不能使用new操做來分配。優化
當須要不只是在局部保持對一個對象的引用時,使用堆handle。如在Chrome瀏覽器中,DOM節點都是使用堆handle。spa
能夠像這樣聲明持久對象:Persistent<Class>。指針
一個context表明一個執行環境上下文,容許單獨的、無關的JavaScript代碼運行在一個V8實例中。能夠指定JavaScript代碼運行在任何context中。code
context機制的引入是很是必要的,JavaScript提供了很是多的內建函數和對象,因爲這些函數和對象能夠在JavaScript代碼執行時被改變,所以若是不提供一個單獨的執行環境context,將會產生許多問題。如兩個徹底不相關的函數都修改了同一個內建的對象。
每次建立一個context都須要建立一系列的內建對象,這將產生很大的消耗。V8使用了緩存機制來解決這一問題,當建立完第一個context後,後續再需建立context時,代價很是小。V8同時使用了snapshot機制(可經過命令 snapshot=yes開啓,默認開啓)來高度優化第一次建立context所帶來的消耗。
當一個context被建立後,能夠屢次進出此context。例如,當在context A中時,進入了context B,此時當前的context更新爲B,當退出B時,當前的context又被轉回A,見下圖所示:
在V8中使用context的絕佳實例是,每一個瀏覽器中的每一個iframe都使用一個單獨的context。
Template被用來封裝C++函數和對象來給JavaScript對象使用。例如,Chrome封裝了C++中的DOM節點做爲JavaScript對象。
Template分爲函數template和對象template。
能夠像下面這樣的方式來使用template:
Local<ObjectTemplate> global = ObjectTemplate::New(isolate); global->Set(String::NewFromUtf8(isolate, "log"), FunctionTemplate::New(isolate, LogCallback));
當JavaScript引擎所提供的能力不能知足業務需求時,如引擎自己對HTML5的支持程度不夠,這時應用程序能夠擴展V8引擎的能力。V8提供兩種方式來擴展引擎:動態的擴展機制以及靜態的綁定機制。
V8經過提供一個基類Extension和一個全局註冊函數,來擴展JavaScript藉口。
示例代碼:
class MyExtension : public v8::Extension { public: virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(v8::Handle<v8::String> name) { // 可根據name來返回不一樣的函數 return v8::FunctionTemplate::New(MyExtension::MyFunc); } static v8::Handle<v8::Value> MyFunc(const v8::Arguments& args) { // 自定義處理 return v8::Undefined(); } }; MyExtension extension; RegisterExtension(&extension);
首先建立基於Extension基類的子類,而後實現GetNativeFunction。接着將子類的實例註冊到V8引擎中,這樣,當JavaScript代碼中調用MyFunc時,就能執行自定義的MyFunc函數。
整個過程很是簡單。
綁定的原理很是簡單,即便用IDL文件或接口文件來生成綁定文件,而後將這些文件與V8引擎一塊兒編譯。
一個簡單的IDL文件以下:
module mymodule { interface [ InterfaceName=MyObject ] MyObj { readonly attribute long myAttr; DOMString myMethod(DOMString myArg); } }
完成好IDL文件後,可使用WebKit的工具來經過將IDL文件轉換成V8的綁定文件。V8的綁定文件便是標準的C++文件,包含了在IDL文件中定義的函數和對象。當綁定文件連同V8一塊兒編譯後,便可在JavaScript代碼中直接使用自定義的函數和對象。