亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

[譯] V8 使用者文檔

lei___ / 2672人閱讀

摘要:注意句柄棧并不是調(diào)用棧中的一部分,但句柄域卻在棧中。一個(gè)依賴于構(gòu)造函數(shù)和析構(gòu)函數(shù)來管理下層對(duì)象的生命周期。對(duì)象模板用來配置將這個(gè)函數(shù)作為構(gòu)造函數(shù)而創(chuàng)建的對(duì)象。

如果你已經(jīng)閱讀過了上手指南,那么你已經(jīng)知道了如何作為一個(gè)多帶帶的虛擬機(jī)使用 V8 ,并且熟悉了一些 V8 中的關(guān)鍵概念,如句柄,上下文。在本文檔中,還將繼續(xù)深入討論這些概念并且介紹其他一些在你的 C++ 應(yīng)用中使用 V8 的關(guān)鍵點(diǎn)。

V8 的 API 提供了編譯和執(zhí)行腳本,訪問 C++ 方法和數(shù)據(jù)結(jié)構(gòu),處理錯(cuò)誤和啟用安全檢查的函數(shù)。你的應(yīng)用可以像使用其他的 C++ 庫一樣使用 V8 。你的 C++ 應(yīng)用可以通過引入頭文件 include/v8.h 來訪問 V8 API 。

當(dāng)你想要優(yōu)化你的應(yīng)用時(shí),V8 設(shè)計(jì)概要文檔可以提供很多有用的背景知識(shí)。

前言

這篇文檔的受眾是那些想要在自己的 C++ 程序中使用 V8 JavaScript 引擎的人。它將能幫助你在 JavaScript 中使用你應(yīng)用中的 C++ 對(duì)象和方法,亦能幫助你在 C++ 應(yīng)用中使用 JavaScript 對(duì)象和方法。

句柄和垃圾回收

一個(gè)句柄提供了對(duì)在堆中的一個(gè) JavaScript 對(duì)象地址的引用。V8 的垃圾回收器會(huì)在該對(duì)象不能再次被訪問到時(shí),將其回收。在垃圾回收的過程中,垃圾回收器可能會(huì)改變對(duì)象在堆中的位置。當(dāng)垃圾回收器移動(dòng)對(duì)象時(shí),所有引用到該對(duì)象的句柄也會(huì)被一同更新。

當(dāng)一個(gè)對(duì)象在 JavaScript 中已經(jīng)不可被訪問并且沒有任何指向它的句柄時(shí),它就會(huì)被垃圾回收。V8 的垃圾回收機(jī)制是 V8 性能表現(xiàn)的關(guān)鍵。更多信息可參閱 V8 設(shè)計(jì)概要文檔。

句柄分為許多種:

本地句柄會(huì)被分配在棧中,并且當(dāng)對(duì)應(yīng)的析構(gòu)函數(shù)被調(diào)用時(shí),它也會(huì)被刪除。這些本地句柄的生命周期取決于它對(duì)應(yīng)的句柄域(handle scope),句柄域通常在一個(gè)函數(shù)調(diào)用的開始被創(chuàng)建。當(dāng)句柄域被刪除時(shí),垃圾回收器就可以清除之前分配在該句柄域中的所有句柄了,因?yàn)樗鼈儾荒茉俦?JavaScript 或其他句柄所訪問到。這也正是在上手指南中使用的句柄。
本地句柄可通過類 Local 創(chuàng)建。

注意:句柄棧并不是 C++ 調(diào)用棧中的一部分,但句柄域卻在 C++ 棧中。故句柄域不可通過 new 關(guān)鍵字來分配。

持久句柄提供了對(duì)分配在堆中的 JavaScript 對(duì)象的引用。當(dāng)你需要在超過一次函數(shù)中保持對(duì)一個(gè)對(duì)象的引用時(shí),或者句柄的生命周期與 C++ 的塊級(jí)域不相符時(shí),你應(yīng)使用持久句柄。例如,在 Google Chrome 中,持久句柄被用來引用 DOM 節(jié)點(diǎn)。一個(gè)持久句柄可以通過 PersistentBase::SetWeak ,變?yōu)槿酰╳eak)持久句柄,當(dāng)一個(gè)對(duì)象所剩的唯一引用是來自于一個(gè)弱持久句柄時(shí),便會(huì)觸發(fā)垃圾回收。

