一经于原型模式面临我们唯有需要运用克隆就可知到位同样的职能。1.JavaScript是如出一辙宗基于原型的面向对象语言。

  于大部分面向目标语言中,对象总是由类似中实例化而来,类以及目标的干就如模具跟模件一样。Javascript中从未类似的定义,就算ES6吃引入的class也可大凡平种语法糖,本质上或者采用原型实现。在原型编程语言中,类并无是不可或缺的,对象不自然需要由类实例化而来,而是经仿制另外一个对象来获得。

JS面向对象编程详解,js面向对象编程

序言
  于JavaScript的深世界里讨论面向对象,都如提到两碰:1.JavaScript是平派系基于原型的面向对象语言
2.模拟类语言的面向对象方式。对于为何而学类语言的面向对象,我个人认为:某些情况下,原型模式会提供一定之福利,但于千头万绪的应用中,基于原型的面向对象系统于抽象性与继承性方面差强人意。由于JavaScript是唯一一个为各大浏览器支持之脚本语言,所以各路好手不得不动用各种办法来提高语言的便利性,优化的结果就是该编制的代码越来越像类语言中的面向对象方式,从而也覆盖了JavaScript原型系统的本来面目。  

因原型的面向对象语言
  原型模式如类模式一样,都是凡一样栽编程泛型,即编程的方法论。另外近年来大红大紫的函数编程也是一致种编程泛型。JavaScript之父Brendan
Eich在规划JavaScript时,从同开始就是没打算啊夫进入类的概念,而是借鉴了另外两派系基于原型的之语言:Self和Smalltalk。

  既然跟为面向对象语言,那就是得起创建对象的不二法门。在类似语言中,对象基于模板来创造,首先定义一个类作为针对实际世界之虚幻,然后由接近来实例化对象;而当原型语言中,对象为克隆另一个目标的主意开创,被克隆的母体称为原型对象。

  克隆的关键在于语言本身是不是为我们提供了原生的仿造方法。在ECMAScript5中,Object.create可以为此来克隆对象。

var person = {
  name: "tree",
  age: 25,
  say: function(){
    console.log("I'm tree.")
  }
};

var cloneTree = Object.create(person);
console.log(cloneTree);

  原型模式之目的并无在获取一个同之目标,而提供了一致栽便民的办法去创建对象(出自《JavaScript设计模式与开支执行》)。但是由语言设计之题目,JavaScript的原型是着诸多矛盾,它的少数复杂的语法看起就是那些因类的语言,这些语法问题掩盖了它们的原型机制(出自《JavaScript语言精粹》)。如:

function Person(name, age){
  this.name = name;
  this.age = age;      
}

var p = new Person('tree', 25)

  实际上,当一个函数对象呗创建时,Function构造器产生的函数对象见面运行类似这样的有些代码:

this.prototype = {constructor: this}

  新的函数对象为给予一个prototype属性,它的值是一个分包constructor属性且属性值为该新函数的靶子。当对一个函数使用new运算符时,函数的prototype的属性的价为当做原型对象来克隆出新目标。如果new运算符是一个智,它的执行进程如下:

Function.prorotype.new = function() {
  //以prototype属性值作为原型对象来克隆出一个新对象
  var that = Object.create(this.prorotype);

  //改变函数中this关键指向这个新克隆的对象
  var other = this.apply(that, arguments);

  //如果返回值不是一个对象,则返回这个新克隆对象
  return (other && typeof other === 'object') ? other : that;
}

  从地方可以看到,虽然采用new运算符调用函数看起像是用模板实例化的点子来创建对象,但实质还是坐原型对象来克隆出新对象。

  
由于新克隆的目标是否访问到原型对象的万事方式及性质,加上new运算符的表征,这就是成了使原型模拟类式语言的内核。 

运原型模拟类式语言
抽象

  用原型模式来模拟类,首先是空虚方式。根据JavaScript语言的表征,通常一个类似(实际上是伪类)通常是以字段放置于构造函数(实际上是new
运算符调用底函数,JavaScript本身并没有构造函数的定义)中,而用计放置于函数的prototype属性里。

function Person(name, age) {
  this.name = name;
  this.age = age;
};

Person.prototype.say = function(){
  console.log("Hello, I'm " + this.name);
};

继承

  继承是OO语言中的一个极致人津津乐道的概念。许多OO语言都支持有限种持续方式:接口继承和贯彻持续。接口继承的累方法签名,而实现连续则继续实际的主意。但是ECMAScript中无法落实接口继承,只支持促成持续,而且那实现持续主要是乘原型链来实现的。(出自《JavaScript高级程序设计》
6.3节——继承)在胜三受笔者探索了各种有关延续的模拟,如:组合继承、原型继承、寄生继承、寄生组合继承,最终寄生组合式成为具有拟类式继承的底子。

