像Java一样,Object.call也应该是Javascript构造函数中的第一个调用吗?

像Java一样,Object.call也应该是Javascript构造函数中的第一个调用吗?,javascript,oop,inheritance,constructor,Javascript,Oop,Inheritance,Constructor,我正在用Javascript编写一些OOP代码,继承的设计提出了一个问题。像Java一样,超级构造函数调用应该是Javascript子类构造函数的第一行吗 var Effect = function (container, height, width) {}; var XEffect = function (container, height, width, resource) { Effect.call(container, height, width ); // really ne

我正在用Javascript编写一些OOP代码,继承的设计提出了一个问题。像Java一样,超级构造函数调用应该是Javascript子类构造函数的第一行吗

var Effect = function (container, height, width) {};

var XEffect = function (container, height, width, resource) {
    Effect.call(container, height, width ); // really necessary to be first line?
};

引用道格拉斯·克罗克福德的话:“JavaScript有一个无类对象系统,其中对象直接从其他对象继承属性。这是非常强大的,但是对于受过经典训练的程序员来说,这是不熟悉的。如果您试图将经典设计模式直接应用于JavaScript,您会感到沮丧。但如果你学会使用JavaScript的原型性质,你的努力就会得到回报。”

查看JavaScript中如何处理继承


在您的代码片段中,
Effect.call(container,height,width);
将作为
undefined
计算,除非您事先明确定义它。要调用
Effect
函数的功能,只需将其作为
Effect()
调用,引用Douglas Crockford:“JavaScript有一个无类对象系统,其中对象直接从其他对象继承属性。这是非常强大的,但是对于受过经典训练的程序员来说,这是不熟悉的。如果您试图将经典设计模式直接应用于JavaScript,您会感到沮丧。但如果你学会使用JavaScript的原型性质,你的努力就会得到回报。”

查看JavaScript中如何处理继承


在您的代码片段中,
Effect.call(container,height,width);
将简单地计算为
undefined
,除非您事先明确定义它。要调用
Effect
函数的功能,只需将其作为
Effect()调用即可我不喜欢用Java和C++语言实现的面向对象系统。我最喜欢的面向对象系统是由java实现的。例如,考虑下面的堡垒代码,它是由(A.K.A.大Quux)编写的著名博客文章:

Fortress中的对象定义引入对象构造函数。这些构造函数可以是空的(例如
EmptyObject
),也可以是参数化的(例如
AdjoinObject
UnionObject

trait类似于。因此,您不能直接创建trait的实例。相反,您需要创建一个实现trait接口的具体对象

请注意,在这个场景中,您永远不需要调用超类构造函数,因为没有超类构造函数是抽象的。它们没有状态,因此不需要初始化。对象的状态封装在对象构造函数中。这很重要,因为它促进了面向对象程序的一个重要属性

那么这个堡垒代码在JavaScript中会是什么样子呢? 用JavaScript编写面向对象代码的方法有很多。但是,我最喜欢的是以下堡垒式的面向对象JavaScript代码:

class IntSet{
get isEmpty(){return false;}
邻接(x){返回邻接对象(this,x);}
联合(其他){return UnionObject(this,other);}
包含(y){抛出新错误(“抽象方法调用”);}
}
const AdjoinObject=(s,x)=>新类扩展了IntSet{
包含(y){返回y==x | | s.contains(y)}
}
const UnionObject=(s1,s2)=>新类扩展了IntSet{
get isEmpty(){返回s1.isEmpty&&s2.isEmpty;}
contains(y){返回s1.contains(y)| s2.contains(y)}
}
const EmptyObject=新类扩展了IntSet{
get isEmpty(){return true;}
包含(y){return false;}
}
const Empty=EmptyObject;
const-example=Empty.adjoin(1).adjoin(2).并集(Empty.adjoin(3));
console.log(example.contains(1));//true
console.log(example.contains(2));//true
console.log(example.contains(3));//true

控制台。log(示例。包含(4));//false < /COD> > P>个人,我不喜欢用Java和C++语言实现的面向对象系统。我最喜欢的面向对象系统是由.java实现的。 Fortress中的对象定义引入对象构造函数。这些构造函数可以是空的(例如
EmptyObject
),也可以是参数化的(例如
AdjoinObject
UnionObject

trait类似于。因此,您不能直接创建trait的实例。相反,您需要创建一个实现trait接口的具体对象

请注意,在这个场景中,您永远不需要调用超类构造函数,因为没有超类构造函数是抽象的。它们没有状态,因此不需要初始化。对象的状态封装在对象构造函数中。这很重要,因为它促进了面向对象程序的一个重要属性

那么这个堡垒代码在JavaScript中会是什么样子呢? 用JavaScript编写面向对象代码的方法有很多。但是,我最喜欢的是以下堡垒式的面向对象JavaScript代码:

class IntSet{
get isEmpty(){return false;}
邻接(x){返回邻接对象(this,x);}
联合(其他){return UnionObject(this,other);}
包含(y){抛出新错误(“抽象方法调用”);}
}
const AdjoinObject=(s,x)=>新类扩展了IntSet{
包含(y){返回y==x | | s.contains(y)}
}
const UnionObject=(s1,s2)=>新类扩展了IntSet{
get isEmpty(){返回s1.isEmpty&&s2.isEmpty;}
contains(y){返回s1.contains(y)| s2.contains(y)}
}
const EmptyObject=新类扩展了IntSet{
get isEmpty(){return true;}
包含(y){return false;}
}
const Empty=EmptyObject;
常数examp
trait IntSet
  getter isEmpty(): Boolean = false
  adjoin(x: ZZ): IntSet = AdjoinObject(self, x)
  union(other: IntSet): IntSet = UnionObject(self, other)
  contains(y: ZZ): Boolean
end

object AdjoinObject(s: IntSet, x: ZZ) extends IntSet
  contains(y: ZZ) = (y = x) OR: s.contains(y)
end

object UnionObject(s1: IntSet, s2: IntSet) extends IntSet
  isEmpty: Boolean = s1.isEmpty AND s2.isEmpty
  contains(y: ZZ) = s1.contains(y) OR: s2.contains(y)
end

object EmptyObject extends IntSet
  isEmpty: Boolean = true
  contains(y: ZZ) = false
end