在JavaScript的原型链继承方式中,为什么子类在调用父类的构造函数时不能传参数?

教程上说子类的构造函数需要父类的实例作为自己的prototype,但在调用父类的构造函数时参数列表必须为空,请问这是为什么?我试了一下传参,没有出现问题,参数也能正确起作用。希望高人解答!

我认为,不是不能给父类构造函数传参数,而是传的参数最终不能起到作用。举个例子:

function Parents(ln) { this.lastName=ln; } //定义父类构造函数
function Children(fn,ln) { this.firstName=fn; } //定义子类,lastName 继承自父类
//原型链继承,给父类构造函数传入参数,试图用 Children 类构造函数中传入的 ln 初始化 lastName:
Children.prototype=new Parents(this ln);
//尝试建立对象实例:
var child=new Children("Bill","Gates");
//输出结果。很明显,lastNmae 并没有得到想要的值:
alert(child.firstName);//Bill
alert(child.lastName);//Undefine

这说明给父类构造函数传递参数是无效的。原因就在于原型链方式中,调用父类构造函数的代码并不在子类构造函数中,建立对象实例时给的属性值(即子类构造函数的参数)并不能影响到子类调用的父类构造函数。
当然,在继承时可以这样写:

Children.prototype=new Parents("Gates");//调用父类构造函数时给固定值

但是,这个固定的属性值必定会影响所有子类的对象实例,相当于子类构造函数“擅作主张”给所有对象实例的属性提前“赋了值”。这样写是不太符合面向对象编程的规则的。
温馨提示:答案为网友推荐,仅供参考
第1个回答  推荐于2017-11-25
以前我在看书时也遇到过这样的问题,找了很多资料都没有明确的解释。
我觉得,并不是语法上不能实现对构造函数的参数传递,而是这样做不符合面向对象编程的规则:对象(实例)才是属性的拥有者。
如果在子类定义时就将属性赋了值,对象实例就不能再更改自己的属性了。这样就变成了类拥有属性,而不是对象拥有属性了。
举个例子,子类 Children 继承父类 Parents,Parents 构造函数:
function Parents(name){ this.name=name; }
使用原型链并给父类构造函数传参数:
Children.prototype=new Parents("Hello");
那么此时,Children 类就拥有了 name=“Hello” 属性,而 Children 类的实例对象 c1、c2、c3 等等只能被迫接受这个 name 属性。Children 是 "Hello" 的拥有者而 c1、 c2、c3不是!
如此写完全失去了面向对象编程的意义,所以在原型链继承方式中规定不能对父类构造函数传递参数。也因为这个原因,原型链继承方式并不实用。本回答被提问者采纳
第2个回答  2017-08-19

WANGERN 的答案很有启发, 我接着他回答, 我也是新手, 这只是我的理解, 希望牛人来指正:

并不是语法上不能实现对构造函数的参数传递,而是这样做不符合面向对象编程的规则:对象(实例)才是属性的拥有者。如果在子类定义时就将属性赋了值,就变成了类拥有属性,而不是对象拥有属性了。 举个例子,

function Parent(name){ this.name=name;}
function Child(age){this.age=age;}
Child.prototype=new Parent("Hello");
var c1= new Child(1);
alert(c1.age+'...'+c1.name);

此时Child类是"Hello"的拥有者, 而Child类的实例对象c1不是. 如此写完全失去了面向对象编程的意义. 但是在"避免类拥有属性值"这一前提下, 还是可以这样修改的:

function Parent(name){this.name=name;}
function Child(age){this.age=age;}
Child.prototype = new Parent();
var c1= new Child(1);
c1.name='Hello';
alert(c1.age+'...'+c1.name);

显然这样的代码也不够优雅, 因为需要初始化之后再设置name值, 代码被打散了. 于是自然想到将 Child 的实例化封装成函数.

function Parent(name){this.name=name;}
function Child(age){this.age=age;}
function createChild(age, name){
  Child.prototype = new Parent();
  var c=new Child(age);
  c.name=name;
  return c;
}
var c1= createChild(1, 'Hello');
alert(c1.age+'...'+c1.name);

可是, 本来规范的 new Child(name,age) 书写变成了 createChild(age, name), 代码还是不优雅. 于是就有了 "对象冒充+原型链继承" 的 "组合模式":

function Parent(name) {this.name = name;}
function Child(age,name){Parent.call(this,name);this.age=age;}
Child.prototype = new Parent();
var c1= new Child(1, 'Hello');
alert(c1.age+'...'+c1.name);

代码变得优雅了一些. 但也不是绝对. 所以, 因为JavaScript语法的灵活(不伦不类), 事实上继承的实现方式有很多, 也并不存在绝对无法传参数的问题, 只不过组合模式代码相对优雅, 而广泛采用. 说到底, 对象冒充一开始也不是ECMAScript官方认定的继承方式. 此问题本身就是灰色地带.

相似回答