Javascript 面向对象编程—继承和封装
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Javascript 面向对象编程—继承和封装相关的知识,希望对你有一定的参考价值。
前 言
javascript是一种基于对象(object-based)的语言,你遇到的所有东西几乎都是对象。但是,它又不是一种真正的面向对象编程(OOP)语言,因为它的语法中没有class(类)。面向对象主要专注于有哪一个对象来解决这个问题,编程特点时出现一个个的类,从类中拿到对象,有这个对象去解决具体问题。 对于调用者来说,面向过程需要调用者去实现各种函数。而面向对象,只需要告诉调用者对象中的具体方法的功能, 而不需要调用者了解方法中的实现细节。
而面向过程主要专注于如何去解决一个问题的步骤。编程特点是由一个个的函数去实现每一步的过程步骤,没有类和对象的概念。
一、 继承 |
我们首先解释一下继承的概念,所谓继承就是使用一个子类,继承另一个父类,那么子类可以自动拥有父类中的所有属性和方法,这个过程叫继承,继承的两方,发生在两个类间。
然后我们阐述一下实现继承的原理, 通过循环将父类对象的所有属性,全部赋给子类对象。关键点在于for-in循环, 即使不扩展循环Object,也能通过简单的循环实现操作
1.1扩展Object实现继承。
1 function Person(name,age){ 2 this.name=name; 3 this.age=age; 4 this.say=function(){ 5 alert("我叫"+this.name); 6 } 7 } 8 9 function Student(no){ 10 this.no=no; 11 this.study=function(){ 12 alert("我在学习"); 13 } 14 } 15 16 var p=new Person("张三",12); 17 var s=new Student("12345"); 18 for(var i in p){ 19 s[i]=p[i]; 20 } 21 22 Object.prototype.extend1=function(){ 23 for(var i in parent){ 24 this[i]=parent[i]; 25 } 26 } 27 s.extend1(p); 28 29 console.log(s);
但是呢,扩展Object继承也有如下缺点:
① 无法通过一次实例化,拿到完整的子类对象,而需要先拿到父类对象和子类对象两个对象,手动合并
② 扩展Object继承方法,也会保留在子类对象上
1.2使用原型实现继承
我们先说说使用原型继承的原理, 将父类对象,赋值给子类的prototype,那么父类对象的属性和方法就会出现在子类的prototype中。 那么,实例化子类时,子类的prototype又不会到子类对象的__proto__中, 最终,父类对象的属性和方法,会出现在子类对象的__proto__
这种继承的特点主要是,子类自身的所有属性,都是成员属性,父类继承过来的属性,都是原型属性,但是依然无法通过一次实例化拿到所有的子类对象。
1 function Person(name,age){ 2 this.name=name; 3 this.age=age; 4 this.say=function(){ 5 alert("我叫"+this.name); 6 } 7 } 8 9 function Student(no){ 10 this.no=no; 11 this.study=function(){ 12 alert("我在学习"); 13 } 14 } 15 16 Student.prototype=new Person("张三",12); 17 var s=new Student(15); 18 console.log(s);
1.3使用call和apply以及bind实现继承
我们先解释一下call/bind/apply三个函数的作用,这三个函数通过函数名调用这三个函数,可以强行将函数中的this指定为某个对象。
1 var name="window" 2 function func(a,b){ 3 console.log(this.name+a+b); 4 } 5 var obj={ 6 name:"zhangsan" 7 } 8 var obj1={ 9 name:"lisi" 10 } 11 func(1,2);//window12 12 func.call(obj,1,2);//zhangsan12 13 func.apply(obj1,[1,2]);//lisi12 14 func.bind(obj)(1,2);//zhangsan12 15 16 17 function Person(name,age){ 18 this.name=name; 19 this.age=age; 20 this.say=function(){ 21 alert("我叫"+this.name); 22 } 23 } 24 25 function Student(no,name,age){ 26 this.no=no; 27 this.study=function(){ 28 alert("我在学习"); 29 } 30 Person.call(this,name,age); 31 } 32 var s=new Student(12345,"张三",15); 33 console.log(s);
这三个函数的唯一区别,在于接受func参数列表的方式不同,除此之外,功能上无区别。
二、 封装 |
什么叫封装呢?封装分为方法的封装和属性的封装。
所谓 方法的封装就是将类内部的函数进行私有化处理,不对外提供调用接口,无法在类外部使用的方法,称为私有方法,即方法的封装。
而属性的封装: 将类中的属性进行私有化处理,对外不能直接使用对象名访问(私有属性)。 同时,需要提供专门用于设置和读取私有属性的set/get方法,让外部使用我们提供的方 法,对属性进行操作。 这就叫属性的封装。
封装也有需要 注意的地方, 封装不是拒绝访问,而是限制访问。 要求调用者,必须使用我们提供的set/get方法进行属性的操作,而不是直接拒绝操作。
因此,单纯的属性私有化,不能称为封装!必须要私有化之后,提供对应的set/get方法。
1、 生成实例对象的原始模式 |
1.1我们把人看做一个对象,人有"姓名"和"年龄"两个属性。
1 var Person={ 2 3 name : "张三", 4 5 age : "12" 6 7 }
1.1我们根据这个原型对象的模式,生成两个实例对象。
1 var Person1= {}; // 创建一个空对象 2 Person1.name = "张三"; // 按照原型对象的属性赋值 3 Person1.age= "12"; 4 var Person2= {}; 5 Person2.name = "李四"; 6 Person2.age= "15"; 7 8 //这就是最简单的封装了,把两个属性封装在一个对象里面。
2、 原始对象模式的改进 |
1 function Person(name,age) { 2 return { 3 name:name, 4 age:age 5 } 6 } 7 8 var Person1= Person("张三","12"); 9 var Person2= Person("李四","15");
3、 构造函数 |
构造函数:其实就是一个普通函数,但是内部使用了this变量。对构造函数使用new
运算符,就能生成实例,并且this
变量会绑定在实例对象上。
我们来说说创建一个类和对象的大概步骤,
首先,创建一个类(构造函数):类名必须使用大驼峰法则。即每个单词首字母大写。
function 类名(属性1){
this.属性1=属性1;
this.方法=function(){
//方法中要调用自身属性,必须使用this.方法
}
}
通过类,实例化(new)出一个对象。
var obj=new 类名(属性1的具体值);
obj.属性; //调用属性
obj.方法(); //调用方法
1 //人的原型对象 2 function Person(name,age){ 3 this.name=name; 4 this.age=age; 5 } 6 7 //生成实例对象 8 var Person1= new Person("张三","12"); 9 var Person2= new Person("李四","15"); 10 console.log(Person1.name); // 张三 11 console.log(Person2.age); // 15 12 13 //Person1 和 Person2都会有一个constructor属性,返回当前对象的构造函数 14 console.log(Person1 .constructor == Person); //true 15 console.log(Person2 .constructor == Person); //true 16 17 //instanceof检测一个对象是不是一个类的实例 18 console.log(Person1 instanceof Person); //true 19 console.log(Person2 instanceof Person); //true
构造函数需要注意以下几点,
1、通过一个类名,new出一个对象的过程,叫做"类的实例化"
2、类中的this,会在实例化的时候指向新的new出的对象
所以,this.方法this.属性,实际上是将属性和方法绑定在即将new出的对象上,在类中调用自身属性,必须使用this.属性名。如果直接使用变量名,则无法访问对应的属性。 类名必须使用大驼峰法则,注意区分与普通函数的区别。
4、 Prototype模式 |
prototype 属性允许您向对象添加属性和方法,每一个构造函数都有一个prototype
属性,指向另一个对象。这个对象的所有属性和方法,都会被构造函数的实例继承。
1 function Person(name,age){ 2 this.name=name; 3 this.age=15; 4 } 5 Person.prototype.age=12; 6 var zhangsan=new Person("张三"); 7 console.log(zhangsan.age);
编者按
Javascript面向对象是最难的,初学者不容易掌握,可以多多参考参考专门Javascript面向对象的资料,最后,希望各位和小编一起努力,在前端的路上越走越远!
以上是关于Javascript 面向对象编程—继承和封装的主要内容,如果未能解决你的问题,请参考以下文章