Javascript进阶(8)---OOP
面对对象编程(OOP)
- OOP定义
面对对象程序设计(Object-oriented programming ,OOP),是一种程序设计范型,同时也是一种程序开发的方法。对象指的是类的实例。他将对象作为程序作用的基本单元,将程序和数据封装其中,以提高程序的复用性。
---维基百科
- OOP特点(相信大家都已烂熟于心)
- 继承
- 封装
- 多态
- 抽象
- 对象实例化下的原型链
- 任意声明一个函数foo,其prototype属性是一个object
- 继续测试JavaScript的内置构造器Number(),发现其prototype属性仍是一个object
- 举例说明
1 function Foo(){ 2 this.x = "x" ; 3 } 4 Foo.prototype.y="y"; 5 var foo1 = new Foo(); 6 console.log(foo1.x); // x 7 console.log(foo1.y); // y
首先明确几点:
- prototype与__proto__不是一回事,prototype是一个JS对象,而__proto__是一个(几乎)所有对象都有的一个属性。
- prototype是函数对象上预设的对象属性(因为他是一个object)
- __proto__是对象上的原型,通常指向其构造器的prototype属性
- 第2行的 this 在第 5 行使用new关键字创建对象的时候,这个this指向的是一个原型(即__proto__属性)为Fun的prototype的一个空对象,然后通过this.x="x" 给这个空对象赋予属性。不难看出这里的this就是指向新生成的foo1对象,使用this.x挂载的属性也将直接挂载在foo1对象上。
- 在使用 new 进行创建对象实例的时候,prototype会被用作 new 出来这些对象的原型
- 结构表示如图
- 使用new创建对象实例之后,动态修改prototype的影响
- 修改已经存在的prototype上的属性 ,会直接对已经创建的实例造成影响
- 直接修改prototype对象本身,不会对已经创建的实例造成影响
Foo.prototype = { } ; //直接将prototype对象设置为一个空对象,这算是对prototype属性的自身的直接修改
- 无论使用上述哪种方法,修改过prototype属性后,再使用new创建的实例,都会受到此次修改的影响
- 任意声明一个函数foo,其prototype属性是一个object
OOP实现继承
1 function Person(name,age){ 2 this.name = name ; 3 this.age = age; 4 } 5 6 Person.prototype.sayHi = function(){ 7 console.log("我的名字是:"+this.name+"我今年"+this.age+"岁。"); 8 } 9 Person.prototype.LEGS_NUM = 2; 10 Person.prototype.ARMS_NUM = 2 ; 11 Person.prototype.walk=function(){ 12 console.log(this.name + "会走路....."); 13 } 14 function Student(name,age,className){ 15 Person.call(this,name,age); 16 this.className = className; 17 } 18 19 20 Student.prototype = Object.create(Person.prototype); //创建一个空对象,并且这个对象的原型指向传入的参数 21 Student.prototype.constructor = Student; //手动将刚才创建的对象的construct指向Student,若不修改则指向Person 22 23 24 //定义Student类自己的方法sayHi 25 Student.prototype.sayHi = function (){ 26 console.log("我的名字是:"+this.name+"我是"+this.className+"班的学生。"); 27 } 28 //定义Student类自己的方法goto_school 29 Student.prototype.goto_school=function(subject){ 30 console.log(this.name + "每天要去上"+subject+"课"); 31 }
//测试 var Jay = new Student("Jay",37,"三年二班"); Jay.sayHi(); //我的名字是:Jay我今年37岁。 console.log(Jay.LEGS_NUM); //2 Jay.walk(); //Jay会走路..... Jay.goto_school("数学"); //Jay每天要去上数学课
- (25行)sayHi方法绑定在Student的prototype上,每当Student实例访问sayHi方法时候,先会在对象本身上找有没有这个方法,发现没有。然后在Student中找到了,则不会继续原型链向上查找,与Java中覆盖父类方法类似
- 在函数对象内使用this参数接收的变量,使用new实例化的时候,会作为新创建的对象的直接属性。例如例子中的,name、age、className属性。
- (20行)实现继承的时候,必须把父类(Person)和子类(Student)的prototype指向的对象分开来,因为子类在添加自己的属性和方法的时候就不会影响到父类的一些属性和方法。
- 例子中原型链继承结构如下
- 从结构图中不难发现,Student.prototype是使用Object.create()方法创建的(20行),所以他的原型(__proto__属性)指向的是Person.prototype。
- 对象的prototype的__proto__属性一般都指向原型链顶端的Object.prototype。
特别注意
上述例子中的__proto__属性在chrome浏览器中测试有效,在其他环境中,请使用Object提供的方法Object.getPrototypeOf(目标对象)的方法获取对象的原型。
(本文归纳自慕课网大BOSN的课程http://www.imooc.com/video/7054,加入了些许个人理解,若侵权私信告知)