Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/425.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 - Fatal编程技术网

如何从javascript中的类继承?

如何从javascript中的类继承?,javascript,oop,Javascript,Oop,在PHP/Java中,可以执行以下操作: class Sub extends Base { } 并自动将超类的所有公共/受保护的方法、属性、字段等变为子类的一部分,必要时可以重写子类 Javascript中的等价物是什么?我现在改变了我的做法,我试图避免使用构造函数及其原型属性,但我2010年的旧答案仍然在底部。我现在更喜欢Object.create()对象。创建在所有现代浏览器中都可用 我应该注意到,Object.create通常比将new与函数构造函数结合使用要好 //The protot

在PHP/Java中,可以执行以下操作:

class Sub extends Base
{
}
并自动将超类的所有公共/受保护的方法、属性、字段等变为子类的一部分,必要时可以重写子类


Javascript中的等价物是什么?

我现在改变了我的做法,我试图避免使用构造函数及其
原型属性,但我2010年的旧答案仍然在底部。我现在更喜欢
Object.create()
<代码>对象。创建
在所有现代浏览器中都可用

我应该注意到,
Object.create
通常比将
new
与函数构造函数结合使用要好

//The prototype is just an object when you use `Object.create()`
var Base = {};

//This is how you create an instance:
var baseInstance = Object.create(Base);

//If you want to inherit from "Base":
var subInstance = Object.create(Object.create(Base));

//Detect if subInstance is an instance of Base:
console.log(Base.isPrototypeOf(subInstance)); //True

使用Object.create的最大好处之一是能够传入参数,这使您能够有效地控制如何访问和枚举类上的属性,我还使用函数创建实例,这些实例在某种程度上充当构造函数,因为您可以在最后进行初始化,而不只是返回实例

var Base = {};

function createBase() {
  return Object.create(Base, {
    doSomething: {
       value: function () {
         console.log("Doing something");
       },
    },
  });
}

var Sub = createBase();

function createSub() {
  return Object.create(Sub, {
    doSomethingElse: {
      value: function () {
        console.log("Doing something else");
      },
    },
  }); 
}

var subInstance = createSub();
subInstance.doSomething(); //Logs "Doing something"
subInstance.doSomethingElse(); //Logs "Doing something else"
console.log(Base.isPrototypeOf(subInstance)); //Logs "true"
console.log(Sub.isPrototypeOf(subInstance)); //Logs "true

这是我2010年的原始答案:

function Base ( ) {
  this.color = "blue";
}

function Sub ( ) {

}
Sub.prototype = new Base( );
Sub.prototype.showColor = function ( ) {
 console.log( this.color );
}

var instance = new Sub ( );
instance.showColor( ); //"blue"

你不能(在古典意义上)。Javascript是一种典型的语言。您将发现,您从未在Javascript中声明过“类”;您只需定义对象的状态和方法。要产生继承,您需要获取一些对象并对其进行原型化。原型扩展了新的功能

在JavaScript中,您没有类,但可以通过多种方式获得继承和行为重用:

伪经典继承(通过原型):

function Super () {
  this.member1 = 'superMember1';
}
Super.prototype.member2 = 'superMember2';

function Sub() {
  this.member3 = 'subMember3';
  //...
}
Sub.prototype = new Super();
function Super () {
  this.member1 = 'superMember1';
  this.member2 = 'superMember2';
}


function Sub() {
  Super.apply(this, arguments);
  this.member3 = 'subMember3';
}
function createSuper() {
  var obj = {
    member1: 'superMember1',
    member2: 'superMember2'
  };

  return obj;
}

function createSub() {
  var obj = createSuper();
  obj.member3 = 'subMember3';
  return obj;
}
// Check if native implementation available
if (typeof Object.create !== 'function') {
  Object.create = function (o) {
    function F() {}  // empty constructor
    F.prototype = o; // set base object as prototype
    return new F();  // return empty object with right [[Prototype]]
  };
}

var superInstance = {
  member1: 'superMember1',
  member2: 'superMember2'
};

