162

JavaScript面向对象(OOP) - 姐姐jy

 6 years ago
source link: http://www.cnblogs.com/jiejiejy/p/7666091.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

  前  言

JRedu

       面向对象程序设计(简称OOP)是现在最流行的程序设计方法,这种方法有别于基于过程的程序设计方法。在写面向对象的WEB应用程序方面JavaScript是一种很好的选择.它能支持OOP.因为它通过原型支持继承的方式和通过属性和方法的方式一样好.很多开发者试图抛弃JS,试着用C#或JAVA仅是因为JS不是他认为合适的面向对象的语言.许多人还没有认识到javascript支持继承.当你写面向对象的代码时.它能给你很强大的能量.你也可以使用它写出可复用,可封装的代码.

一、什么是面向对象编程(OOP)?

        在了解什么是面向对象编程之前,我们来看看语言的分类。总体可以分为三类:面向机器面向过程还有面向对象。面向对象的语言主要有C++、Java、PHP等。

1面向过程与面向对象

1)面向过程:面向过程专注于如何去解决一个问题的过程步骤。编程特点是由一个个函数去实现每一步的过程步骤,没有类和对象的概念。
2)面向对象:专注于由哪一个对象来解决这个问题,编程特点是出现了一个类,从类中拿到对象,由这个对象去解决具体问题。
         对于调用者来说,面向过程需要调用者自己去实现各种函数。而面向对象,只需要告诉调用者,对象中具体方法的功能,而不需要调用者了解方法中的实现细节。

2面向对象的三大特征

这个对于计算机专业的人来说,相信大家已经很熟悉啦,那我就再说一遍吧~

      面向对象的三大特征是继承、封装、多态。JS可以模拟实现继承和封装,但是无法模拟实现多态,所以我们说JS是一门基于对象的语言,而非是面向对象的语言。

3类和对象

1、类:一类具有相同特征(属性)和行为(方法)的集合。
比如,人类具有身高、体重等属性,吃饭、大笑等行为,所以,我们可以把人划分为一类。

2、对象:从类中,拿出具有确定属性值和方法的个体。
比如,张三-->属性:身高180体重180 方法:说话-->我叫张三,身高180

3、类和对象的关系:
①类是抽象的,对象是具体的(类是对象的抽象化,对象是类的具体化)

②类是一个抽象的概念,只能说类有属性和方法,但是不能给属性赋具体的。比如,人类有姓名,但是不能说人类的姓名叫什么。
   对象是一个具体的个例,是将类中的属性进行具体赋值而来的个体。
比如,张三是一个人类的个体。可以说张三的姓名叫张三。也就是张三对人类的每一个属性进行了具体的赋值,那么张三就是由人类产生的一个对象。

4、使用类和对象的步骤:

1)创建一个类(构造函数):类名必须使用大驼峰法则。即每个单词首字母都要大写

function 类名(属性1){
     this.属性1=属性1;
     this.方法=function(){
      //方法中要调用自身属性,必须使用this.属性
     }
}

2)通过类实例化(new)出一个对象。

var obj=new 类名(属性1的具体值);
obj.属性; 调用属性
obj.方法; 调用方法

3)注意事项
①通过类名,new出一个对象的过程,叫做"类的实例化"。
②类中的this,会在实例化的时候,指向新new出的对象。
所以,this.属性 this.方法实际上是将属性和方法绑定在即将new出的对象上面。
③在类中,要调用自身属性,必须使用this.属性名。如果直接使用变量名,则无法访问对应的属性。

function Person(name,age){
   this.name=name;
   this.age=age;
   this.say=function(content){
       //在类中,访问类自身的属性,必须使用this.属性调用。
       alert("我叫"+this.name+",今年"+this.age+"岁,我说了一句话:"+content);
   }
}
var zhangsan=new Person("姐姐",18);
zhangsan.say("你好呀");

④类名必须使用大驼峰法则,注意与普通函数区分。

4面向对象的两个重要属性

1)constructor:返回当前对象的构造函数。
>>>zhangsan.constructor==Person;  ( true)
2)instanceof:检测一个对象是不是一个类的实例;
>>>lisi instanceof Person              √ lisi是通过Person类new出的
>>>lisi instanceof Object              √ 所有对象都是Object的实例
>>>Person instanceof Object        √ 函数本身也是对象

5广义对象与狭义对象

1)狭义对象:只有属性和方法,除此之外没有任何其他内容。

var obj={};  //用{}声明的对象
var obj=new Object(); //用new声明的对象

2)广义对象:除了用字面量声明的基本数据类型之外,JS中万物皆对象。换句话说,只要能添加属性和方法的变量,都可以称为对象。

var s="123";  //不是对象
s.name="aaa";
console.log(typeof(s)); //String
console.log(s.name); //undfined 字面量声明的字符串不是对象,不能添加属性
var s=new String("123");  //是对象
s.name="aaa";
console.log(typeof(s)); //Object
console.log(s.name); //"aaa" 使用new声明的字符串是对象,能添加属性和方法。
二、 成员属性、静态属性和私有属性

1、在构造函数中,使用this.属性声明。或者在实例化出对象以后,使用"对象.属性"追加的,都属于成员属性成员方法。也叫实例属性或实例方法。
     成员属性/方法,是属于由类new出的对象的。
     需要使用"对象名.属性名"调用。

【静态属性与静态方法】
2、通过“类名.属性名”、“类名.方法名”声明的属性和方法,称为静态属性静态方法。也叫类属性和类方法。
     类属性/类方法,是属于类的(属于构造函数的)
     通过"类名.属性名"调用。

3、成员属性是属于实例化出的对象的,只能使用对象调用。
静态属性是属于构造函数的,只能使用类名调用。