一個(gè) UniquePersistent 依賴于 C++ 構(gòu)造函數(shù)和析構(gòu)函數(shù)來管理下層對(duì)象的生命周期。

一個(gè) Persistent 可以通過自身的構(gòu)造函數(shù)來創(chuàng)建,但必須手動(dòng)地通過 Persistent::Reset 來清除。

還有兩種很少會(huì)被使用到的句柄,在這里我們僅對(duì)它們做一個(gè)簡單的介紹:

永久(Eternal)句柄是一種為被認(rèn)為永遠(yuǎn)不會(huì)被刪除的 JavaScript 對(duì)象所設(shè)計(jì)的持久句柄。它的創(chuàng)建開銷更低,因?yàn)樗恍枰焕厥铡?/p>

PersistentUniquePersistent 都不能被復(fù)制,所以它們不能作為 C++ 11 之前的標(biāo)準(zhǔn)庫容器中的值來使用。PersistentValueMapPersistentValueVector 為它們提供了容器類,提供了類似于集合和向量的語義。

當(dāng)然,每當(dāng)你為了創(chuàng)建一個(gè)對(duì)象而創(chuàng)建一個(gè)本地句柄時(shí),往往可能會(huì)導(dǎo)致創(chuàng)建了許多句柄。這就是句柄域所存在的意義。你可以將句柄域視作一個(gè)保存了許多句柄的容器。當(dāng)句柄域的析構(gòu)函數(shù)被調(diào)用時(shí),所有它里面的句柄都會(huì)被從棧中移除。正如你所期望的,這些句柄做指向的對(duì)象隨后就可以被垃圾回收。

回到我們?cè)谏鲜种改现械睦?,在下面的圖示中,你可以看到句柄棧和堆中的對(duì)象。值得注意的是,Context::New() 的返回值是一個(gè)本地句柄,然后我們基于它創(chuàng)建了一個(gè)新的持久句柄,用以闡述持久句柄的用途。

當(dāng) HandleScope::~HandleScope 析構(gòu)函數(shù)被調(diào)用時(shí),該句柄域便會(huì)被刪除。所有被句柄域中的句柄所引用的對(duì)象,都將可以在下次垃圾回收時(shí)被刪除,如果沒有其他對(duì)于它們的引用存在。垃圾回收器同樣還會(huì)刪除堆中的 source_objscript_obj 對(duì)象,因?yàn)樗鼈儾槐蝗魏尉浔?,并且也不可?JavaScript 訪問。由于 context 對(duì)象是一個(gè)持久句柄,所以當(dāng)句柄域退出時(shí),它并不會(huì)被移除,唯一可以刪除它的辦法就是調(diào)用它的 Reset 方法。

注意:后文中的句柄如果不加注明,都指的是本地句柄。

在這個(gè)模型下,有一個(gè)非常常見的陷阱需要注意:你不可以直接地在一個(gè)聲明了句柄域的函數(shù)中返回一個(gè)本地句柄。如果你這么做了,那么你試圖返回的本地句柄,將會(huì)在函數(shù)返回之前,在句柄域的析構(gòu)函數(shù)中被刪除。正確的做法是使用 EscapableHandleScope 來代替 HandleScope 創(chuàng)建句柄域,然后調(diào)用 Escape 方法,并且傳入你想要返回的句柄。例子:

// 這個(gè)函數(shù)會(huì)返回一個(gè)帶有 x,y 和 z 三個(gè)元素的新數(shù)組
Local NewPointArray(int x, int y, int z) {
  v8::Isolate* isolate = v8::Isolate::GetCurrent();

  // 我們將會(huì)創(chuàng)建一些臨時(shí)的句柄,所以我們先創(chuàng)建一個(gè)句柄域
  EscapableHandleScope handle_scope(isolate);

  // 創(chuàng)建一個(gè)空數(shù)組
  Local array = Array::New(isolate, 3);

  // 如果在創(chuàng)建數(shù)組時(shí)產(chǎn)生異常,則返回一個(gè)空數(shù)組
  if (array.IsEmpty())
    return Local();

  // 填充數(shù)組
  array->Set(0, Integer::New(isolate, x));
  array->Set(1, Integer::New(isolate, y));
  array->Set(2, Integer::New(isolate, z));

  // 通過 Escape 返回該數(shù)組
  return handle_scope.Escape(array);
}

Escape 方法復(fù)制參數(shù)中的值至一個(gè)封閉的域中,然后刪除其他本地句柄,最后返回這個(gè)可以被安全返回的新句柄副本。

上下文

在 V8 中,上下文是一個(gè)允許多個(gè)分別獨(dú)立的,不相關(guān)的 JavaScript 應(yīng)用在一個(gè)多帶帶的 V8 實(shí)例中運(yùn)行的執(zhí)行環(huán)境。你必須為每一個(gè)你想要執(zhí)行的 JavaScript 代碼指定一個(gè)上下文。

這樣做是必要的么?這么做的原因是,JavaScript 本身提供了一組內(nèi)建的工具函數(shù)和對(duì)象,但它們又可以被 JavaScript 代碼所修改。例如,兩個(gè)完全沒有關(guān)聯(lián)的 JavaScript 函數(shù)同時(shí)修改了一個(gè)全局對(duì)象,那么可能就會(huì)造成不可預(yù)期的后果。

從 CPU 時(shí)間和內(nèi)存的角度來看,創(chuàng)建一個(gè)擁有指定數(shù)量的內(nèi)建對(duì)象的執(zhí)行上下文似乎開銷很大。但是,V8 的緩存機(jī)制可以確保,雖然創(chuàng)建的第一個(gè)上下文開銷非常大,但后續(xù)的上下文創(chuàng)建的開銷都會(huì)小很多。這是因?yàn)榈谝淮蝿?chuàng)建上下文時(shí),需要?jiǎng)?chuàng)建內(nèi)建對(duì)象和解析內(nèi)建的 JavaScript 代碼,而后續(xù)的上下文創(chuàng)建則只需為它們的上下文創(chuàng)建內(nèi)建對(duì)象即可。如果開啟了 V8 的快照特性(可通過選項(xiàng) snapshot=yes 開啟,默認(rèn)值即為開啟),第一次創(chuàng)建上下文的時(shí)間花銷也會(huì)被極大的優(yōu)化,因?yàn)榭煺罩邪诉@些所需的內(nèi)建 JavaScript 代碼已然被編譯后的版本。除了垃圾回收外,V8 的緩存也是 V8 性能表現(xiàn)的關(guān)鍵,更多詳情可參閱V8 設(shè)計(jì)概要文檔。

當(dāng)你創(chuàng)建了一個(gè)上下文后,你可以隨意地進(jìn)入和離開它,沒有次數(shù)的限制。當(dāng)你已經(jīng)在上下文 A 中時(shí),你還可以再次進(jìn)入另一個(gè)上下文 B ,這以為著當(dāng)前的上下文環(huán)境變成了 B 。當(dāng)你離開了 B 后,A 就再次成為了當(dāng)前上下文。如圖示:

需要注意的是,JavaScript 內(nèi)建工具函數(shù)和對(duì)象是相互獨(dú)立的。當(dāng)你創(chuàng)建一個(gè)上下文時(shí),你可以同時(shí)設(shè)置可選的安全標(biāo)識(shí)(security token)。更多詳情請(qǐng)參閱下文的安全模型章節(jié)。

在 V8 中使用上下文的最初動(dòng)機(jī)是,在一個(gè)瀏覽器中,每一個(gè)窗口和 iframe 都需要有各自獨(dú)立的 JavaScript 環(huán)境。

模板

一個(gè)模板即為一個(gè)上下文中 JavaScript 函數(shù)和對(duì)象的藍(lán)圖。你可以在 JavaScript 對(duì)象內(nèi)使用一個(gè)模板來包裹 C++ 函數(shù)和數(shù)據(jù)結(jié)構(gòu),致使它們可以被 JavaScript 腳本所操縱。例如,Google Chrome 使用模板來將 C++ DOM 節(jié)點(diǎn)包裹為 JavaScript 對(duì)象,然后在全局命名空間下注冊(cè)函數(shù)。你可以創(chuàng)建一個(gè)模板集合,然后在不同的上下文中使用它。模板的數(shù)量并沒有限制,但是在一個(gè)指定的上下文中,每一個(gè)模板都只允許有一個(gè)它的實(shí)例。

