javascript是一门弱类型语言,从不须要类型转换。对象继承关系变得可有可无。对于一个对象来讲重要的是它能作什么,而不是它从哪里来。javascript是一门基于原型的语言,这意味着对象直接从其余对象继承。 javascript
一、伪类 java
javascript不直接让对象从其余对象继承,反而是插入了一个中间层:经过构造器函数产生对象。 json
当一个函数被建立时,Function 构造器产生的函数对象会运行相似这样的一些代码: 数组
this.prototype = {constructor : this};新建立的函数对象被赋予了一个prototype属性。对于普通函数,这个属性没有任何做用。由于javascript没有提供一种方法去肯定那个函数是用来打算作构造器的,因此给每个函数对象都赋予了这样一个prototype属性。对于做为构造器的函数对象来讲,这个prototype属性是用来存放继承特征的地方。
函数做为构造器去构造新对象时,就是采用构造器调用模式去调用函数 ,也就是使用new 前缀去调用一个函数。此时的函数就至关于构造对象的一个类,固然这不是一个真正意义上的类,只是javascript为了刻意模拟面向对象系统而构造的一种语法。因此构造器函数是一个伪类。 闭包
如今咱们来实现一个new 方法来替代 new 操做符,经过这个new 方法咱们来看看到底new 操做符作了哪些操做: app
Function.prototype.method = function(name, fun) { this.prototype[name]= fun; }; Object.create = function(pro){ var F = function(){}; F.prototype = o; return new F(); }; Function.method('new', function(){ var that = Object.create(this.prototype); var other = this.apply(that, arguments); return (other && typeof other === 'object') || that; });
上面例子首先给Function的原型添加一个method方法,这个方法被全部的函数对象继承(Function本身也是函数对象),用于给本身的原型添加某个方法。这个用这个函数构造出来的新对象将会共享(继承)这个方法。 函数
而后又给Object添加了一个create方法,这个方法用于建立一个新的对象,并以参数pro 做为构造函数的原型。这个新建立的对象将会共享(继承)pro的全部属性。 this
最后,咱们给Function原型添加了一个new方法,这个方法模拟了new操做符在构建新对象时所做的操做。让咱们看一个例子: spa
var Person = function (name, age ){ this.name = name; this.age = age; }; var p = Person.new("clopopo",12); p.name // "clopopo" p.age // 12
二、对象说明符 prototype
编写构造器函数时,参数用一个对象说明符来代替一大串参数
//使用一大串参数来构造对象 var myObject = make(f, l, m, c, s); //使用对象说明符来代替一大串参数 myObject = make({ first : f, middle : m, last : l, state : s, city : c });
至关于把参数组织成了相似json对象的东西。优势是不须要记住参数的顺序,另外一个就是能够直接传入json对象,来生成真正的对象实例。
三、原型
基于原型的继承比基于类的继承模型在概念上要更简单:一个新对象能够继承一个旧对象的属性。利用上面Object的create方法,咱们彻底能够避免使用new这样使人迷惑的模拟类的继承方式(本质上仍是基于原型)。
首先,利用对象字面量来定义一个有用的对象:
var myMammal = { name : 'Herb the Mammal', get_name : function() { return this.name; }, says : function(){ return this.saying || ''; } }
一旦有一个想要的对象,咱们就能够利用Object的create方法(上文本身定义的)基于这个对象定制新的对象。
var myCat = Object.create(myMammal); myCat.name = 'Henrietta'; myCat.saying = 'meow'; myCat.getName = function(){ return this.says + ' ' + this.name + ' ' + this.says; };
这是一种差别化继承,myCat查找属性时,若是自身存在就调用自身的属性,不然就去查找myCat链接的原型对象。
四、函数化
上文的几种继承方式有一个弱点就是没法保护隐私,就是咱们没法获得私有函数和私有变量。有一种很是不可取的方法就是被称为“假装私有”模式。就是给私有方法或变量去一个怪模怪样的名字,并但愿使用代码的用户伪装看不到这些变量,这是典型的自欺欺人啊。幸好javascript的闭包特性给咱们提供了一种叫作应用模块的模式。
var mammal = function(spec){ var that = {}; that.get_name = function(){ return spec.name; }; that.says = function(){ return spec.saying || ' '; }; return that; } var myMammal = mammal({name: 'Herb'});
再来看看原型继承
var cat = function(spec){ spec.saying = spec.saying || ''; var that = mammal(spec); that.get_name = function(){ return that.says() + ' ' + spec.name; } return that; }
var myCat = cat('kitty');
函数化模式还给咱们提供了一个处理父类方法的方法。用闭包封存了调用superior方法对象的this和当时name属性对应的方法。
Object.method('superior', function(name){ var that = this, method = that[name]; return function(){ return method.apply(that, arguments); }; });
先看看这个方法的用法:
var coolcat = function(spec){ var that = cat(spec), super_get_name = that.superior('get_name'); that.get_name = function(n){ return 'like ' + super_get_name() + ' baby'; }; return that; };
super_get_name 获得的是cat对象建立时的get_name方法,根据superior方法定义知道,该方法永远都会以调用superior时的那个对象为上下文,上例中就是cat对象。因此调用super_get_name()时就是以cat为上下文,cat建立时的get_name方法为方法体。