Javascript私有/公共继承语法

时间:2013-11-20 02:11:48

标签: javascript inheritance

我无法在Javascript中将私有/公共方法与继承相结合。我认为这只是我的一个误解,希望能够轻松解决。

这就是我所拥有的:

RB = {};
RB.Fruit = function() {
    // Public
    this.getType = function() {
        return "FRUIT";
    }
}

RB.Orange = function() {

    // Private
    function makeOrangeJuice() {
        console.log("Orange has been squeezed.");
    }

    // Public
    return {
        getName : function() {
            return "Orange";
        }
    }
}
RB.Orange.prototype = new RB.Fruit();
var o = new RB.Orange();
console.log(o.getType());

当我运行此代码时,我收到错误“Uncaught TypeError:Object#have method'getType'”。我知道它与在类函数中使用“return”有关(因为将getName方法移出“return”块允许它工作),但是我想继续能够声明private /类中的公共方法。

如何修改此选项以允许RB.Orange访问RB.Fruit.getType函数?

谢谢!

6 个答案:

答案 0 :(得分:2)

在JavaScript中,构造函数调用隐式返回新构造的实例构造函数可以通过显式返回不同的对象来覆盖该默认行为。例如,如果您像这样定义“构造函数”Foo

function Foo() {
    return new Date();
}

然后语句foo = new Foo()会将foo设置为新的Date而不是新的Foo

如果我理解你想要什么,你只需要改变它:

    return {
        getName : function() {
            return "Orange";
        }
    }

(由此你的“构造函数”返回一个完全新鲜的对象,只有getName方法,并且与正在构造的对象无关):

    this.getName = function() {
        return "Orange";
    };