function Person(name, age) {
  this.name = name;
  this.age = age;
};

Person.prototype.say = function(){
  console.log("Hello, I'm " + this.name);
};

function Employee(name, age, major) {
  Person.apply(this, arguments);
  this.major = major;
};

Employee.prototype = Object.create(Person.prototype);
Employee.prorotype.constructor = Employee;

Employee.prorotype.sayMajor = function(){
  console.log(this.major);
}

  高三丁独让起了单继承的缓解方案,关于多延续的仿我们尚得投机想办法。由于大多延续来该本身的困苦:面向对象语言如果支持了大多延续的话,都见面遇上著名的菱形问题(Diamond Problem)。假设有一个而左图所著之接续关系,O中产生一个道foo,被A类和B类覆写,但是没于C类覆写。那么C在调用foo方法的时,究竟是调用A中之foo,还是调用B中之foo?

图片 1

  所以大多数语言并无支持多累,如Java支持单继承+接口的花样。JavaScript并无支持接口,要于一个免支持接口的语言上模拟接口怎么处置?答案是妇孺皆知的鸭式辨型。放到实际代码中就是是混入(mixin)。原理非常简短:

 function mixin(t, s) {
    for (var p in s) {
      t[p] = s[p];
    }
  } 

  值得一提的凡dojo利用MRO(方法分析顺序(Method Resolution
Order),即找被调用的办法所在类时的搜寻顺序)方式解决了差不多延续的题目。  

  到这个,我们就知晓了仿类语言的基本原理。作为一个易折腾的程序员,我想拥有和谐之道来简化类的创立:

  • 供平等栽便民之艺术去创建类,而无露函数的prototype属性
  • 每当子类中盖父类方法时,能够像Java一样提供super函数,来直接访问父类同名方法
  • 盖还有利于的点子丰富静态变量和办法而休错过关注prototype
  • 像C#那样支持Attribute   

末,在借鉴各位大牛的学识总结,我修了好的切近创建工具O.js:

(function(global) {
  var define = global.define;
  if (define && define.amd) {
    define([], function(){
      return O;
    });
  } else {
    global.O = O;
  }

  function O(){};

  O.derive = function(sub) {
    debugger;
    var parent = this;
    sub = sub ? sub : {};

    var o = create(parent);
    var ctor = sub.constructor || function(){};//如何调用父类的构造函数?
    var statics = sub.statics || {};
    var ms = sub.mixins || [];
    var attrs = sub.attributes || {};

    delete sub.constructor;
    delete sub.mixins;
    delete sub.statics;
    delete sub.attributes;

    //处理继承关系
    ctor.prototype = o;
    ctor.prototype.constructor = ctor;
    ctor.superClass = parent;
    //利用DefineProperties方法处理Attributes
    //for (var p in attrs) {
      Object.defineProperties(ctor.prototype, attrs);
    //}
    //静态属性
    mixin(ctor, statics);
    //混入其他属性和方法,注意这里的属性是所有实例对象都能够访问并且修改的
    mixin(ctor.prototype, sub);
    //以mixin的方式模拟多继承
    for (var i = 0, len = ms.length; i < len; i++) {
      mixin(ctor.prototype, ms[i] || {});
    }

    ctor.derive = parent.derive;
    //_super函数
    ctor.prototype._super = function(f) {
      debugger;
      return parent.prototype[f].apply(this, Array.prototype.slice.call(arguments, 1));
    }

    return ctor;
  }

  function create(clazz) {
    var F = function(){};
    F.prototype = clazz.prototype;
    //F.prototype.constructor = F; //不需要
    return new F();
  };

  function mixin(t, s) {
    for (var p in s) {
      t[p] = s[p];
    }
  }
})(window);

好像创建方式如下:

var Person = O.derive({
  constructor: function(name) {//构造函数
    this.setInfo(name);
  },
  statics: {//静态变量
    declaredClass: "Person"
  },
  attributes: {//模拟C#中的属性
    Name: {
      set: function(n) {
        this.name = n;
        console.log(this.name);
      },
      get: function() {
        return this.name + "Attribute";
      }
    }
  },
  share: "asdsaf",//变量位于原型对象上,对所有对象共享
  setInfo: function(name) {//方法
    this.name = name;
  }
});
var p = new Person('lzz');
console.log(p.Name);//lzzAttribute
console.log(Person);

继承:

var Employee = Person.derive({//子类有父类派生
  constructor: function(name, age) {
    this.setInfo(name, age);
  },
  statics: {
    declaredClass: "Employee"
  },
  setInfo: function(name, age) {
    this._super('setInfo', name);//调用父类同名方法
    this.age = age;
  }
});

var e = new Employee('lll', 25);
console.log(e.Name);//lllAttribute
console.log(Employee);