在 JavaScript 中,函數(shù)和對(duì)象間有強(qiáng)烈的二元性。在 Java 或 C++ 中,如果要?jiǎng)?chuàng)建一個(gè)新類型的對(duì)象,你需要首先定義一個(gè)新的類。而在 JavaScript 中,你需要定義一個(gè)新的函數(shù),然后把這個(gè)函數(shù)視作一個(gè)構(gòu)造函數(shù)。一個(gè) JavaScript 對(duì)象的外形和功能都與它的構(gòu)造函數(shù)關(guān)系密切。這些也都反應(yīng)在了 V8 模板的工作方式中。模板分為兩種類型:

函數(shù)模板
一個(gè)函數(shù)模板就是一個(gè)獨(dú)立函數(shù)的藍(lán)圖。在一個(gè)你想要實(shí)例化 JavaScript 函數(shù)的上下文中,你可以通過調(diào)用模板的 GetFunction 方法來創(chuàng)建一個(gè)模板的 JavaScript 實(shí)例。當(dāng) JavaScript 函數(shù)實(shí)例被調(diào)用時(shí),你還可以為模板關(guān)聯(lián)一個(gè) C++ 回調(diào)函數(shù)一同被調(diào)用。

對(duì)象模板
每一個(gè)函數(shù)模板都有一個(gè)與之關(guān)聯(lián)的對(duì)象模板。對(duì)象模板用來配置將這個(gè)函數(shù)作為構(gòu)造函數(shù)而創(chuàng)建的對(duì)象。你可以為對(duì)象模板關(guān)聯(lián)兩種類型的 C++ 回調(diào):

訪問器回調(diào)會(huì)在指定對(duì)象原型被腳本訪問時(shí)被調(diào)用。

攔截器回調(diào)會(huì)在任何對(duì)象原型被腳本訪問時(shí)被調(diào)用。

訪問器和攔截器的詳情會(huì)在后文中繼續(xù)討論。

下面的例子中,我們將創(chuàng)建一個(gè)關(guān)聯(lián)全局對(duì)象的模板,然后設(shè)置一些內(nèi)建的全局函數(shù)。

// 創(chuàng)建一個(gè)關(guān)聯(lián)全局對(duì)象的模板,然后設(shè)置一些內(nèi)建的全局函數(shù)。
Local global = ObjectTemplate::New(isolate);
global->Set(String::NewFromUtf8(isolate, "log"), FunctionTemplate::New(isolate, LogCallback));

Persistent context = Context::New(isolate, NULL, global);

該例子取自于 process.cc 中的 JsHttpProcessor::Initialiser。

訪問器

訪問器為當(dāng)一個(gè) JavaScript 對(duì)象原型被腳本訪問時(shí),執(zhí)行的一個(gè) C++ 回調(diào)函數(shù),它計(jì)算并返回一個(gè)值。訪問器需要通過一個(gè)對(duì)象模板來配置,通過它的 SetAccessor 方法。這個(gè)方法的第一個(gè)參數(shù)為關(guān)聯(lián)的屬性,最后一個(gè)參數(shù)為當(dāng)腳本試圖讀寫這個(gè)屬性時(shí)執(zhí)行的回調(diào)。

訪問的復(fù)雜度取決于你想要其控制的數(shù)據(jù)類型:

訪問靜態(tài)全局變量

訪問動(dòng)態(tài)變量

訪問靜態(tài)全局變量

假設(shè)有兩個(gè)名為 xy 的 C++ 整形變量,它們需要成為一個(gè)上下文的 JavaScript 中的全局變量。為了達(dá)成這個(gè)目的,當(dāng)腳本讀或?qū)戇@些變量時(shí),你需要調(diào)用 C++ 訪問器函數(shù)。這些訪問器函數(shù)使用 Integer::New 來把 C++ 整形數(shù)轉(zhuǎn)換為 JavaScript 整形數(shù),并且使用 Int32Value 來把 JavaScript 整形數(shù)轉(zhuǎn)換為 C++ 整形數(shù)。例子:

  void XGetter(Local property,
                const PropertyCallbackInfo& info) {
    info.GetReturnValue().Set(x);
  }

  void XSetter(Local property, Local value,
               const PropertyCallbackInfo& info) {
    x = value->Int32Value();
  }

  // YGetter/YSetter 十分類似,這里就省略了

  Local global_templ = ObjectTemplate::New(isolate);
  global_templ->SetAccessor(String::NewFromUtf8(isolate, "x"), XGetter, XSetter);
  global_templ->SetAccessor(String::NewFromUtf8(isolate, "y"), YGetter, YSetter);
  Persistent context = Context::New(isolate, NULL, global_templ);

