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的对象特性,在构造函数中创建一个对象,把这个对象上面的非私有的属性、方法全部拷贝给实例化出来的对象