【问题标题】:OO Javascript: use of prototype and callOO Javascript:原型的使用和调用
【发布时间】:2013-04-01 23:51:12
【问题描述】:

我有这个代码:

function Stickman() {
    //some methods and properties

}

function JuniorStickman() {
    Stickman.call(this);
    this.p = new value // override a property in Stickman

}
JuniorStickman.prototype = new Stickman();

junior = new JuniorStickman();

我根据 MDN 上的示例改编了这段代码:https://developer.mozilla.org/en-US/docs/JavaScript/Introduction_to_Object-Oriented_JavaScript

我不明白的是:call() 和行

JuniorStickman.prototype = new Stickman() 

似乎做同样的事情。如果我注释掉这一行

JuniorStickman.prototype = new Stickman();

我的 JuniorStickman 仍然具有 Stickman 的所有方法和属性;真的;他的原型属性现在是 JuniorStickman 而不是 Stickman,但这似乎并不重要。

在这里调用如何使我的 Junior Stickman(初级)拥有 Stickman 的所有方法,是否需要原型分配?

据我了解, call() 并没有真正给我继承权。我只是得到一种 Stickman 的副本,我可以在其中添加/覆盖属性。这个对吗?

【问题讨论】:

  • “如何在这里调用工作以使我的初级火柴人(初级)拥有火柴人的所有方法”---通过分配。您将实例分配为原型。

标签: javascript oop call prototype


【解决方案1】:

这里的调用如何让我的初中火柴人拥有火柴人的所有方法

您在代码中的注释似乎表明您正在设置 Stickman 构造函数中的所有属性(也是方法)。因此,如果您调用 Stickman 并将 this 显式设置为新的 JuniorStickman 实例 (Stickman.call(this);),则所有分配给 thisStickman 内的属性都会分配给新实例。

.call [MDN] 所做的只是在函数内部设置this 以引用第一个参数。示例:

function foo() {
    alert(this.bar);
}

foo.call({bar: 42}); // alerts 42
foo.call({bar: 'baz'}); // alerts baz

那么为什么在这里使用.call?它与在其他语言中调用super() 的作用相同:它在新的子实例上执行父构造函数。

原型分配是否必要

这不是你的情况。但通常您将所有应该跨实例共享的属性分配给函数的原型,即Stickman.prototype。例如,方法通常分配给原型。只有特定每个实例的属性才应该在构造函数中分配。

如果您不执行此分配,JuniorStickman 的实例将没有分配给 Stickman.prototype 的任何方法,因为它不在实例的原型链中。


FWIW,通过将父级的新实例分配给原型来设置继承并不是最佳方式。如果Stickman 需要强制 参数怎么办?你会通过哪些?

此时你不想创建一个新的Stickman 实例,你想要的只是将Stickman.prototype 带入原型链。这可以使用Object.create [MDN] 轻松完成:

JuniorStickman.prototype = Object.create(Stickman.prototype);

【讨论】:

  • 好的。这一切都很清楚。如果我使用原型属性正确设置 Stickman 而不是将方法和属性放在构造函数中,那么我需要进行原型分配。谢谢。您的回答实际上为我清除了很多关于 OO Javascript 的信息。
【解决方案2】:

如果你的 Stickman() 构造函数为每个新实例做不同的事情(假设它设置一个属性等于它创建的时间),那么你会希望 JuniorStickman() 的每个实例调用 Stickman()构造函数,而不是依赖于您调用 Stickman() 设置原型时存储在原型中的时间戳。

例如:

function a() {
    this.time = new Date().getTime();
}

function b() {
    // a.call(this)
    this.hello = "something";
}

b.prototype = new a();

注释掉该行后,每个新 b() 的时间戳都是相同的,但如果您取消注释该行,它们的行为将按照您的意愿行事。

【讨论】:

  • 这有助于解释何时使用原型属性和何时将方法和属性放入构造函数之间的区别。谢谢。
【解决方案3】:

JavaScript 原型就像子类。但是“子”对象的所有实例都继承了一个父实例。更改的复杂值会针对所有子实例进行更改。

当使用 parent.call(thisContext) 时,在父函数体中用 this.somevar 声明的父变量将对子实例变得唯一,因为它们被初始化为子实例的 this 上下文。 当你只有 parent.call(this 那么孩子不会是父母的一个实例,所以:

(child instanceof parent) 如果你只使用 parent.call(this

将会是假的
function parent(){
  this.arr=[];
  this.name="parent";
}
function child1(){
 parent.call(this);//sets all this elements 
                   //of parent to the current 
                   // instance of child1
}
child1.prototype = new parent();
function child2(){
}
child2.prototype = new parent();
var c1=new child1();
c1.name="c1"
c1.arr.push(["c1"]);
var anotherc1=new child1();
anotherc1.name="another c1";
anotherc1.arr.push("another c1");
var c2 = new child2();
c2.name="c2";
c2.arr.push(["c2"]);
var anotherc2 = new child2();
anotherc2.name="another c2";
anotherc2.arr.push(["another c2"]);
console.log(c1.name,c1.arr);//["c1"]
console.log(anotherc1.name,anotherc1.arr);//["anotherc1"]
console.log(c2.name,c2.arr);//["c2","anotherc2"]
console.log(anotherc2.name,anotherc2.arr);//["c2","anotherc2"]
console.log(c1 instanceof parent);//true

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-02-22
    • 1970-01-01
    • 1970-01-01
    • 2010-10-08
    • 1970-01-01
    • 2015-09-14
    • 1970-01-01
    • 2011-08-19
    相关资源
    最近更新 更多