注意代碼中的對(duì)象模板和上下文幾乎在同時(shí)創(chuàng)建。模板可以提前創(chuàng)建好,然后在任意數(shù)量的上下文中使用它。

訪問動(dòng)態(tài)變量

在上面的例子中,變量是靜態(tài)和全局的。那么,如果數(shù)據(jù)是動(dòng)態(tài)的,像瀏覽器中的 DOM 樹這樣呢?假設(shè)我們有一個(gè) C++ 類 Point,它有兩個(gè)屬性 xy

  class Point {
   public:
    Point(int x, int y) : x_(x), y_(y) { }
    int x_, y_;
  }

為了讓任意數(shù)量的 C++ point 實(shí)例可以通過 JavaScript 訪問,我們需要為每一個(gè) C++ point 實(shí)例創(chuàng)建一個(gè) JavaScript 對(duì)象。這可以通過外部(external)值和內(nèi)部(internal)屬性共同辦到。

首先創(chuàng)建一個(gè)對(duì)象模板,用以包裹 point 實(shí)例:

  Local point_templ = ObjectTemplate::New(isolate);

每一個(gè) JavaScript 中的 point 對(duì)象都保持了對(duì) C++ 對(duì)象的引用,因?yàn)樗詢?nèi)部屬性的方式被包裹。這些屬性不可通過 JavaScript 訪問,只能通過 C++ 代碼訪問到。一個(gè)對(duì)象可以有任意數(shù)量的內(nèi)部屬性,這個(gè)數(shù)量需通過以下方法來設(shè)置:

  point_templ->SetInternalFieldCount(1);

上面的例子中,內(nèi)部屬性的數(shù)量被設(shè)置為了 1,表明這對(duì)象有一個(gè)內(nèi)部屬性,索引值為 0。

向模板添加 xy 訪問器:

  point_templ.SetAccessor(String::NewFromUtf8(isolate, "x"), GetPointX, SetPointX);
  point_templ.SetAccessor(String::NewFromUtf8(isolate, "y"), GetPointY, SetPointY);

接下來,我們通過創(chuàng)建一個(gè)新的模板實(shí)例來包裹 C++ point 實(shí)例,然后將內(nèi)部屬性 0 設(shè)置為 p 的外部包裹。

  Point* p = ...;
  Local obj = point_templ->NewInstance();
  obj->SetInternalField(0, External::New(isolate, p));

一個(gè)外部對(duì)象僅被用來在內(nèi)部屬性中存儲(chǔ)引用。JavaScript 對(duì)象不能直接地引用 C++ 對(duì)象,所以外部值就像從 JavaScript 到 C++ 的“一座橋梁”。所以外部值是句柄的相反面,因?yàn)榫浔淖饔檬亲屛覀冊(cè)?C++ 中可以獲取 JavaScript 對(duì)象的引用。

以下便是 x 的讀和寫訪問器的定義,y 的定義和 x 的十分類似,只需將 x 替換為 y 即可:

  void GetPointX(Local property,
                 const PropertyCallbackInfo& info) {
    Local self = info.Holder();
    Local wrap = Local::Cast(self->GetInternalField(0));
    void* ptr = wrap->Value();
    int value = static_cast(ptr)->x_;
    info.GetReturnValue().Set(value);
  }

  void SetPointX(Local property, Local value,
                 const PropertyCallbackInfo& info) {
    Local self = info.Holder();
    Local wrap = Local::Cast(self->GetInternalField(0));
    void* ptr = wrap->Value();
    static_cast(ptr)->x_ = value->Int32Value();
  }

訪問器抽象了對(duì)于 C++ point 對(duì)象的引用和對(duì)其的讀寫操作。這樣這些訪問器就可以被用于任意數(shù)量的被包裹后的 point 對(duì)象中了。

攔截器

你還可以在一個(gè)腳本訪問任意對(duì)象屬性時(shí),設(shè)置一個(gè)回調(diào)函數(shù)。這些回調(diào)函數(shù)稱為攔截器。攔截器分為兩種類型:

具名屬性攔截器,它會(huì)在訪問名稱為字符串的屬性時(shí)被調(diào)用,如瀏覽器環(huán)境中的 document.theFormName.elementName 。

索引屬性攔截器,它會(huì)在訪問索引屬性時(shí)被調(diào)用,如瀏覽器環(huán)境中的 document.forms.elements[0] 。

V8 源碼中的 process.cc 文件中,包含了一個(gè)攔截器的使用實(shí)例。下面例子中的 SetNamedPropertyHandler 設(shè)置了 MapGetMapSet 這兩個(gè)攔截器:

Local result = ObjectTemplate::New(isolate);
result->SetNamedPropertyHandler(MapGet, MapSet);

MapGet 攔截器源碼如下:

void JsHttpRequestProcessor::MapGet(Local name,
                                    const PropertyCallbackInfo& info) {
  // Fetch the map wrapped by this object.
  map *obj = UnwrapMap(info.Holder());

  // Convert the JavaScript string to a std::string.
  string key = ObjectToString(name);

  // Look up the value if it exists using the standard STL idiom.
  map::iterator iter = obj->find(key);

  // If the key is not present return an empty handle as signal.
  if (iter == obj->end()) return;

  // Otherwise fetch the value and wrap it in a JavaScript string.
  const string &value = (*iter).second;
  info.GetReturnValue().Set(String::NewFromUtf8(value.c_str(), String::kNormalString, value.length()));
}

和訪問器一樣,特定的回調(diào)函數(shù)會(huì)在一個(gè)屬性被訪問后觸發(fā)。它和訪問器的區(qū)別就是,訪問器會(huì)回調(diào)僅會(huì)在一個(gè)特定的屬性被訪問時(shí)觸發(fā),而攔截器回調(diào)則會(huì)在任意屬性被訪問時(shí)觸發(fā)。

安全模型

“同源策略”(首次出現(xiàn)于網(wǎng)景瀏覽器 2.0 中),用于阻止從另一個(gè)“源”中加載腳本或文檔到本地“源”里。這個(gè)源的概念中包含了域名(www.example.com),協(xié)議(http 或 https)和端口(如 www.example.com:81 和 www.example.com 不同源)。以上部分全部一樣,才能被視為同源。如果沒了這層保護(hù),許多網(wǎng)頁就可以會(huì)遭到其他惡意網(wǎng)頁的攻擊。

在 V8 中,“源”即為上下文。在一個(gè)上下文中訪問另一個(gè)上下文默認(rèn)是不被允許的。如果一定訪問,那么必須使用安全標(biāo)識(shí)(security tokens)或安全回調(diào)(security callbacks)。一個(gè)安全標(biāo)識(shí)可以是任意類型的值,但通常是一個(gè) symbol 或一個(gè)唯一字符串。當(dāng)你設(shè)置一個(gè)上下文時(shí),可以通過 SetSecurityToken 可選地設(shè)置一個(gè)安全標(biāo)識(shí)。如果你沒有明確地指明一個(gè)安全標(biāo)識(shí),那么 V8 將會(huì)為該上下文自動(dòng)生成一個(gè)。

當(dāng)試圖去訪問一個(gè)全局變量時(shí),V8 的安全系統(tǒng)首先會(huì)去檢查被訪問的全局變量的上下文的安全標(biāo)識(shí)與訪問代碼的上下文的安全標(biāo)識(shí)是否一致,若一致,則允許訪問。如果安全標(biāo)識(shí)不一致,那么 V8 將會(huì)觸發(fā)一個(gè)回調(diào)函數(shù)來判斷這個(gè)訪問是否該被允許。你可以通過在對(duì)象模板的方法 SetAccessCheckCallbacks ,來設(shè)置這個(gè)安全回調(diào)。這個(gè)回調(diào)的參數(shù)為,將會(huì)被訪問的對(duì)象,將會(huì)被訪問的屬性名,和訪問的類型(如讀,寫或刪除)并且返回值即表示是否允許這次訪問。

在 Google Chrome 中,這套安全機(jī)制運(yùn)用在以下幾處:window.focus(),window.blur(),window.close(),window.locationwindow.open(),history.forward()history.back()history.go() 。

異常