[私有属性和私有方法]
4、在构造函数中,使用var声明的变量称为私有属性;
在构造函数中,使用function声明的函数,称为私有方法;

function Person(){
    var num=1;//私有属性
    function func(){}//私有方法
}

私有属性和私有方法的作用域,只在构造函数内容有效。即只能在构造函数内部使用,在构造函数外部,无论使用对象名还是类名都无法调用。

function Person(name){
    this.name=name; //声明成员属性
    var sex="男";//私有属性
                
}
            
var zhangsan=new Person("张三");
zhangsan.age=14; //追加成员属性
alert(zhangsan.name); //调用成员属性
            
Person.count="60亿"; //声明静态属性
alert(Person.count); //调用静态属性
var lisi=new Person("李四");
console.log(lisi.count); //undefined 静态属性是属于类的,只能用类名调用。
三、 JavaScript模拟实现封装

1、什么叫封装?
①方法的封装:将类内部的函数进行私有化处理,不对外提供接口,无法在类外部使用的方法,称为私有方法,即方法的封装。
②属性的封装:将类中的属性进行私有化处理,对外不能直接使用对象名访问(私有属性)。同时,需要提供专门用于设置和读取私有属性的set/get方法,让外部使用我们提供的方法,对属性进行操作。这就叫属性的封装。
2、注意:封装不是拒绝访问,而是限制访问。要求调用者,必须使用我们提供的set/get方法进行属性的操作,而不是直接拒绝操作。
因此,单纯的属性私有化,不能称为封装!必须要有私有化后,提供对应的set/get方法。

function Person(name,age1){
    this.name=name;
// this.age=age; var age=0; this.setAge=function(ages){ if(ages>0&&ages<=120){ age=ages; }else{ alert("年龄赋值失败"); } } // 当实例化类拿到对象时,可以直接通过类名的()传入年龄,设置私有属性 if(age1!=undefined) this.setAge(age1); this.getAge=function(){ return age; } this.sayTime=function(){ alert("我说当前时间是:"+getTime()); } this.writeTime=function(){ alert("我写了当前时间是:"+getTime()); }
/*私有化的方法,只能在类内部被其他方法调用,而不能对外提供功能。这就是方法的封装*/ function getTime(){ return new Date(); } } var zhangsan=new Person("张三",99); zhangsan.setAge(99); alert("张三的年龄是"+zhangsan.getAge()); var lisi=new Person("李四",99); lisi.setAge(110); alert("李四的年龄是:"+lisi.getAge());
四、JavaScript中的this指向详解

1、谁最终调用函数,this最终指向谁(记住!)
①this指向谁,不应考虑函数在哪声明,而应该考虑函数在哪调用!!!
②this指向的永远只可能是对象,而不可能是函数。
③this指向的对象,叫做函数的上下文context,也叫函数的调用者。

2、this指向的规律!!!(跟函数的调用方式息息相关,记住这点,相信你一定会分清this指向哒)
①通过函数名()调用的,this永远指向window
②通过对象.方法调用的,this指向这个对象。
③函数作为数组中的一个元素,用数组下标调用的,this指向这个数组
④函数作为window内置函数的回调函数使用,this指向window。
setInterval setTimeout 等。
⑤函数作为构造函数,使用new关键字调用,this指向新new出的对象。

function func(){
    console.log(this);
}
var obj={
    name:"zhangsan",
    func:func
}
//①通过函数名()调用的,this永远指向window。
func();
//②通过对象.方法调用的,this指向这个对象
obj.func();//狭义对象
            
window.onclick=function(){
    document.getElementById("div1").onclick=function(){
        func();//最终还是使用()调用,所以指向window
    }
    document.getElementById("div1").onclick=func;//广义对象,指向div
}
//③函数作为数组中的一个元素,用数组下标调用的,this指向这个数组
var arr=[1,2,3,func,4,5,6];
arr[3]();
            
//④函数作为window内置函数的回调函数使用,this指向window。
setTimeout(func,1000);
            
//⑤函数作为构造函数,使用new关键字调用,this指向新new出的对象。
var obj1=new func();

现在,你一定分清了this指向了吧,下面我们来看一个综合案例:

var obj1={
    name:"obj1",
    arr:[func,1,{name:"obj2",func:func},3,4],
}
obj1.arr[0]();//最终的调用者是数组。this-->obj.arr
setTimeout(obj1,arr[0],2000);//obj.arr[0]仅仅是取到函数赋给setTimeout,但并没有调用。函数的最终调用者是setTimeout。这个式子相当于setTimeout(func,2000);
obj1.arr[2].func();//最终调用者是{name:"obj2",func:func}
setTimeout(obj1.arr[2].func,2000);//最终调用者是setTimeout
            
//↓最终的调用者是div1
//document.getElementById("div1").onclick=obj1.arr[0]; //document.getElementById("div1").onclick=arr[2].func;

最后,我们再来看一道面试题:

var fullname = 'John Doe';
var obj = {
   fullname: 'Colin Ihrig',
   prop: {
      fullname: 'Aurelio De Rosa',
      getFullname: function() {
         return this.fullname;
      }
   }
};
console.log(obj.prop.getFullname()); 
// 函数的最终调用者 obj.prop 
            
var test = obj.prop.getFullname;
console.log(test());  
// 函数的最终调用者 test()  this-> window
            
obj.func = obj.prop.getFullname;
console.log(obj.func()); 
// 函数最终调用者是obj
            
var arr = [obj.prop.getFullname,1,2];
arr.fullname = "JiangHao";
console.log(arr[0]());
// 函数最终调用者数组

这次就分享到这了,下次再介绍JS中OOP中的继承方法吧~


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK