Js面向对象

一、js中面向对象编程的几种形式

1、静态类(直接json对象形式)

var Person = {
    age : 15 ,
    name : "小明",
    say : function( msg ){
      console.log( msg );
    }
};
console.log( Person.age ); //=>15
Person.say( "Person say" ); //=>"Person say"

特点:

  • 书写方便,不容易扩展

2、构造函数方式

(1)公有属性,方法(prototype原型链方式)
function Person( name, age ){
    this.init( name , age );
}
Person.prototype.init = function( name, age ){
    this.age = age;
    this.name = name;
};
Person.prototype.age = 0;
Person.prototype.name = "";
Person.prototype.say = function ( msg ){
    console.log( msg );
};

var xiaoming = new Person( 'xm', 10 );
console.log(xiaoming.age); //=>10
console.log(xiaoming.name); //=>'xm'
xiaoming.say( "say xm ok" ); //=>"say xm ok"

特点:

  • 比较像其它有class面向对象编程语言的书写方法,容易接受
  • 在内存中只有一份,提高了程序的执行效率,减少了存储空间
  • prototype写的方法不能访问,构造函数里面声明的私有方法(缺点)
(2)特权属性、方法
function Person( name , age ){
    this.name = name;
    this.age = age;
    this.say = function( msg ){
        console.log( msg );
    };
}

var xiaoming = new Person( 'xm', 25 );
console.log( xiaoming.name ); //=>'xm'
console.log( xiaoming.age ); //=>25
xiaoming.say( "say xm ok" ); //=>"say xm ok"

特点:

  • 每实例化一个对象,就都在内存中挂载上属性和方法,比较浪费内存,程序执行效率会变低
(3)私有属性、方法(闭包)
function Person( nameInit, ageInit ){
 var name = nameInit;
 var age = ageInit;
 var say = function( msg ){
    console.log( msg );
 };
 this.print = function(){
    console.log(name);
    console.log(age);
 };
}

var xm = new Person( "xm", 111 );
xm.print(); //=>"xm" => 111

在js中由于没有专门写类的class,所以没有private这个私有属性和方法,但是利用js的作用于的特性我们可以在js构造函数中定义的变量,外部无法访问,所以后人称这为私有属性和方法
特点:

  • 这里的私有属性方法能被,构造函数、特权方法、私有方法进行访问,公有方法(prototype原型)不可以访问,说的更简单一点就是,只能被在构造函数里面定义的函数进行访问

3、另一种构造函数,不用new出来的实例对象,用js的特性:

function Person( nameInit, ageInit, heightInit ){
    var name = nameInit,
        age = ageInit,
        height = heightInit, //私有
        say = function( msg ){
            console.log( msg );
        };

    return { //这边放出接口(返回公有属性和方法)
        name : name,
        age : age,
        say : say
    };
}

var xm = Person( 'xm', 20 , 175 );
console.log( xm.height ); //=>undefined
console.log( xm.name ); //=>'xm'
xm.say("say xm"); //=>"say xm"

特点:和特权方式一样

二、js继承

//先写一个父亲
function Person( name, age ){
    this.age = age;
    this.name = name;
}
Person.prototype.age = 15;
Person.prototype.name = '用来继承Person';
Person.prototype.say = function( msg ){
    console.log( msg );
}

继承方式1:公有的方式继承

function Student( name , age ){}
Student.prototype = new Person( '', 23 );

var obj = new Student( 'xx', 555 );

console.log(obj.name); //=>'用来继承Person'
console.log(obj.age); //=>15
obj.say('aa');

原理:new 出父亲的得实例,这样这个实例拥有父亲的所以属性、方法,利用js特性,直接赋值给Student的原型,这里因为new出来的实例的属性和方法也是在原型上的,故出现了一个原型链,以后有机会在探讨

继承方式2:利用内部函数,call(),apply()函数进行函数进行属性的拷贝

function Student( name , age ){
    Person.apply( this, [name,age] );
}

var obj = new Student( 'xm' , 1 );
console.log( obj.name ); //=>'xm'
obj.say( 'bb' ); //=>'bb'

原理:拷贝 Person实例化出来的特权的属性、方法给子类的 实例化对象
缺点:不能拷贝Person的公有属性、方法(原型上)
call()和apply() 的区别只是 传参数父类的构造函数的方式不同:

function Student( name, age ){
   // Person.apply( this, [name,age] );
   Person.call( this, name, age );
}

call():直接在在传实例化this,后面跟着参数
apply():把参数,放到一个数组里
ps:两个传参数的顺序都要和Person这个构造函数的参数顺序一致

继承方式3:遍历方式

function Student( name, age ){
    var Child = new Person( name, age );
    for( var i in Child ){
        this[i] = Child[i];
    }
}

var obj = new Student( 'xm', 1 );

console.log(obj.name); //=>'xm'
obj.say('aa'); //=>'aa'

原理:利用js的对象特性,在构造函数中创建一个对象,把这个对象上面的非私有的属性、方法全部拷贝给实例化出来的对象

ps:上面写出的继承方式,都是单独列出来的,他们各有各的优点,所以你在运用的过程中,也可以随意的组合,结合他们各自的优势,这样写出更漂亮的代码

你可能感兴趣的