當(dāng)一個(gè)錯(cuò)誤發(fā)生時(shí),V8 將會(huì)拋出一個(gè)異常。例如,當(dāng)一個(gè)腳本或函數(shù)試圖去讀取一個(gè)不存在的屬性時(shí),或一個(gè)非函數(shù)對(duì)象被調(diào)用時(shí)。

如果一次操作失敗了,V8 將會(huì)返回空句柄。因?yàn)樵谶M(jìn)一步操作前,檢查返回值是否是空句柄就變得尤為重要。我們可以通過本地句柄類(Local)的成員函數(shù) IsEmpty() 來進(jìn)行檢查。

你也可以通過 TryCatch 類捕獲異常,例子:

  TryCatch trycatch(isolate);
  Local v = script->Run();
  if (v.IsEmpty()) {
    Local exception = trycatch.Exception();
    String::Utf8Value exception_str(exception);
    printf("Exception: %s
", *exception_str);
    // ...
  }

如果返回值是一個(gè)空句柄,并且你沒有使用 TryCatch ,那么你的代碼必須要終止。如果你使用了 TryCatch ,那么你的代碼則可以繼續(xù)執(zhí)行。

繼承

JavaScript 是第一個(gè)不基于類的面向?qū)ο缶幊陶Z言。它使用了基于原型的繼承。這對(duì)于一直使用傳統(tǒng)面向?qū)ο缶幊陶Z言(如 C++ 和 Java)的程序員來說,可能會(huì)有些困惑。

傳統(tǒng)的面向?qū)ο缶幊陶Z言(如 C++ 和 Java)通常基于兩個(gè)概念:類和繼承。JavaScript 是一個(gè)基于原型的編程語言,所以它和傳統(tǒng)的面向?qū)ο缶幊陶Z言不同,它只有對(duì)象。JavaScript 并不原生支持基于類聲明的繼承。但是 JavaScript 的原型機(jī)制簡化了為實(shí)例添加自定義屬性和方法的過程。在 JavaScript 中,你可以為單個(gè)實(shí)例添加自定義的屬性。例子:

// 創(chuàng)建一個(gè)對(duì)象 bicycle
function bicycle(){
}
// 創(chuàng)建一個(gè)名為 roadbike 的實(shí)例
var roadbike = new bicycle()
// 為 roadbike 定義一個(gè)自定義屬性 wheels
roadbike.wheels = 2

自定義屬性僅僅存在于當(dāng)前這個(gè)實(shí)例中。如果我們創(chuàng)建了另一個(gè) bicycle 實(shí)例,如 mountainbikemountainbike.wheels 將會(huì)是 undefined

某些時(shí)候,這就是我們想要的。而又有些時(shí)候,我們想要為所有的實(shí)例都添加上這個(gè)屬性。因?yàn)楫吘顾械淖孕熊嚩加休喿?。這是我們就會(huì)使用到原型機(jī)制。我們只需為對(duì)象的 prototype 屬性上添加我們想要的自定義屬性即可:

// 創(chuàng)建一個(gè)對(duì)象 bicycle
function bicycle(){
}
// 將 wheels 屬性添加到對(duì)象的原型上
bicycle.prototype.wheels = 2

這樣,所有的 bicycle 實(shí)例都將會(huì)擁有 wheels 屬性。

在 V8 的模板中,做法也是一樣的。每一個(gè) FunctionTemplate 類實(shí)例都有一個(gè) PrototypeTemplate 方法來給出函數(shù)的原型。你可以在其上添加屬性,為這些屬性關(guān)聯(lián) C++ 函數(shù)。都會(huì)影響到該模板關(guān)聯(lián)所有的實(shí)例中。例子:

 Local biketemplate = FunctionTemplate::New(isolate);
 biketemplate->PrototypeTemplate().Set(
     String::NewFromUtf8(isolate, "wheels"),
     FunctionTemplate::New(isolate, MyWheelsMethodCallback)->GetFunction();
 )

上面的代碼將會(huì)使所有的 biketemplate 實(shí)例擁有一個(gè) wheels 方法。當(dāng)該方法被調(diào)用時(shí),C++ 函數(shù) MyWheelsMethodCallback 就會(huì)執(zhí)行。

