Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/420.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
用Javascript扩展原型——好方法?_Javascript_Oop_Inheritance_Prototype_Extend - Fatal编程技术网

用Javascript扩展原型——好方法?

用Javascript扩展原型——好方法?,javascript,oop,inheritance,prototype,extend,Javascript,Oop,Inheritance,Prototype,Extend,我想验证我在扩展原型时使用的方法是正确的——假设“extend”是正确的词 这个主题有很多克隆。我仍在努力正确理解这个话题 目的是: -写干净好的代码。 -为了避免使用框架,如果可能,使用纯Javascript。 -获取关于干净框架的建议,这些框架不会扭曲JS以获得支持类的行为 以下是我的沙盒的父原型: function Parent(){ } Parent.prototype = { "init":function(){ this.name = "anon";

我想验证我在扩展原型时使用的方法是正确的——假设“extend”是正确的词

这个主题有很多克隆。我仍在努力正确理解这个话题

目的是: -写干净好的代码。 -为了避免使用框架,如果可能,使用纯Javascript。 -获取关于干净框架的建议,这些框架不会扭曲JS以获得支持类的行为

以下是我的沙盒的父原型:

function Parent(){

}

Parent.prototype = {

    "init":function(){

        this.name = "anon";
    },

    "initWithParameters":function(parameters){

        this.name = parameters.name ? parameters.name : "anon";
    },

    "talk": function(){

        console.log('Parent is: ' + this.name);
    }
}
现在,子原型-它添加了一个“位置”属性并重新定义了行为:

function Child(){

    Parent.call(this);
}


Child.prototype = new Parent;
Child.prototype.constructor = Child;

Child.prototype.init = function(){

    Parent.prototype.call(this);

    this.setPosition(0, 0);
}

Child.prototype.initWithParameters = function(parameters){

    Parent.prototype.initWithParameters.call(this, parameters);

    if(!this.position){

        this.position = {x:0, y:0};
    }

    this.setPosition(parameters.pos.x, parameters.pos.y);
}

Child.prototype.setPosition = function(x, y){

    this.position.x = x;
    this.position.y = y;
}

Child.prototype.talk = function(){

    console.log('Child is: ' + this.name + ' and location is: ' + this.position.x + ', ' + this.position.y);
}
这是一种好的做法吗?在重写属性时,是否没有避免写“Child.prototype.”的速记方法(可能使用literal,就像编写父原型一样)

我知道J.Resig的类/扩展方法。但我宁愿使用Javascript作为它的原型语言,而不是让它作为一种“类行为的无类OO语言”工作


感谢您的帮助:-)

您的方法这是一种很好的纯JavaScript方法。每次给“Child.prototype”小费的唯一办法就是把它放在一个参考变量中

比如:

但你仍然在做这个背后的儿童原型。您还可以定义一个函数来完成此操作,请参见下划线绑定,也许它适合您的需要


干杯

对于这个建议,我可能会非常激动,因为在我的示例中,有几篇文章可能会反对某些做法,但这对我来说很有效,对于外观整洁的代码来说效果很好,保持一致性,缩小规模,在严格模式下运行,并且与IE8兼容

我还喜欢使用原型方法(而不是你随处可见的所有“扩展”或“应用”样式)

我这样写我的课。是的,它看起来很像你不想要的OOP语言,但它仍然遵循原型模型,同时与其他熟悉的语言有相似之处,这使得项目更容易导航

这是我喜欢的风格:)我不是说这是最好的,但它很容易阅读

(function(ns) {

  var Class = ns.ClassName = function() {

  };

  Class.prototype = new baseClass();
  Class.constructor = Class;
  var _public = Class.prototype;
  var _private = _public._ = {};

  Class.aClassProperty = "aValue";

  Class.aClassMethod = function(params) {

  }

  _public.aMethod = function(params) {
      _private.myMethod.call(this, "aParam");
      Class.aClassMethod("aParam");
  }

  _private.myMethod = function(params) {

  }

})({});
编辑:

我继续将您的示例转换为这种样式,只是为了向您展示它的外观:

var namespace = {};