(通过它向正在构造的对象添加getName方法,并且仍允许返回该对象。

答案 1 :(得分:2)

主要问题

当您从构造函数返回非原始值时,将返回非原始值,而不是默认返回的实例,您希望使用new关键字调用它。

E.g。

function A() { return {}; }
new A() instanceof A; //false

因此,您只需将代码更改为:

RB.Orange = function() {

    // Private
    function makeOrangeJuice() {
        console.log("Orange has been squeezed.");
    }

    this.getName = function ()  {
        return 'Orange';
    };

    //priviledged function which uses a private member
    this.someOtherFunction = function () {
        makeOrangeJuice();
    };
};

代码中的一些低效率

为什么不使用prototype

不应在构造函数中声明非特权的函数。换句话说,不应该在构造函数中创建不访问私有变量的函数,因为它们不必这样做,并且这样做非常低效。为什么?因为每次调用构造函数时都会创建新函数

相反,您应该使用Constructor.prototype在所有实例之间共享您的公共功能。

E.g。

function Person(name) {
    this.name = name;
}

Person.prototype.sayName = function () {
    console.log('My name is ' + this.name);
};

new Person('Foo Bar').sayName();

尽可能使用Object.create而不是new继承。

使用new关键字的大多数继承模式都是这样做的,因为语言缺少另一种设置对象原型链的方法,但现在我们有Object.create,你应该使用它。使用new关键字进行继承的方式有一些不受欢迎的副作用,比如运行构造函数。有一些方法可以通过使用中间空函数来避免这些副作用,但为什么不简单地使用Object.create

E.g。 (基于上面的例子)

function BadPerson(name) {
    //call parent constructor
    Person.call(this, name + ' the bad');
}

BadPerson.prototype = Object.create(Person.prototype);
BadPerson.prototype.constructor = BadPerson; //fix constructor

也可以共享私人功能!

请注意,也可以共享不访问私有变量的私有函数。您可以使用模块模式为它们创建范围。

E.g。

var Person = (function () {

    //private function used in a functionnal style
    function _validateName(name) {
        console.log('Validating the name in functionnal style');
    }

    //private function used in an OO style
    function _validateNameOO() {
        console.log('Validating the name in a OO style');
    }

    function Person(name) {
        this.name = name;
    }

    Person.prototype.validateNameBothWays = function () {
        _validateName(this.name);

        _validateNameOO.call(this);
    };

    return Person;
})();

new Person().validateNameBothWays();

答案 2 :(得分:1)

如果您希望将这些函数继承,则需要将这些函数分配给对象的原型。

RB = {};
RB.Fruit = function() {};
RB.Fruit.prototype.getType = function() {
    return 'Fruit';
};

RB.Orange = function() {};
RB.Orange.prototype = new RB.Fruit();
RB.Orange.prototype.getName = function() {
    return 'Orange';
};

如果你真的需要使用私有,并且不能只使用_name之类的约定将事物标记为私有,那么你需要将使用私有的函数移动到私有成员的构造函数中。

如果它们不是特定于实例的,那么你可以(并且应该)使用即时功能包装整个事物。

(function() {
    // All previous code here

    window.RB = RB;
}());

答案 3 :(得分:1)

以下显示了如何实现共享私有成员以及放置特权方法的位置(可以访问共享私有方法的方法);

我从未发现这种模式有多大用处,并且通常表示一个名为_aPrivate的私有私有,正如Phillip在他的回答中已经解释过的那样。

有关构造函数,原型,继承和this点击here的价值的介绍。

RB = {};
RB.Fruit = function() {
}
// Public
RB.Fruit.prototype.getType = function() {
  return "FRUIT";
};

RB.Orange = function() {
  //inherit instance specific values of Fruit (there are none but there might be)
  RB.Fruit.apply(this,arguments);
};
//inherit shared members from the prototype of Fruit
RB.Orange.prototype = Object.create(RB.Fruit.prototype);
//repair constructor to be Orange instead of Fruit
RB.Orange.prototype.constructor = RB.Orange;
//shared privates and privileged methods (methods that can access the privates)
// go in the following IIFE function body.
(function(){
    //private version of makeOrangeJuice
    var makeOrangeJuice = function () {
      //the value of 'this' here isn't the Orange instance
      //if you need it then pass it with the public version of
      //makeOrangeJuice or use makeOrangeJuice.call(this) in the
      //public version
      console.log("Orange has been squeezed.");
    };
    //public version of makeOrangeJuice
    RB.Orange.prototype.makeOrangeJuice=function(){
      //call private makeOrangeJuice function
      makeOrangeJuice();
    }
}());
//non privileged member, in getName the private version of makeOrangeJuice
//doesn't exist you can call the public version with this.makeOrangeJuice
RB.Orange.prototype.getName = function() {
 return "Orange";
};
var o = new RB.Orange();
console.log(o.getType());
o.makeOrangeJuice();

答案 4 :(得分:0)

这是你可以做到的一种方式:

var RB = {};
RB.Fruit = function() {
    // Public
    this.getType = function() {
        return "FRUIT";
    }
}

RB.Orange = function() {
    // Private variable
    var fruit = new RB.Fruit();

    // Private function
    function makeOrangeJuice() {
        console.log("Orange has been squeezed.");
    }

    // Public object with accessor
    return {
        getName : function() {
            return "Orange";
        },
        getType: fruit.getType
    }
}

var o = new RB.Orange();
console.log(o.getType());

答案 5 :(得分:0)

试试这段代码。

RB = {};
RB.Fruit = function() {
    // Public
    this.getType = function() {
        return "FRUIT";
    }
}
RB.Fruit.prototype.getType = function() {
        return "FRUIT";
    };
RB.Orange = function() {
    RB.Fruit.call(this);
    // Private
    function makeOrangeJuice() {
        console.log("Orange has been squeezed.");
    }

    this.getName = function() {
            return "Orange";
        };
    this.getJuice = function(){
            makeOrangeJuice();
        };

};
var o = new RB.Orange();
//calling the super-call's function
console.log(o.getType());
//public function
o.getJuice();
//trying to access private function
o.makeOrangeJuice();

有关面向代码对象的更多详细信息请访问以下链接 http://mckoss.com/jscript/object.htm