V8 的 FunctionTemplate 類提供了一個(gè)公開成員函數(shù) Inherit() ,當(dāng)你想要一個(gè)函數(shù)模板繼承于另一個(gè)函數(shù)模板時(shí),你可以使用它,例子:

void Inherit(Local parent);
最后

原文鏈接:https://developers.google.com/v8/embed

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/86366.html

相關(guān)文章

  • 」JavaScript 究竟是如何工作的?(第一部分)

    摘要:文章的第二部分涵蓋了內(nèi)存管理的概念,不久后將發(fā)布。的標(biāo)準(zhǔn)化工作是由國際組織負(fù)責(zé)的,相關(guān)規(guī)范被稱為或者。隨著分析器和編譯器不斷地更改字節(jié)碼,的執(zhí)行性能逐漸提高。 原文地址:How Does JavaScript Really Work? (Part 1) 原文作者:Priyesh Patel 譯者:Chor showImg(https://segmentfault.com/img...

    Youngdze 評(píng)論0 收藏0
  • JavaScript 工作原理之二-如何在 V8 引擎中書寫最優(yōu)代碼的 5 條小技巧()

    摘要:本章將會(huì)深入谷歌引擎的內(nèi)部結(jié)構(gòu)。一個(gè)引擎可以用標(biāo)準(zhǔn)解釋程序或者即時(shí)編譯器來實(shí)現(xiàn),即時(shí)編譯器即以某種形式把解釋為字節(jié)碼。引擎的由來引擎是由谷歌開源并以語言編寫。注意到?jīng)]有使用中間字節(jié)碼來表示,這樣就不需要解釋器了。 原文請(qǐng)查閱這里,略有刪減。 本系列持續(xù)更新中,Github 地址請(qǐng)查閱這里。 這是 JavaScript 工作原理的第二章。 本章將會(huì)深入谷歌 V8 引擎的內(nèi)部結(jié)構(gòu)。我們也會(huì)...

    PingCAP 評(píng)論0 收藏0
  • []你并不知道Node

    摘要:問題什么是調(diào)用棧并且它是的一部分么調(diào)用棧當(dāng)然是的一部分。為什么理解是重要的因?yàn)槟阍诿總€(gè)進(jìn)程中只能獲取一個(gè)調(diào)用棧。它是一個(gè)從事件隊(duì)列中跳去事件的循環(huán)并且將它們的回調(diào)壓入到調(diào)用棧中。當(dāng)調(diào)用棧為空的時(shí)候,事件循環(huán)可以決定下一步執(zhí)行哪一個(gè)。 你并不知道Node 原文:You don’t know Node 譯者:neal1991 welcome to star my articles-tra...

    miqt 評(píng)論0 收藏0
  • [] Node.js 架構(gòu)概覽

    摘要:文件系統(tǒng)請(qǐng)求和相關(guān)請(qǐng)求都會(huì)放進(jìn)這個(gè)線程池處理其他的請(qǐng)求,如網(wǎng)絡(luò)平臺(tái)特性相關(guān)的請(qǐng)求會(huì)分發(fā)給相應(yīng)的系統(tǒng)處理單元參見設(shè)計(jì)概覽。 譯者按:在 Medium 上看到這篇文章,行文脈絡(luò)清晰,闡述簡明利落,果斷點(diǎn)下翻譯按鈕。第一小節(jié)背景鋪陳略啰嗦,可以略過。剛開始我給這部分留了個(gè) blah blah blah 直接翻后面的,翻完之后回頭看,考慮完整性才把第一節(jié)給補(bǔ)上。接下來的內(nèi)容干貨滿滿,相信對(duì) N...

    antyiwei 評(píng)論0 收藏0
  • [] JavaScript 性能優(yōu)化殺手

    摘要:原文引言這篇文檔包含了如何避免使代碼性能遠(yuǎn)低于預(yù)期的建議尤其是一些會(huì)導(dǎo)致牽涉到等無法優(yōu)化相關(guān)函數(shù)的問題一些背景在中并沒有解釋器但卻有兩個(gè)不同的編譯器通用編譯器和優(yōu)化編譯器這意味著你的代碼總是會(huì)被編譯為機(jī)器碼后直接運(yùn)行這樣一定很快咯并不是 原文:http://dev.zm1v1.com/2015/08/19/javascript-optimization-killers/引言 這篇文檔包...

    MockingBird 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<