Nodejs中一个奇怪的javascript extend问题
Nodejs中一个奇怪的javascript extend问题
代码在这里:
http://jsbin.com/xabowoyihawe/1/edit?js,console
问题: 为什么noop.name可以取到值而noop.title是undefined?而name和title都是在noop.prototype中的
function noop() { }
function _extend(source, obj) {
for (var prop in source) {
if(!obj.prototype[prop]) {
obj.prototype[prop] = source[prop]
}
}
return obj
}
noop.prototype[“name”] = ‘noop’
_extend({“title”:“sometitle”}, noop)
var n = new noop()
console.log( noop.name, noop.title, noop.prototype.name, noop.prototype.title, noop.prototype)
console.log( n.name, n.title)
Node.js 中一个奇怪的 JavaScript extend
问题
背景
在 Node.js 中,我们经常需要扩展对象的功能。使用 extend
函数可以帮助我们将一个对象的属性复制到另一个对象的原型上。然而,在某些情况下,这种操作可能会导致一些意外的行为。
问题描述
在这个例子中,我们定义了一个名为 noop
的函数,并使用 _extend
函数尝试将一个包含 name
和 title
属性的对象扩展到 noop
函数的原型上。尽管 name
和 title
都被添加到了 noop.prototype
中,但当我们创建一个新的 noop
实例并访问这些属性时,只有 name
可以正确地获取到值,而 title
却是 undefined
。
示例代码
function noop() { }
function _extend(source, obj) {
for (var prop in source) {
if (!obj.prototype[prop]) {
obj.prototype[prop] = source[prop];
}
}
return obj;
}
// 直接设置 name 属性到 prototype
noop.prototype["name"] = 'noop';
// 使用 _extend 方法扩展 title 属性
_extend({ "title": "sometitle" }, noop);
// 创建新的 noop 实例
var n = new noop();
// 输出结果
console.log(noop.name, noop.title, noop.prototype.name, noop.prototype.title, noop.prototype);
console.log(n.name, n.title);
分析
让我们详细分析一下代码执行的步骤:
-
直接设置
name
属性:noop.prototype["name"] = 'noop';
这行代码直接将
name
属性添加到noop.prototype
上。 -
使用
_extend
方法扩展属性:_extend({ "title": "sometitle" }, noop);
这里
_extend
函数遍历传入的对象,并将其属性添加到noop.prototype
上。但是由于noop.prototype
已经有一个name
属性,因此_extend
函数不会覆盖它。 -
创建新的
noop
实例:var n = new noop();
当我们创建一个新的
noop
实例时,该实例的原型链指向noop.prototype
。 -
输出结果:
noop.name
是'noop'
,因为我们在noop.prototype
上直接设置了name
。noop.title
是undefined
,因为在_extend
函数中,我们检查了obj.prototype[prop]
是否存在,如果存在则不进行赋值。n.name
是'noop'
,因为n
继承自noop.prototype
。n.title
是undefined
,因为_extend
函数没有覆盖已经存在的name
属性。
解决方案
为了避免这种情况,可以在 _extend
函数中去掉对现有属性的检查:
function _extend(source, obj) {
for (var prop in source) {
obj.prototype[prop] = source[prop]; // 移除检查
}
return obj;
}
通过这种方式,_extend
函数会覆盖 noop.prototype
上已有的属性,从而确保所有属性都被正确地继承到新实例中。