在Javascript

时间:2015-09-24 14:00:37

标签: javascript oop

我在使对象延伸工作时迷失了方向。我已经阅读了几十个与此主题相关的网站,但我仍然没有更聪明。似乎每个人都使用它自己的方法来完成这项工作,我也是如此,我试图找到扩展/继承对象的最佳方法。

我也知道有很多框架/插件来涵盖这个功能,但我只是想了解它的工作原理。没有提到大多数这些框架包含许多我可能永远不会使用的其他东西,因此我试图创建自己的东西。

我能够扩展一个对象,在我开始向目标对象添加方法之前,一切似乎都没问题。要了解此问题,请参阅以下示例...

或者只是试试这个JSFiddle

问题是,在初始化Rabbit对象的新实例后,我无法访问 Rabbit 方法changeName。 而且我不明白它为什么会发生,也就是说它为什么不认识这种方法。

[*] 请查看我下面的更新代码(也是JFiddle),现在看来一切正常。

如果这是一个好方法或我错过了什么,请告知anoyne吗?

var Class = (function(NewClass){
    if(NewClass.length != 0){
        var extend = function(target, source, args) {
            Object.getOwnPropertyNames(source).forEach(function(propName) {
                if(propName !== "Extend")
                {
                    Object.defineProperty(
                        target, propName,
                        Object.getOwnPropertyDescriptor(source, propName)
                    );
                }
                if (typeof source[propName] !== 'undefined'){
                    delete source[propName];
                }
            });

            return target;
        };
        var inherit = function(source, args){
            var baseClass = Object.getPrototypeOf(this); 
            baseClass.prototype = extend.call(this, baseClass, source, args);
        };
        if(NewClass.Extend){
            var Class = function(){ //// New Class Constructor ////
                if(typeof NewClass.Extend === 'function'){
                    NewClass.Extend.apply(this, arguments);
                    inherit.call(this, NewClass.Extend);
                    console.log(NewClass)
                    inherit.call(this, NewClass, arguments);
                    if(NewClass.Initialize){
                        NewClass.Initialize.call(this, arguments);
                    }
                }
            };
            Class.prototype.constructor = Class;
            return Class; 
        }
    }
});

var Animal =(function(args){//// constructor ////
    var self = this;
    self.name = typeof args !== 'undefined' ? args.name : null;
    self.bags = 0;
});

var Rabbit = new Class({
    Extend: Animal ,
    Initialize: function(){
        console.log(this.name)
    },
    changeName: function(a){

        console.log(this.name)
    }
});


var LittleRabbit = new Rabbit({name: "LittleRabbit", type: "None"});
console.log(LittleRabbit instanceof Rabbit)
console.log(LittleRabbit)
LittleRabbit.changeName("alex");

3 个答案:

答案 0 :(得分:2)

您的extend函数工作错误,因为Object.getPrototypeOf返回原型,所以在更多情况下它 object

var extend = function(source, args){
    var baseClass = Object.getPrototypeOf(this); 
    source.apply(this, args);

    //so here you just add property prototype to object, and this not same as set prototype to function.
    baseClass.prototype = Object.create(source.prototype);
};

所以你可以在下面的代码片段中解决这个问题:



function Class(args) {
  if (arguments.length != 0) {
    var C = function() {
      if (typeof args.Extend == 'function') {
        args.Extend.apply(this, arguments)
      }
      if (args.Initialize) {
        args.Initialize.call(this);
      }
    };
    if (typeof args.Extend == 'function') {
      C.prototype = Object.create(args.Extend.prototype);
    }

    Object.keys(args).filter(function(el) {
      return ['Extend', 'Initialize'].indexOf(el) == -1
    }).forEach(function(el) {
      C.prototype[el] = args[el];
    });

    return C;
  }
};

var Animal = (function(args) { //// constructor ////
  var self = this;
  self.name = typeof args !== 'undefined' ? args.name : null;
  self.bags = 0;
});

var Rabbit = Class({
  Extend: Animal,
  Initialize: function() {
    console.log(this.name);
  },
  changeName: function(a) {
    this.name = a;
  }
});


var LittleRabbit = new Rabbit({
  name: "LittleRabbit",
  type: "None"
});
console.log(LittleRabbit instanceof Rabbit);
console.log(LittleRabbit instanceof Animal);
console.log(LittleRabbit.name);
LittleRabbit.changeName('new little rabbit');
console.log(LittleRabbit.name);




答案 1 :(得分:1)

我建议阅读MDN article detailing the JavaScript object model。它包含“手动”子类化的示例:

function Employee() {
  this.name = "";
  this.dept = "general";
}

function Manager() {
  Employee.call(this);
  this.reports = [];
}
Manager.prototype = Object.create(Employee.prototype);

function WorkerBee() {
  Employee.call(this);
  this.projects = [];
}
WorkerBee.prototype = Object.create(Employee.prototype)

将您的示例翻译为此样式很简单:

function Animal(name) {
  this.name = name;
  this.bags = 0;
}

function Rabbit(name) {
  Animal.call(this, name);
  console.log(this.name);
}
Rabbit.prototype = Object.create(Animal.prototype);
Rabbit.prototype.changeName = function(name) {
  this.name = name;
};

然后你可以轻松运行你的例子,修改一下:

var LittleRabbit = new Rabbit("LittleRabbit");
console.log(LittleRabbit instanceof Rabbit)
console.log(LittleRabbit)
LittleRabbit.changeName("new name");

一旦你理解了这一点,我建议你不要建立自己的类创建机制,只需使用ES6 classes

class Animal {
  constructor(name) {
    this.name = name;
    this.bags = 0;
  }
}

class Rabbit extends Animal {
  constructor(name) {
    super(name);
    console.log(this.name);
  }

  changeName(name) {
    this.name = name;
  }
}

您可以在Babel REPL中看到此示例。某些浏览器/ js运行时natively support ES6 classes already,但您可以使用Babel将代码转换为ES5,以用于尚未安装的环境。

顺便说一下,实际上需要完全正确地进行子类化。一个更完整的例子(可能不适用于所有环境)是:

function Animal() {}
function Rabbit() {
  Animal.call(this);
}
Rabbit.prototype = Object.create(Animal.prototype);
Rabbit.prototype.constructor = Rabbit;
Rabbit.__proto__ = Animal;

答案 2 :(得分:0)

可以为ES6类继承一个选项:

'use strict';
class Animal {
  constructor( name ) {
    this.name = name;
  }
  changeName( name ) {
    this.name = name;
  }
}

class Rabbit extends Animal {
  constructor() {
    super( 'rabbit' );
  }
}

let littleRabbit = new Rabbit();

console.log( littleRabbit.name ); //log default name

littleRabbit.changeName( 'littleRabbit' ); //executing an method of animal class

console.log( littleRabbit.name ); //log changed name

你不需要为旧的好javascript制作OOP继承的“开销”,因为那里有“翻译器”将你的es6代码翻译成es5代码。例如,babel:https://babeljs.io/

我认为值得尝试一下......