جافاسكريبت - لماذا يعيد عامل التشغيل `instanceof` القيمة false عند تمرير مثيل إلى مكتبة؟ (لا يوجد توريث متورط)
أنا أبني مكتبة باستخدام TS. تستخدم هذه المكتبة مكتبة ssh2 كاعتماد.
أحاول إنشاء دالة يمكنها قبول إما كائن تكوين ssh2 أو نسخة Client موجودة بالفعل لتنفيذ أمر (هذه حالة مبسطة):
import { Client, ConnectConfig } from 'ssh2';
export function runCommand(params: Client | ConnectConfig) {
if(params instanceof Client) {
// do something
} else {
// create our own client
// do something
}
}
عندما أبني هذه المكتبة وأستدعي الدالة هكذا:
const { readFileSync } = require("fs");
const { Client } = require("ssh2");
const { runCommand } = require("myLib");
const conn = new Client();
conn
.on("ready", () => {
console.log("Client :: ready");
runCommand(conn);
})
.connect({
host: "example.com",
port: 22,
username: "me",
privateKey: readFileSync(process.env.HOME + "/.ssh/id_ed25519"),
});
سيُرجع التحقق باستخدام instanceof في دالتي false لسبب ما. ما الذي يحدث بالضبط هنا؟ هل هي مشكلة في تجميع TypeScript أم أن Node.js يرى Client من تبعية مكتبتي وتبعية كود المستهلك الخاص بي كفئتين مختلفتين؟
يبدو الكود المجمّع شيئًا مثل:
const ssh2_1 = require("ssh2");
//...
function runCommand(params) {
if (params instanceof ssh2_1.Client) {
// do something
}
else {
// create our own client
// do something
}
}
الإجابة رقم 1
ما قد لا يكون واضحًا من سلوك عامل instanceof هو أن الفئة يجب أن تكون بالضبط في سلسلة الوالد، بمعنى مرجع كائن جافاسكريبت reference.
لذلك، إذا قمت باستيراد فئة Client مرتين، فهي مراجع كائن فعلية مختلفة، وقد يعطي instanceof نتيجة "false" سلبية.
من المحتمل جدًا أن هذا ما يحدث هنا: ssh2 مضمّن مع مكتبتك، ومن ثم يستورد نسخته الخاصة من التبعية. في حين أن تطبيقك يستورد ssh2 بمفرده، مما يؤدي إلى وجود نسخة منفصلة.
لديك بضع خيارات:
- لا تقم بضم الاعتماديات مع مكتبتك (على سبيل المثال باستخدام webpack
externals)، دع التطبيق يقوم بتثبيت نسخة واحدة ستقوم كل من مكتبتك والتطبيق باستيرادها؛ حالة نموذجية لتحديدpeerDependencies - لا تستخدم العامل
instanceof؛ بدلاً من ذلك، استخدم بعض الأساليب الحدسية لتحديد ما إذا كان الكائن له الشكل الذي تحتاجه؛ عادةً تحقق من بعض الخصائص ونوعها - أعد تصدير التبعية (على سبيل المثال
Clientفي حالتك) من مكتبتك، واستخدمها في تطبيقك (const { Client, runCommand }=require("myLib");)، بحيث تكون النسخة هي نفسها بالضبط (نظرًا لأنها مُجمعة بالفعل، لماذا لا نعيد استخدامها بدلًا من إعادة تجميعها؟)