上述就是是本文的全部内容,希望对大家的求学有帮助。

  原型模式是用来创建对象的等同栽模式。在盖近乎为主导的语言中,要创建一个目标首先使指定这个目标的类,然后实例化一个对象。使用原型模式创建对象时不必关心对象的具体项目,而是找到一个靶,然后经仿制来创造一个一如既往的对象。所以于前者被如要是根据一个靶创建多单相同之对象,我们要事先保存之目标的具有属性信息,然后将性信息设置及新创建的对象上,而于原型模式面临我们仅需要以克隆就会就同样的功用。

君或许感兴趣的章:

  • JS面向对象编程之对象下分析
  • 面向对象的Javascript之二(接口实现介绍)
  • Javascript 面向对象(一)(共有方法,私有方法,特权方法)
  • JavaScript面向对象之Prototypes和继承
  • javascript面向对象入门基础详细介绍
  • javascript面向对象包装类Class封装类库剖析
  • js一般法改写成面向对象方法的不过级折叠菜单示例代码
  • JavaScript面向对象编程入门教程
  • JS面向对象基础讲解(工厂模式、构造函数模式、原型模式、混合模式、动态原型模式)

http://www.bkjia.com/Javascript/1106938.htmlwww.bkjia.comtruehttp://www.bkjia.com/Javascript/1106938.htmlTechArticleJS面向对象编程详解,js面向对象编程 序言
在JavaScript的非常世界里讨论面向对象,都要干两碰:1.JavaScript凡相同派系基于原型的面向对象语言…

  于一些玄幻小说中时时会面面世一些修真大能,以分身之样式游走世间。这个过程十分吻合原型模式的行使:

function Master(){
    this.blood = 100;
    this.level = 6;
}

var noumenon = new Master();
noumenon.level = 9;


var ektype = Object.create(noumenon);

console.log(ektype);

  ES5提供了原生的仿造方法:Object.create,不支持之艺术的浏览器可以如下代码:

function clone(obj){
    function F(){};
    F.prototype = obj;
    return new F();
}

var ektype = clone(noumenon);

  通过以上代码,我们视了哪通过原型模式来克隆出一个一如既往的的对象。原型模式的真正意义决不创建一个均等底靶子,而是提供平等种植创建对象的方法,Javascript的面向对象机制是依据原型模式之,他的靶子系统就是是采用原型模式,通过仿制来创造的,克隆是创造一个目标的过程以及心眼。以持续为条例:

function Person(name){
    this.name = name;
}

function Developer(lang){
    this.language = lang;
}

var p = new Person('coder');

Developer.prototype = p;

var dev = new Developer('Javascript');

 

  基于原型的接轨体系,子类的历次实例化都是本着该构造函数的prototype属性的仿制。所以每次创建Developer对象,其实都是于对p对象的仿造。

  在Java等为类为主导的面向对象语言中,经常利用new实例化一个对象。但是Javascript是因原型的面向对象语言,在这边new运算符创建对象的法门与Java中的new运算符并不相同,Javascript中之new运算符也是经过仿制来实例化对象的,克隆的凡构造器函数的原型对象,new运算符的作用一样于如下代码:

function Person(name){
    this.name = name;
}

function Developer(lang){
    this.language = lang;
}

var p = new Person('coder');

Developer.prototype = p;


function _new(_Constructor) {
    var that = Object.create(_Constructor.prototype);
    var args = Array.prototype.slice.call(arguments, 1);
    var other = _Constructor.apply(that, args);

    return (typeof other === 'object' && other) ? other : that;
}
_new(Developer, 'JavaScript')

  从立我们啊堪看看,Javascript的原型实际上有在诸多矛盾,它的某些复杂语法看起就是比如那些因类的言语,这掩盖了其的原型机制。所以jQuery中尽量避免使用new运算符来创建对象。

  根据前所说Javascript中新创造的对象还是基于原有对象的仿制,所以当Javascript中有一个极度老之对象:Object.prototype,所有目标都是由其克隆而来。

 

  这边所说之仿制是当Javascript原型模式这同一杀条件下之平等种植语义表达,在计算机的物理世界面临并无有真正的仿造。所以这里对克隆应当知道也产生一个兼有__proto__特性指向原对象的对象的经过,原对象变成为克隆的靶子,也不怕是构造函数的prototype对象。

 

  拥有上述共识后,我们得以收获在Javascript中原型编程的核心规则:

  1. Javascript中大部分数还是目标
  2. 一旦抱一个对象,不是经过实例化类,而是找到一个目标作为原型并克隆它
  3. 对象会铭记它们的原型
  4. 如若目标无法响应某个请求,他见面把这个要委托为她好之原型

 

参考书籍:

《Javascript语言精粹》

《Javascript设计模式与出实践》

相关文章