كيف يقوم ClojureScript بتجميع عمليات الإغلاق؟
-
14-11-2019 - |
سؤال
عند استخدام ClojureScript حاولت تعريف دالة تكون بمثابة إغلاق لمتغير مثل هذا:
(let [x 42]
(defn foo [n] (+ x n)))
يقوم بطباعة المصدر التالي في Rhino REPL:
function foo(n){
return cljs.core._PLUS_.call(null,x__43,n);
}
تعمل الوظيفة كما أتوقع ولكن عند محاولة الوصول إلى المتغير المسمى x__43
لا أستطيع الحصول عليه.اين ذهبت؟
المحلول
(let [x 42]
(defn foo [n] (+ x n)))
يتم تجميعها حاليا ل
var x__1311 = 42;
cljs.user.foo = (function foo(n){
return (x__1311 + n);
});
الرقم الدقيق المرفق x
قد تختلف بالطبع من تجميع إلى تجميع و cljs.user
سيتم استبداله باسم مساحة الاسم المناسب.
لا توجد محاولة لإخفاء المتغير الذي تم إنشاؤه من تعليمات برمجية غير ذات صلة في إغلاق JavaScript، لذلك من حيث المبدأ لا يزال من الممكن تعديله إذا بذل المرء قصارى جهده للقيام بذلك.من المستبعد جدًا حدوث تصادمات عرضية ولن تحدث ببساطة مع ClojureScript العادي.
لاكتشاف أشياء مثل ما سبق، يمكنك إما استدعاء المترجم باستخدام {:optimizations :simple :pretty-print true}
من بين الخيارات أو اطلب منه إصدار بعض JavaScript في ملف REPL (كما هو منصوص عليه في script/repl
في شجرة المصدر ClojureScript أو lein repl
في مشروع Leiningen مع إعلان ClojureScript باعتباره تبعية):
(require '[cljs.compiler :as comp])
(binding [comp/*cljs-ns* 'cljs.user]
(comp/emit
(comp/analyze {:ns {:name 'cljs.user} :context :statement :locals {}}
'(let [x 42] (defn foo [n] (+ x n))))))
نصائح أخرى
يتم تعريف المتغير x خارج الدالة foo، في الرابط Let.لا يمكنك "الحصول عليه" لأنك لست ضمن نطاق السماح بالربط.هذا هو الهدف الأساسي من استخدام عمليات الإغلاق.
من الناحية النظرية، دع الارتباطات يتم تنفيذها كاستدعاءات دالة:
(let [x 2] ...)
يعادل
((fn [x] ...) 2)
الذي من المحتمل مشابه ل let
يتم تنفيذه في ClojureScript - إما كتحويل ماكرو إلى fn
أو مباشرة إلى (function(x){...})(2)
.