javascript – 了解为什么真正的原型继承比古典/伪原型继承更好,为什么我不应该使用“新”

前端之家收集整理的这篇文章主要介绍了javascript – 了解为什么真正的原型继承比古典/伪原型继承更好,为什么我不应该使用“新”前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
Aadit M ShahWhy Prototypal Inheritance Matters阅读一些文章
Stop Using Constructor Functions in JavaScript来自埃里​​克·埃利奥特(Eric Elliott),我认为我理解了所有的观点,在理论上.但实际上我看不到这种模式的真正优势.

我们来看看两个代码片段中的两个实现来继承.

>第一个使用augment.js它是Aadit M Shah的脚本
>在这个例子中,我们将使用this script.由Aadit M Shah也是这样做的.

实施1:

var AugmentPerson = Object.augment(function() {
      this.constructor = function(name) {
          this.name = name;
      };
      this.setAddress = function(country,city,street) {
          this.country = country;
          this.city = city;
          this.street = street;
      };
    });
    var AugmentFrenchGuy = AugmentPerson.augment(function(base) {
      this.constructor = function(name) {
          base.constructor.call(this,name);
      };
      this.setAddress = function(city,street) {
          base.setAddress.call(this,"France",street);
      };
    });
    var AugmentParisLover = AugmentFrenchGuy.augment(function(base) {

      this.constructor = function(name) {
          base.constructor.call(this,name);
      };

      this.setAddress = function(street) {
          base.setAddress.call(this,"Paris",street);
      };
    });
    var t = new AugmentParisLover("Mary");
    t.setAddress("CH");
    console.log(t.name,t.country,t.city,t.street); //Mary France Paris CH

在这个例子中,我们使用函数构造函数,而不是直接从对象继承.

实施2:

var CreatePerson = {
        create: function (name) {
            this.name = name;
            return this.extend();
        },setAddress: function(country,street) {
             this.country = country;
             this.city = city;
             this.street = street;
        }
    };
    var CreateFrenchGuy  = CreatePerson.extend({
        create: function (name) {
            return CreatePerson.create.call(this,name);
        },setAddress: function(city,street) {
            CreatePerson.setAddress('France',street);
        }
    });
    var CreateParisLover  = CreateFrenchGuy.extend({
        create: function (name) {
            return CreateFrenchGuy.create.call(this,setAddress: function(street) {
            CreateFrenchGuy.setAddress('Paris',street);
        }
    });

    var t = CreateParisLover.create("Mary");
    t.setAddress("CH");
    console.log(t.name,t.street); //Mary France Paris CH

说实话,我试图看到第二个实现的好处.但我不能.我唯一看到的是更灵活的是因为我们可以使用apply来创建实例:

var t = CreateParisLover.create.apply(CreateParisLover,[“Mary”]);

这给了我们更多的灵活性,这是真的.但是我们可以对this做同样的事情:

Function.prototype.new = function () {
     function functor() { return constructor.apply(this,args); }
     var args = Array.prototype.slice.call(arguments);
     functor.prototype = this.prototype;
     var constructor = this;
     return new functor;
  };

然后我们可以:

var t = AugmentParisLover.new.apply(AugmentParisLover,["Mary"]);

在灵活性,可重用性,难度方面真正的好处是什么?
因为如果你检查两种情况的表现. Object.create()几乎比new:http://jsperf.com/inheritance-using-create-vs-new慢得多
我很混乱

@H_403_34@

解决方法

以前有类似的问题已经被问及了很多次.看到:

Constructor function vs Factory functions
Classical Vs prototypal inheritance

更多学习:
https://medium.com/javascript-scene/3-different-kinds-of-prototypal-inheritance-es6-edition-32d777fa16c9#.s0r3i5w6t
http://vimeo.com/69255635

TL;博士

>构建者打破/封闭的原则
>构造函数对象创建与对象初始化相结合 – 有时会妨碍代码的可重用性
>构造函数看起来有点像类,这是令人困惑的. JavaScript不需要类(我建议避免ES6中的类关键字). JavaScript有一些比类更好的东西.
>原型委托和动态对象扩展(连接继承)的组合比传统的继承更强大和灵活.
>构造函数.prototype和实例之间的连接在JavaScript中是虚弱的和不可信的.使用构造函数可以提供一个工作实例的幻觉,当它不能在执行上下文中工作时,这可能会令人困惑,或者如果构造函数原型被替换,则不起作用.
使用构造函数更换原型更加困难.您可能想要这样做来启用多态对象构造.使用工厂,热插拔原型很容易,可以使用.call()和.apply()完成.

编辑 – 响应OP发布的“答案”:

Object.create最好的一点是,它是一个专用的低级工具,可以让您创建一个新的对象,并分配您想要的任何原型,而不使用构造函数.有很多理由来避免构建者,这里深入讨论:Constructor function vs Factory functions

>用于演示“较少代码”的代码并不能真正显示古典和原型继承之间的区别.一个更典型的例子可能是:

古典

var Animal = function Animal(name) {
  this.name = name;
};

Animal.prototype.walk = function walk() {
  console.log(this.name + ' goes for a walk.');
};

var Rabbit = function Rabbit(/* name */) {
  // Because construction and instantiation are conflated,you must call super().
  Animal.prototype.constructor.apply(this,arguments);
};

// Classical inheritance is really built on top of prototypal inheritance:
Rabbit.prototype = Object.create(Animal.prototype);

// Fix the .constructor property:
Rabbit.prototype.constructor = Rabbit;

Rabbit.prototype.jump = function jump() {
  console.log(this.name + ' hops around a bit.');
};

var myRabbit = new Rabbit('Bunny George');

myRabbit.walk();
// Bunny George goes for a walk.

原型

var animalMethods =  {
  walk: function walk() {
    console.log(this.name + ' goes for a walk.');
  }
};

var animal = function animal(name) {
  var instance = Object.create(animalMethods);
  instance.name = name;
  return instance;
};

var rabbitMethods = {
  jump: function jump() {
    console.log(this.name + ' hops around a bit.');
  }
};

var rabbit = function rabbit(name) {
  var proto = rabbitMethods;

  // This is more commonly done like mixin({},animalMethods,rabbitMethods);
  // where mixin = $.extend,_.extend,mout.object.mixIn,etc... It just copies
  // source properties to the destination object (first arg),where properties from
  // the last argument override properties from prevIoUs source arguments.
  proto.walk = animalMethods.walk;
  var instance = Object.create(rabbitMethods);

  // This could just as easily be a functional mixin,// shared with both animal and rabbit.
  instance.name = name;
  return instance;
};

var rabbit2 = rabbit('Bunny Bob');

rabbit2.walk();
// Bunny Bob goes for a walk.

所需的代码量非常相似,但对于我来说,原型更重要的是做得更多,而且它也更灵活,并且没有一个典型的继承关系式的行李.

@H_403_34@ @H_403_34@

猜你在找的JavaScript相关文章