var subInstance = Object.create(superInstance);
subInstance.member3 = 'subMember3';
应与新的
操作员一起使用:

var subInstance = new Sub();
var subInstance = new Sub();
函数应用程序或“构造函数链接”:

function Super () {
  this.member1 = 'superMember1';
}
Super.prototype.member2 = 'superMember2';

function Sub() {
  this.member3 = 'subMember3';
  //...
}
Sub.prototype = new Super();
function Super () {
  this.member1 = 'superMember1';
  this.member2 = 'superMember2';
}


function Sub() {
  Super.apply(this, arguments);
  this.member3 = 'subMember3';
}
function createSuper() {
  var obj = {
    member1: 'superMember1',
    member2: 'superMember2'
  };

  return obj;
}

function createSub() {
  var obj = createSuper();
  obj.member3 = 'subMember3';
  return obj;
}
// Check if native implementation available
if (typeof Object.create !== 'function') {
  Object.create = function (o) {
    function F() {}  // empty constructor
    F.prototype = o; // set base object as prototype
    return new F();  // return empty object with right [[Prototype]]
  };
}

var superInstance = {
  member1: 'superMember1',
  member2: 'superMember2'
};

var subInstance = Object.create(superInstance);
subInstance.member3 = 'subMember3';
此方法还应与
新的
操作员一起使用:

var subInstance = new Sub();
var subInstance = new Sub();
与第一个示例不同的是,当我们将
超级
构造函数应用于
中的
对象时,它会直接在新实例上添加分配给
的属性,例如,
subInstance
直接包含属性
member1
member2
subInstance.hasOwnProperty('member1')==true;

在第一个示例中,这些属性通过原型链访问,它们存在于内部
[[prototype]]
对象上

寄生继承或幂构造函数:

function Super () {
  this.member1 = 'superMember1';
}
Super.prototype.member2 = 'superMember2';

function Sub() {
  this.member3 = 'subMember3';
  //...
}
Sub.prototype = new Super();
function Super () {
  this.member1 = 'superMember1';
  this.member2 = 'superMember2';
}


function Sub() {
  Super.apply(this, arguments);
  this.member3 = 'subMember3';
}
function createSuper() {
  var obj = {
    member1: 'superMember1',
    member2: 'superMember2'
  };

  return obj;
}

function createSub() {
  var obj = createSuper();
  obj.member3 = 'subMember3';
  return obj;
}
// Check if native implementation available
if (typeof Object.create !== 'function') {
  Object.create = function (o) {
    function F() {}  // empty constructor
    F.prototype = o; // set base object as prototype
    return new F();  // return empty object with right [[Prototype]]
  };
}

var superInstance = {
  member1: 'superMember1',
  member2: 'superMember2'
};

var subInstance = Object.create(superInstance);
subInstance.member3 = 'subMember3';
这种方法基本上基于“对象增强”,您不需要使用
new
操作符,并且正如您所看到的,不涉及
This
关键字

var subInstance = createSub();
ECMAScript第五版对象。创建方法:

function Super () {
  this.member1 = 'superMember1';
}
Super.prototype.member2 = 'superMember2';

function Sub() {
  this.member3 = 'subMember3';
  //...
}
Sub.prototype = new Super();
function Super () {
  this.member1 = 'superMember1';
  this.member2 = 'superMember2';
}


function Sub() {
  Super.apply(this, arguments);
  this.member3 = 'subMember3';
}
function createSuper() {
  var obj = {
    member1: 'superMember1',
    member2: 'superMember2'
  };

  return obj;
}

function createSub() {
  var obj = createSuper();
  obj.member3 = 'subMember3';
  return obj;
}
// Check if native implementation available
if (typeof Object.create !== 'function') {
  Object.create = function (o) {
    function F() {}  // empty constructor
    F.prototype = o; // set base object as prototype
    return new F();  // return empty object with right [[Prototype]]
  };
}

var superInstance = {
  member1: 'superMember1',
  member2: 'superMember2'
};

var subInstance = Object.create(superInstance);
subInstance.member3 = 'subMember3';
上述方法是由提出的原型继承技术

对象实例从其他对象实例继承,仅此而已


这种技术比简单的“对象扩充”更好,因为继承的属性不会复制到所有新对象实例上,因为基本对象被设置为扩展对象的
[[Prototype]]]
,在上面的示例中,
子实例
物理上只包含
member3
属性。

您不能从JavaScript中的类继承,因为JavaScript中没有类。

在JavaScript中没有“类继承”,只有“原型继承”。因此,您不需要创建一个类“truck”,然后将其标记为“automobile”的子类。相反,你制作一个对象“杰克”,并说它使用“约翰”作为原型。如果约翰知道“4+4”是多少,那么杰克也知道


我建议您在这里阅读Douglas Crockford关于原型继承的文章:他还展示了如何使JavaScript具有“相似性”继承与其他OO语言一样,然后解释说,这实际上意味着以一种不应该使用的方式破坏javaScript。

您可以使用
.inheritationwith
.fastClass
。它比大多数流行的库更快,有时甚至比本机版本更快

非常容易使用:

function Super() {
   this.member1 = "superMember";//instance member
}.define({ //define methods on Super's prototype
   method1: function() { console.log('super'); } //prototype member
}.defineStatic({ //define static methods directly on Super function 
   staticMethod1: function() { console.log('static method on Super'); }
});

var Sub = Super.inheritWith(function(base, baseCtor) {
   return {
      constructor: function() {//the Sub constructor that will be returned to variable Sub
         this.member3 = 'subMember3'; //instance member on Sub
         baseCtor.apply(this, arguments);//call base construcor and passing all incoming arguments
      },
      method1: function() { 
         console.log('sub'); 
         base.method1.apply(this, arguments); //call the base class' method1 function
      }
}
用法


我觉得这句话最有启发性:

本质上,JavaScript“类”只是一个函数对象,它充当构造函数和附加的原型对象。()

我喜欢使用构造函数而不是对象,所以我偏爱“伪经典继承”方法。下面是一个带有原型链的多重继承的示例:

// Lifeform "Class" (Constructor function, No prototype)
function Lifeform () {
    this.isLifeform = true;
}

// Animal "Class" (Constructor function + prototype for inheritance)
function Animal () {
    this.isAnimal = true;
}
Animal.prototype = new Lifeform();

// Mammal "Class" (Constructor function + prototype for inheritance)
function Mammal () {
    this.isMammal = true;
}
Mammal.prototype = new Animal();

// Cat "Class" (Constructor function + prototype for inheritance)
function Cat (species) {
    this.isCat = true;
    this.species = species
}
Cat.prototype = new Mammal();

// Make an instance object of the Cat "Class"
var tiger = new Cat("tiger");

console.log(tiger);
// The console outputs a Cat object with all the properties from all "classes"

console.log(tiger.isCat, tiger.isMammal, tiger.isAnimal, tiger.isLifeform);
// Outputs: true true true true

// You can see that all of these "is" properties are available in this object
// We can check to see which properties are really part of the instance object
console.log( "tiger hasOwnProperty: "
    ,tiger.hasOwnProperty("isLifeform") // false
    ,tiger.hasOwnProperty("isAnimal")   // false
    ,tiger.hasOwnProperty("isMammal")   // false
    ,tiger.hasOwnProperty("isCat")      // true
);

// New properties can be added to the prototypes of any
// of the "classes" above and they will be usable by the instance
Lifeform.prototype.A    = 1;
Animal.prototype.B      = 2;
Mammal.prototype.C      = 3;
Cat.prototype.D         = 4;

console.log(tiger.A, tiger.B, tiger.C, tiger.D);
// Console outputs: 1 2 3 4

// Look at the instance object again
console.log(tiger);
// You'll see it now has the "D" property
// The others are accessible but not visible (console issue?)
// In the Chrome console you should be able to drill down the __proto__ chain
// You can also look down the proto chain with Object.getPrototypeOf
// (Equivalent to tiger.__proto__)
console.log( Object.getPrototypeOf(tiger) );  // Mammal 
console.log( Object.getPrototypeOf(Object.getPrototypeOf(tiger)) ); // Animal
// Etc. to get to Lifeform

这里是,这里是。

在阅读了许多帖子后,我想出了这个解决方案()。大多数时候我不需要更复杂的东西

var Class = function(definition) {
    var base = definition.extend || null;
    var construct = definition.construct || definition.extend || function() {};

    var newClass = function() { 
        this._base_ = base;        
        construct.apply(this, arguments);
    }

    if (definition.name) 
        newClass._name_ = definition.name;

    if (definition.extend) {
        var f = function() {}       
        f.prototype = definition.extend.prototype;      
        newClass.prototype = new f();   
        newClass.prototype.constructor = newClass;
        newClass._extend_ = definition.extend;      
        newClass._base_ = definition.extend.prototype;         
    }

    if (definition.statics) 
        for (var n in definition.statics) newClass[n] = definition.statics[n];          

    if (definition.members) 
        for (var n in definition.members) newClass.prototype[n] = definition.members[n];    

    return newClass;
}


var Animal = Class({

    construct: function() {        
    },

    members: {

        speak: function() {
            console.log("nuf said");                        
        },

        isA: function() {        
            return "animal";           
        }        
    }
});


var Dog = Class({  extend: Animal,

    construct: function(name) {  
        this._base_();        
        this.name = name;
    },

    statics: {
        Home: "House",
        Food: "Meat",
        Speak: "Barks"
    },

    members: {
        name: "",

        speak: function() {
            console.log( "ouaf !");         
        },

        isA: function(advice) {
           return advice + " dog -> " + Dog._base_.isA.call(this);           
        }        
    }
});


var Yorkshire = Class({ extend: Dog,

    construct: function(name,gender) {
        this._base_(name);      
        this.gender = gender;
    },

    members: {
        speak: function() {
            console.log( "ouin !");           
        },

        isA: function(advice) {         
           return "yorkshire -> " + Yorkshire._base_.isA.call(this,advice);       
        }        
    }
});


var Bulldog = function() { return _class_ = Class({ extend: Dog,

    construct: function(name) {
        this._base_(name);      
    },

    members: {
        speak: function() {
            console.log( "OUAF !");           
        },

        isA: function(advice) {         
           return "bulldog -> " + _class_._base_.isA.call(this,advice);       
        }        
    }
})}();


var animal = new Animal("Maciste");
console.log(animal.isA());
animal.speak();

var dog = new Dog("Sultan");
console.log(dog.isA("good"));
dog.speak();

var yorkshire = new Yorkshire("Golgoth","Male");
console.log(yorkshire.isA("bad"));
yorkshire.speak();

var bulldog = new Bulldog("Mike");
console.log(bulldog.isA("nice"));
bulldog.speak();

Javascript继承与Java和PHP有点不同,因为它实际上没有类。相反,它有提供方法和成员变量的原型对象。您可以链接这些原型以提供对象继承。我在研究这个问题时发现的最常见的模式在。我已经更新了他们的示例,包括对超类方法的调用,并在警报消息中显示日志:

//形状-超类
函数形状(){
这个.x=0;
这个。y=0;
}
//超类方法
Shape.prototype.move=函数(x,y){
这个.x+=x;
这个.y+=y;
日志+='形状已移动。\n';
};
//矩形子类
函数矩形(){
Shape.call(this);//调用超级构造函数。
}
//子类扩展了超类
Rectangle.prototype=Object.create(Shape.prototype);
Rectangle.prototype.constructor=矩形;
//覆盖方法
Rectangle.prototype.move=函数(x,y){
Shape.prototype.move.call(this,x,y);//调用超类方法
日志+='矩形已移动。\n';
}
var log=“”;
var rect=新矩形();
log+=('rect是矩形的实例吗?'+(rect instanceof Rectangle)+'\n');//真的
log+=('rect是形状的实例吗?'+(rect instanceof Shape)+'\n');//真的
直线移动(1,1);//产出,