这个 JavaScript class 示例适合作为新的 placeholder 吗?
这段代码可以作为练习起点,用来介绍 class 前建议做些修改。它展示了类的声明、构造函数和方法调用,但 join() 没有用到构造函数保存的数据,读者不容易看出实例属性与方法之间的关系。
如果这里的 placeholder 指教学用的占位示例,可以根据讲解目标自行设计。foo、bar 或 a、b 都只是示例名称。介绍类时,选用含义明确的名称,更方便解释对象代表什么。
原示例有哪些问题?
实例保存的数据没有参与后续操作:
const ball = new test("Dog", "Cat");
ball.join(["Hello", "World!"]); // 返回 "Hello World!"
"Dog" 和 "Cat" 分别保存在 ball.a、ball.b 中,join() 却只处理传入的数组。换一个实例,只要传入相同数组,结果就一样。当前的 join() 用普通函数也能实现,因此这个例子没能充分说明创建实例的用途。
数组检查也增加了学习负担。初学者需要同时理解 Array.isArray()、every()、箭头函数和 typeof,容易把注意力放在参数校验上。
命名也可以更清楚。class test 的语法合法,不过类名通常采用 PascalCase,例如 Greeting。ball、a、b 这些名称与字符串拼接的用途没有明显联系,读者很难从名称理解它们的含义。
怎样改成更清楚的 class 入门示例?
可以保留拼接两个字符串的功能,做以下调整:
- 给类和属性取有含义的名称。
- 在构造函数中保存每个实例的数据。
- 让方法读取这些属性,并展示不同实例的结果。
class Greeting {
constructor(first = "Hello", second = "World!") {
this.first = first;
this.second = second;
}
join() {
return [this.first, this.second].join(" ");
}
}
const greeting = new Greeting();
const animalGreeting = new Greeting("Dog", "Cat");
console.log(greeting.join()); // "Hello World!"
console.log(animalGreeting.join()); // "Dog Cat"
new Greeting(...) 创建实例并调用 constructor,构造函数中的 this 指向正在初始化的实例。调用 greeting.join() 时,方法通过 this.first 和 this.second 读取该实例的数据。两个实例保存的属性值不同,调用同一个方法会得到不同的结果,实例属性和实例方法的用途也就更容易理解。
这里的接口也发生了变化:join() 拼接的是实例中保存的数据,不再接收待拼接的数组。
默认值和输入校验需要注意什么?
原代码中的写法:
this.a = a || "Hello";
会在 a 为假值时使用 "Hello",包括 ""、0、false、null、undefined 和 NaN。如果允许输入空字符串,这种写法会意外地将它替换掉。
改进后的示例使用默认参数:
constructor(first = "Hello", second = "World!")
只有省略对应实参,或显式传入 undefined 时,默认参数才会生效。传入 "" 或 null 都不会触发默认值。默认参数也不负责类型校验,这个入门示例假定调用者传入字符串。
后续讲到参数校验时,可以单独扩展示例,说明如何处理无效输入。原代码对非数组、包含非字符串元素的数组,以及合法的空数组都返回 "",调用者无法仅凭返回结果区分这些情况。基础教学中,先讲清楚实例数据与方法的关系,再加入校验规则,会更容易理解。
备注:内容仅供参考。
