JavaScript 扩展类

IT技术 javascript oop object inheritance ecmascript-6
2021-03-06 16:50:48

我有一个基类:

function Monster() {
  this.health = 100;
}

Monster.prototype.growl = function() {
  console.log("Grr!");
}

我想扩展并创建另一个类:

function Monkey extends Monster() {
  this.bananaCount = 5;
}

Monkey.prototype.eatBanana {
  this.bananaCount--;
  this.health++; //Accessing variable from parent class monster
  this.growl();  //Accessing function from parent class monster
}

我已经做了很多研究,在 JavaScript 中似乎有很多令人费解的解决方案。在 JS 中实现这一点的最简单和最可靠的方法是什么?

6个回答

下面针对 ES6 更新

2013 年 3 月和 ES5

这个 MDN 文档很好地描述了扩展类:

https://developer.mozilla.org/en-US/docs/JavaScript/Introduction_to_Object-Oriented_JavaScript

特别是,现在他们处理它:

// define the Person Class
function Person() {}

Person.prototype.walk = function(){
  alert ('I am walking!');
};
Person.prototype.sayHello = function(){
  alert ('hello');
};

// define the Student class
function Student() {
  // Call the parent constructor
  Person.call(this);
}

// inherit Person
Student.prototype = Object.create(Person.prototype);

// correct the constructor pointer because it points to Person
Student.prototype.constructor = Student;

// replace the sayHello method
Student.prototype.sayHello = function(){
  alert('hi, I am a student');
}

// add sayGoodBye method
Student.prototype.sayGoodBye = function(){
  alert('goodBye');
}

var student1 = new Student();
student1.sayHello();
student1.walk();
student1.sayGoodBye();

// check inheritance
alert(student1 instanceof Person); // true 
alert(student1 instanceof Student); // true

请注意,Object.create()某些旧浏览器不支持,包括 IE8:

Object.create 浏览器支持

如果您需要支持这些,链接的 MDN 文档建议使用 polyfill,或以下近似值:

function createObject(proto) {
    function ctor() { }
    ctor.prototype = proto;
    return new ctor();
}

使用 this likeStudent.prototype = createObject(Person.prototype)比使用更可取new Person(),因为它避免在继承原型时调用父构造函数,并且仅在调用继承者的构造函数调用父构造函数

2017 年 5 月和 ES6

幸运的是,JavaScript 设计者听到了我们的求助,并采用了更合适的方式来解决这个问题。

MDN有另一个关于 ES6 类继承的很好的例子,但我将展示与上面在 ES6 中复制的完全相同的类集:

class Person {
    sayHello() {
        alert('hello');
    }

    walk() {
        alert('I am walking!');
    }
}

class Student extends Person {
    sayGoodBye() {
        alert('goodBye');
    }

    sayHello() {
        alert('hi, I am a student');
    }
}

var student1 = new Student();
student1.sayHello();
student1.walk();
student1.sayGoodBye();

// check inheritance
alert(student1 instanceof Person); // true 
alert(student1 instanceof Student); // true

干净易懂,就像我们都想要的那样。请记住,虽然 ES6 很常见,但并非所有地方都支持

ES6 浏览器支持

Student.prototype = Object.create(Person.prototype); 经典的创建方法在这里工作
2021-04-20 16:50:48
@PhamHuyAnh 只是做类似的事情 function Person(n) { this.name = n; }
2021-04-22 16:50:48
Student.prototype = new Person(); 如果我访问超类中的参数,此行会导致错误。
2021-05-10 16:50:48
如果 Person 构造函数需要参数,例如 Person(name) ... 呢?
2021-05-14 16:50:48
我正在尝试创建扩展功能,它自己完成所有工作。是否有可能以某种方式移动“Person.call(this);” 或从下面的示例“Monster.apply(this, arguments);” 到这样的功能?我在这样做时遇到了问题。
2021-05-18 16:50:48

ES6 现在让你有机会使用class & extends关键字:

然后,您的代码将是:

你有一个基类:

class Monster{
       constructor(){
             this.health = 100;
        }
       growl() {
           console.log("Grr!");
       }

}

你想扩展和创建另一个类:

class Monkey extends Monster {
        constructor(){
            super(); //don't forget "super"
            this.bananaCount = 5;
        }


        eatBanana() {
           this.bananaCount--;
           this.health++; //Accessing variable from parent class monster
           this.growl(); //Accessing function from parent class monster
        }

}
使用try{}catch(e){}块来管理它,并告诉最终用户在需要时更新他的浏览器。
2021-05-04 16:50:48
这更干净,可以确认在 chrome 51.0、Firefox 47 中工作。
2021-05-18 16:50:48

试试这个:

Function.prototype.extends = function(parent) {
  this.prototype = Object.create(parent.prototype);
};

Monkey.extends(Monster);
function Monkey() {
  Monster.apply(this, arguments); // call super
}

编辑:我在这里放了一个快速演示http://jsbin.com/anekew/1/edit请注意,这extends是 JS 中的保留字,您在整理代码时可能会收到警告,您可以简单地将其命名为inherits,这就是我通常所做的。

有了这个助手并使用对象props作为唯一参数,JS 中的继承就变得更简单了:

Function.prototype.inherits = function(parent) {
  this.prototype = Object.create(parent.prototype);
};

function Monster(props) {
  this.health = props.health || 100;
}

Monster.prototype = {
  growl: function() {
    return 'Grrrrr';
  }
};

Monkey.inherits(Monster);
function Monkey() {
  Monster.apply(this, arguments);
}

var monkey = new Monkey({ health: 200 });

console.log(monkey.health); //=> 200
console.log(monkey.growl()); //=> "Grrrr"
@Phil,这是一个提升的函数声明,它应该可以工作。您从此代码中得到的唯一“问题”是“extends 是一个保留字”,但您可以轻松地将其更改为任何其他标识符。
2021-04-25 16:50:48
谢谢,兄弟。这很棒。可以在 Node.js 中应用它来为构造函数等创建基类,所以每次创建构造类时我都不必创建 mongo 连接等
2021-05-14 16:50:48
使用它,Monkey不会继承Monster的属性 ( health)。如果在调用之前未定义,您还将收到“ReferenceError: Monkey is not defined”MonkeyMonkey.extends(Monster)
2021-05-20 16:50:48

如果你不喜欢原型方法,因为它并没有真正以一种很好的 OOP 方式表现,你可以试试这个:

var BaseClass = function() 
{
    this.some_var = "foobar";

    /**
     * @return string
     */
    this.someMethod = function() {
        return this.some_var;
    }
};

var MyClass = new Class({ extends: BaseClass }, function()
{
    /**
     * @param string value
     */
    this.__construct = function(value)
    {
        this.some_var = value;
    }
})

使用轻量级库(2k 缩小):https : //github.com/haroldiedema/joii

感谢您提供此库的链接!!看起来很棒:D 似乎这就是我一直在寻找的东西!<3
2021-05-18 16:50:48

我可以提出一种变体,只是在书中读过,似乎最简单:

function Parent() { 
  this.name = 'default name';
};

function Child() {
  this.address = '11 street';
};

Child.prototype = new Parent();      // child class inherits from Parent
Child.prototype.constructor = Child; // constructor alignment

var a = new Child(); 

console.log(a.name);                // "default name" trying to reach property of inherited class