(function(ns) {

    var Class = ns.Parent = function() {

    };

    var _public = Class.prototype;
    var _private = _public._ = {};

    _public.init = function() {
        this.name = "anon";
    }

    _public.initWithParameters = function(parameters) {
        this.name = parameters.name ? parameters.name : "anon";
    }

    _public.talk = function() {
        console.log('Parent is: ' + this.name);
    }

})(namespace);

(function(ns) {

    var Class = ns.Child = function() {
        this.position = {x:0, y:0};
    };

    Class.prototype = new ns.Parent();
    Class.constructor = Class;
    var _public = Class.prototype;
    var _private = _public._ = {};

    _public.init = function() {
        _public.init.call(this);
        this.setPosition(0, 0);
    }

    _public.initWithParameters = function(parameters) {
        _public.initWithParameters.call(this, parameters);
        this.setPosition(parameters.pos.x, parameters.pos.y);
    }

    _public.setPosition = function(x, y) {
        this.position.x = x;
        this.position.y = y;
    }

    _public.talk = function() {
        console.log('Child is: ' + this.name + ' and location is: ' + this.position.x + ', ' + this.position.y);
    }

})(namespace);

一般来说,您的方法可行,但更好的方法是替换:

Child.prototype = new Parent;
与:

这样,您就不需要调用
新父级
,这在某种程度上是一种反模式。您还可以按如下方式直接定义新特性:

Child.prototype = Object.create(Parent.prototype, {
  setPosition: {
    value: function() {
      //... etc
    },
    writable: true,
    enumerable: true,
    configurable: true
  }
});
希望这有帮助


以下是我通常的做法:

使用辅助函数:

/**
 * A clone of the Node.js util.inherits() function. This will require
 * browser support for the ES5 Object.create() method.
 *
 * @param {Function} ctor
 *   The child constructor.
 * @param {Function} superCtor
 *   The parent constructor.
 */

function inherits (ctor, superCtor) {
  ctor.super_ = superCtor;
  ctor.prototype = Object.create(superCtor.prototype, {
    constructor: {
      value: ctor,
      enumerable: false
    }
  });
};
然后你可以简单地做:

function ChildClass() {
    inherits(this, ParentClass);
    // If you want to call parent's constructor:
    this.super_.apply(this, arguments);
}
使用Lodash扩展原型

_.assign(ChildClass.prototype, {
  value: key
});
或者给ES6一个机会

class ParentClass {
    constructor() {
        var date = new Date();
        var hours = date.getHours();
        var minutes = date.getMinutes();
        var seconds = date.getSeconds();
        this.initializeTime = hours + ':' + minutes + ':' + seconds;
    }
}

class ChildClass extends ParentsClass {
  constructor() {
      super();
      console.log(this.initializeTime);
  }
}

2019年来自谷歌

从中可以看出,扩展原型的方法是:

函数MyClass(){
调用(this);
}
//继承一个类
MyClass.prototype=Object.create(SuperClass.prototype);
//混入另一个
Object.assign(MyClass.prototype{
//…你拥有自己的原型。。。
});
//重新分配构造函数

MyClass.prototype.constructor=MyClass我的示例演示了几件事:私有变量、parant和子构造函数的相同解析参数、rewrite.toString()函数try:
“”+this
:)

文档的完整示例:

输出:

构造函数参数 扩展子类中的函数 增量变量 私有变量 保护变量
/**
*父类的类接口
*
*@级
*/
函数父函数(){
this.parseArguments(…参数);
/**
*隐藏变量
*
*@type{Boolean}
*@私人
*/
var hidden=true;
/**
*躲起来
*/
this.getHidden=()=>{
log(this+“:hidden(private var)is”,hidden);
}
/**
*隐藏
*
*@param{Boolean}状态隐藏的新值
*/
this.setHidden=(状态)=>{
log(此+”:隐藏(私有变量)设置为“,!!状态);
隐藏=状态;
}
defineProperty(这个,“_id”,{value:“312”});
}
Object.defineProperty(Parent.prototype,“nameString”,{value:“Parent”});
/**
*解析参数
*/
Parent.prototype.parseArguments=函数(arg1,arg2){
this.arg1=arg1;
this.arg2=arg2;
};
/**
*使用`class.toString()获取类名`
*/
Parent.prototype.toString=函数(){
返回此.nameString;
};
/**
*初始化中间件
*/
Parent.prototype.init=函数(){
log(this+“:默认输出”);
};
/**
*增值
*/
Parent.prototype.increment=函数(){
this.value=(this.value)?this.value+1:1;
console.log(this+“:increment”,this.value);
};
/**
*子类的类接口
*
*@级
*/
函数childInterface(){
this.parseArguments(…参数);
}
//延伸
childInterface.prototype=新父级();
Object.defineProperty(childInterface.prototype,“nameString”,{value:“childInterface”});
/**
*初始化中间件(重写默认值)
*/
childInterface.prototype.init=函数(chatClient){
log(this+“:新输出”);
};
/**
*Child2的类接口
*
*@级
*/
函数child2Interface(){
this.parseArguments(…参数);
}
//延伸
child2Interface.prototype=new Parent();
Object.defineProperty(child2Interface.prototype,“nameString”,{value:“child2Interface”});
//---------------------------------------------------------
//---------------------------------------------------------
MM=新的父项(“arg1的值”、“arg2的值”);
Child1=新的childInterface(“1”、“2”);
Child2=新的Child2接口(“a”、“b”);
日志(MM+“args:”,MM.arg1,MM.arg2);
log(Child1+“args:”,Child1.arg1,Child1.arg2);
日志(Child2+“args:”,Child2.arg1,Child2.arg2);
控制台日志(“”);
MM.init();
Child1.init();
Child2.init();
控制台日志(“”);
MM.增量();
Child1.increment();
Child2.increment();
Child2.increment();
MM.增量();
控制台日志(“p”、“c1”、“c2”);
console.log(MM.value,“+Child1.v
_.assign(ChildClass.prototype, {
  value: key
});
class ParentClass {
    constructor() {
        var date = new Date();
        var hours = date.getHours();
        var minutes = date.getMinutes();
        var seconds = date.getSeconds();
        this.initializeTime = hours + ':' + minutes + ':' + seconds;
    }
}

class ChildClass extends ParentsClass {
  constructor() {
      super();
      console.log(this.initializeTime);
  }
}
MM = new Parent("val of arg1", "val of arg2");
Child1 = new childInterface("1", "2");
Child2 = new child2Interface("a", "b");

console.log(MM + "args:", MM.arg1, MM.arg2);
// Parentargs: val of arg1 val of arg2
console.log(Child1 + "args:", Child1.arg1, Child1.arg2);
// childInterfaceargs: 1 2
console.log(Child2 + "args:", Child2.arg1, Child2.arg2);
// child2Interfaceargs: a b
MM.init();
// Parent: default ouput
Child1.init();
// childInterface: new output
Child2.init();
// child2Interface: default ouput
MM.increment();
// Parent: increment 1
Child1.increment();
// childInterface: increment 1
Child2.increment();
// child2Interface: increment 1
Child2.increment();
// child2Interface: increment 2
MM.increment();
// Parent: increment 2
console.log("p", "c1", "c2");
// p c1 c2
console.log(MM.value, " " + Child1.value, " " + Child2.value);
// 2  1  2
MM.getHidden();
// Parent: hidden (private var) is true
MM.setHidden(false);
// Parent: hidden (private var) set to false
Child2.getHidden();
// child2Interface: hidden (private var) is true
MM.setHidden(true);
// Parent: hidden (private var) set to true


Child2.setHidden(false);
// child2Interface: hidden (private var) set to false
MM.getHidden();
// Parent: hidden (private var) is true
Child1.getHidden();
// childInterface: hidden (private var) is true
Child2.getHidden();
// child2Interface: hidden (private var) is false 
function Parent() {
  //...
  Object.defineProperty(this, "_id", { value: 312 });
};

console.log(MM._id); // 312
MM._id = "lol";
console.log(MM._id); // 312