二,js 基于原型的类实现详解

基本概念

在java中,类有如下四种成员:类属性,类方法,实例属性,实例方法。

js中没有这些概念,但是js中的类有如下3中成员:

constructor: 构造函数,上面可以定义类属性和类方法.但是这些属性和方法只能通过类来访问,不能通过实例来访问。

prototype: 原型,定义实例方法,被所有实例共享

instance object: 定义实例属性,每个实例都有自己的属性


因此,定义类有三个基本步骤:

1,定义构造函数,构造函数内部定义实例属性。

2,在prototype上定义实例方法

3,在构造函数上定义类属性和类方法,

function People(name){
     this.name = name;
}
People.prototype.say = function(m){
     console.log(this.name + ":" + m);
}
People.type = "people";


instanceof

instanceof 是通过比较prototype来实现的。

function A(){};
var a = new A();
a instanceof A;//true
var b={};
b instanceof A;//false
b.__proto__ = A;
b instanceof A;//true



利用闭包实现私有属性和方法

私有属性

js不支持private,可以利用闭包来实现私有属性。

function People(name){
     this.getName = function(){return name;};     //name是私有变量,只能通过set/get来访问。
     this.setName = function(n){name = n;}
}
var p = new People("Bob");
p.name;     //undefined
p.getName();     //Bob
p.setName("Lily");
p.getName();     //Lily


不同于java等语言,这样实现私有属性后,3点不足之处:

1,getter/setter 在每个实例中都有一份拷贝,不符合实例共享同一组方法的原则,而且影响性能。

2,即使在类自身的方法中也无法用this.name来访问name,不过这样未必是坏事。

3,get/set必须定义在构造函数中,使构造函数很臃肿。

私有方法

还是利用闭包来实现

var People = (function(){
     function People(name){
          this.name = name ;
     };
     People.prototype.sayName = function(){     //public
          _sayName.call(this);     //call private method
     };
     function _sayName(){     //private
          console.log(this.name);
     };
     return People;
}());




继承

继承的关键是继承原型和指定构造方法,即如下两行关键代码:

B.prototype = inherit(A.prototype);     //从原型继承A的实例方法,inherit的定义在下面

B.prototype.constructor = B;     //否则就变成A了


一个继承的完整例子:

function People(name){
     this.name = name;
}
People.prototype.sayName = function(){
     alert(this.name);
}

function Student(name, studentID){
     People.call(this, name);
     this.id = studentID;
}
Student.prototype = inherit(People.prototype);     //关键点1
Student.prototype.constructor = Student;     //关键点2
Student.prototype.sayID = function(){
     alert(this.id);
}




//封装一个完整的方法
//从一个prototype继承一个新的对象,即 newObj.prototype = p;
function inherit(p){
     if(p == null) throw TypeError();
     if(Object.create) return Object.create(p);
     var t = typeof p;
     if(t != "object" && t != "function") throw TypeError();
     function f(){};
     f.prototype = p;
     return new f();
}

//把p的可枚举属性复制到o中,o中同名属性会被覆盖
function extend(o, p){
     for(pro in p) o[pro] = p[pro];
     return o;
}

function defineSubClass(superClass     //父类
                                   , constructor     //构造函数
                                   , methods          //实例方法,添加到prototype上
                                   , statics          //静态属性,被添加到构造函数上
){
     constructor.prototype = inherit(superClass.prototype);
     constructor.prototype.constructor = constructor;
     if(methods) extend(constructor.prototype, methods);
     if(statics) extend(constructor, statics);
     return constructor;

}

Function.prototype.extend = function(constructor, methods, statics){
     return defineSubclass(this, constructor, methods, statics);
}


接口,抽象类和抽象方法

因为js没有提供对接口、抽象类和抽象方法的语法支持,所以一般的实现方式是:默认抛出异常,因此在实现类中不重写这些方法就会出错。

function abstractMethod = function(){     //一个全局的抽象方法
     throe new Error("unimplemented abstract method!");
}

function AbstractClassOne = function(){     //抽象类
     throe new Error("can't instantiate abstract Class!");
}
AbstractClassOne.prototype.prop1 = abstractMethod;     //抽象方法


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值