JavaScript笔记——面向对象与原型

JavaScript也是一门面向对象的语言。面向对象的语言有一个标志,那就是类的概念,而通过类可以创建任意多个具有相同属性和方法的对象。但是,JavaScript竟然没有class,因此它的面向对象也与其他的OOP语言有所不同,创建对象和继承关系都显得很怪异很复杂难用

创建对象

JavaScript也采用了构造函数的概念:

 

function Box(name, age) {   //构造函数模式
this.name = name;
this.age = age;
this.run = function () {
return this.name + this.age + '运行中...';
};
}
var box1 = new Box('Lee', 100); 
var box2 = new Box('Jack', 200);
alert(box1.run());
alert(box1 instanceof Box);   //很清晰的识别他从属于 Box

 

构造函数的方法有一些规范:

1.函数名和实例化构造名相同且大写,(非强制,但这么写有助于区分构造函数和普通函数)

2.通过构造函数创建对象,必须使用 new 运算符(构造函数和普通函数的唯一区别,就是他们调用的方式不同。构造函数也是函 数,必须用 new 运算符来调用,否则就是普通函数了)

构造函数示意图:

 

 

原型的概念

在创建类之前,先要有原型的概念,我们创建的每个函数都有一个 prototype(原型)属性,这个属性是一个对象,它的用途是 包含可以由特定类型的所有实例共享的属性和方法。简单地说原型就是实现共享的功能:比如说类里的方法和一些需要共享的属性(较少见)

function Box() {}    //声明一个构造函数
Box.prototype.name = 'Lee';    //在原型里添加属性
Box.prototype.age = 100;
Box.prototype.run = function () {    //在原型里添加方法
return this.name + this.age + '运行中...';
};
var box1 = new Box();
var box2 = new Box();
alert(box1.run== box2.run);     //true,方法的引用地址保持一致

在上面的run方法和name,age属性不论声明多少个对象都是相等的(共享了)

 


原型示意图:

在原型模式声明中,多了两个属性,这两个属性都是创建对象时自动生成的。__proto__ 属性是实例指向原型对象的一个指针,它的作用就是指向构造函数的原型属性 constructor。 通过这两个属性,就可以访问到原型里的属性和方法了。浏览器中无法获取其内部信息

 

原型的声明是有先后顺序的,所以,重写的原型会切断之前的原型

function Box() {};

Box.prototype = { //使用原型创建属性和方法
constructor : Box,
name : 'Lee',
age : 100,
run : function () {
return this.name + this.age + '运行中...';
     }
};

Box.prototype = {      //原型被重写了
age :200
};
var box = new Box(); 
alert(box.run());     //错误TypeError: box.run is not a function ,因为重写了原型,原来的原型方法,属性失效

 

 

创建类与对象

使用动态原型模式创建对象可以使方法成为共享的,而属性各是各的

//动态原型模式创建对象
function Box(name,age){
    this.name=name;
    this.age=age;
    
    if(typeof this.run!='function'){
        Box.prototype.run=function(){                //使用原型来实现方法共享
            return this.name+this.age+'运行时';
        };
    }
}

var box1=new Box('lz',21);
var box2=new Box('Jack',20);
alert(box1.run());
alert(box2.run());

 

继承

继承是面向对象中一个比较核心的概念。其他正统面向对象语言都会用两种方式实现继承:一个是接口实现,一个是继承。而JavaScript只支持继承,不支持接口实现

推荐使用寄生组合继承的方式:

function obj(o) {           //传递一个字面量函数
function F() {}             //创建一个构造函数
F.prototype = o;          //把字面量函数赋值给构造函数的原型
return new F();          //最终返回出实例化的构造函数
}

function create(box,desk){                 //将来传入父类和子类
    var f=obj(box.prototype);           //将父类的原型传入
    f.constructor=desk;                    //改变子类的constructor
    desk.prototype=f;                     //又将f传给子类的原型
}

function Box(name,age){            //父类
    this.name=name;
    this.age=age;
    this.arr=['爸爸','妈妈','儿子'];
    if(typeof this.run!='function'){
        Box.prototype.run=function(){
            return this.name+this.age+'运行时';
        }
    }
}

function Desk(name,age){                      //子类
    Box.call(this,name,age);                 //对象冒充
}

create(Box,Desk);                                  //通过这里实现继承


//下面是证明不同子类对象互不影响(不同空间)
var desk=new Desk('lz',21);
desk.arr.push('女儿');
alert(desk.arr);


var desk2=new Desk('jack',20);
alert(desk2.arr);

 

posted @ 2017-04-30 00:51  OverZeal  阅读(198)  评论(0编辑  收藏  举报