古典与典型的用例

时间:2017-02-06 03:31:20

标签: javascript inheritance

关于经典继承与原型继承,我有一个问题。我想看看哪个更好?

假设我们有一个名为familyTree的函数。

function familyTree(){
  this.lastname = "xyz";
}

如果我想为我们添加任何其他详细信息,我们可以通过两种方式继承父级:

1:原型方式:

familyTree.prototype.personDetails = function(){

this.firstName = "abc";
this.middleName = "middle1";

 var newToString = function(name){ //overwriting toString method
  console.log("The name is: "+name+"Middle Name is "+middleName);
 }
}

2:使用'new'关键字

的经典方式
    var newPerson = new familyTree();
    newPerson.firstName = "abc";
    newPerson.middleName = "middle1";
    newperson.newToString = function (name){
     console.log("The name is: "+name+"Middle Name is "+middleName);
    }

假设我要创建100个不同的中间名。

什么更有意义?使用经典继承还是原型?因为使用Classical可以复制所有对象,但使用原型可以使一切变得混乱。

请说明,当一个人应该使用古典与原型时。

1 个答案:

答案 0 :(得分:2)

JavaScript中只有一种继承,即典型的继承。 JavaScript中不存在“经典”继承。

尽管JavaScript语言必须使基于类编程的OOP开发人员感到宾至如归(包括class关键字)的“语法糖”,但JavaScript实际上并没有或使用类。这种语言词汇只是为了让你感到温暖和模糊。

您的问题实际上并不是询问继承,而是询问是否应将属性附加到构造函数或原型。

请参阅代码注释以获取解释:

// When you create a function that you will use to create object instances,
// you have a "constructor function". By convention, these functions should
// be named in PascalCase as a way to let others know that they are to be
// used in conjunction with the "new" keyword as a constructor.
function FamilyTree(first, middle, last){
  
  // Because this function will be used to create instances of a
  // FamilyTree object, each instance created will need to store
  // data that is different from another. This is done with "instance
  // properties" and they are created by prepending the property name
  // with "this.". The "this" object will be referenced by the object
  // instance variable that is used when the instance is created:
  this.firstName = first;
  this.middleName = middle;
  this.lastName = last;
  
}

// JavaScript objects don't technically have "methods" - - they
// have properties that store functions and functions are how
// to add behavior to an object. Since the behaviors of an object
// don't typically change from instance to instance, you should not
// add them to the constructor function. If you did, the code would
// work, but each instance would need to store a copy of the exact 
// same behavior, making the objects unnecessarialy large in memory.
// Instead, we attach behaviors that all instances of an object will
// need to the prototype of the constructor and that way all instances
// created from the constructor will inherit the behaviors, but the 
// acutal behavior will only be stored once, thus saving on memory space
// and eliminating the possibility of one instance behaving differently 
// than others, unintentionally.

// Implementing "methods" that all FamilyTree instances will inherit:
FamilyTree.prototype.newToString = function(name){ 
  return "First name: " + this.firstName + ", Last Name: " + this.lastName;
}

// The constructor function's prototype (as with all objects) derives from "Object"
// which defines a "toString" property, by re-defining that property on the constructor's
// prorotype, we will be able to override the inherited one
FamilyTree.prototype.toString = function(name){ 
  return this.lastName + ", " + this.firstName;
}
  
// To use this object, we have a few choices, but the simplest one is to just instantiate it:
var myFamilyTree = new FamilyTree("John","Fitzgerald","Kennedy");

// Now, we just work with the instance:
console.log(myFamilyTree.firstName);
console.log(myFamilyTree.middleName);
console.log(myFamilyTree.lastName);
console.log(myFamilyTree.newToString());
console.log(myFamilyTree.toString());

现在,上面的代码可以工作,但在技术上没有很好地组织,因为对象是一个“家谱”,它真正存储的只是一个人的名字和一些输出该名称的方法。家谱不多。实际上,这个“家谱”对象应该由其他对象组成(即,许多个人应该能够与其他相关的家谱数据一起被包括在内)。如果我们应用OOP "Single Responsibility Principle" (“类/模块应该只有一个改变的原因”),我们需要使Family Tree对象具有较小的对象部分。所有这些都涉及使原始对象具有存储一组人物对象的属性:

// First, make objects that represent the parts of the whole
function Person(first, middle, last, dob, maiden){
  // Instance properties are added to the constructor, which makes individual instances:
  this.firstName = first;
  this.middleName = middle;
  this.lastName = last;
  this.dob = dob;
  this.maidenName = maiden;
}

// Behavior properties are added to the constructor's prototype to avoid duplication
// of code across instances:
Person.prototype.newToString = function(name){ 
  return "First name: " + this.firstName + ", Last Name: " + this.lastName;
}

Person.prototype.toString = function(name){ 
  return this.lastName + ", " + this.firstName;
}

// Then create an object that becomes the sum of the parts:
function FamilyTree(){
  // We just need a way to store family members.
  // Each FamilyTree instance can have different members, so an instance property
  // is needed:
  this.people = [];
}

// And, again, behaviors are added to the prototype:
FamilyTree.prototype.getMemberCount = function(){
  return this.people.length;
}

FamilyTree.prototype.addMember = function(personObject){
  this.people.push(personObject);
}

FamilyTree.prototype.removeMember = function(personObject){
  var index = this.people.findIndex(function(element){
    return personObject === element;
  });
  this.people.splice(index, 1);
}

// And, because the tree stores an array, we can looop through it:
FamilyTree.prototype.enumerate = function(){
  var result = "";
  this.people.forEach(function(person){
    result += person.firstName + " " + person.middleName + " " + person.lastName + 
           " (" + person.newToString() + " [" + person.toString() + "])";
  });
  return result;
};

  
// Now, to use the Family Tree, we first need some people
var jack = new Person("John","Fitzgerald","Kennedy", new Date(1917, 4, 29));
var bobby = new Person("Robert", "Francis", "Kennedy", new Date(1925, 11, 20));
var teddy = new Person("Edward","Moore","Kennedy", new Date(1932, 1, 22));

// Now, we add those objects to a new Family Tree instance:
var kennedyTree = new FamilyTree();
kennedyTree.addMember(jack);
kennedyTree.addMember(bobby);
kennedyTree.addMember(teddy);
console.log("The tree contains: " + kennedyTree.getMemberCount() + " members.");
console.log(kennedyTree.enumerate());

// Let's remove a member:
kennedyTree.removeMember(bobby);
console.log("The tree contains: " + kennedyTree.getMemberCount() + " members.");
console.log(kennedyTree.enumerate());