js面向对象

一、面向对象编程的特点

1.抽象:
2.封装:
3.继承:
4.多态:

二、面向对象的组成

1.对象的属性:对象下面的变量。
2.对象的方法:对象下面的函数。

三、this指向

1.当用new去创建一个对象,构造函数中的this指向新创建出来的对象,而且函数的返回值默认是this(隐式返回)。

四、原型

作用:改写对象下面公用的方法和属性,让公用的方法或者属性在内存中存在一份(提高性能)。

五、包装对象

基本类型都有自己的包装对象:String Number Boolean
当基本类型的对象调用方法时,会先找到对应的包装对象类型,包装对象类型会把对象所有的属性和方法给基本类型,最后包装对象消失。

var str='hello';
str.charAt(0);//e,此处是调用了包装对象String下面的charAt()方法。
var str='hello';
str.number=10;//用包装对象创建对象添加属性
alert(str.number);//undefine,此时包装对象已经消失

六、原型链

1.定义:实例对象与原型之间的连接,叫做原型链。
2.proto(隐式连接)
3.Object对象类型是原型链的最外层

function Aaa(){
    this.num=10;
    }
Aaa.prototype.num=20;
Object.prototype.num=30;
    
var a1=new Aaa();
alert(a1.num);//10
function Aaa(){ }
Aaa.prototype.num=20;
Object.prototype.num=30;
    
var a1=new Aaa();
alert(a1.num);//20
function Aaa(){}
Object.prototype.num=30;
    
var a1=new Aaa();
alert(a1.num);//30
js面向对象_第1张图片
原型链图解

七、面向对象的一些属性和方法

1.hasOwnProperty():查看当前属性是不是对象自身下面的属性。

var arr=[];
arr.num=10;
Array.prototype.num2=20;
alert(arr.hasOwnProperty('num'));//true,arr所独有的属性
alert(arr.hasOwnProperty('num2'));//false,不是arr所独有的属性   

2.constructor:查看对象的构造函数
例1:

function Aaa(){}
var a=new Aaa();
alert(a.constructor);//Aaa

例2:

var arr=[];
alert(arr.constructor);//Array
alert(arr.constructor==Array);//true
arr.constructor==Array可以用于数组类型的判断,但不是最好方法。

注意1:在写完一个函数后,系统会默认给该函数的原型添加一个constructor属性。
例如,创建如下函数:

function Aaa(){}

该函数的原型上默认自动生成一个constructor属性:

Aaa.prototype.constructor=Aaa;

所以有:

function Aaa(){}
var a=new Aaa();
alert(a.constructor);//Aaa

注意2: 系统自带属性for in不能获取到。

function Aaa(){}
Aaa.prototype.name='晓明';
Aaa.prototype.constructor=Aaa;
var a=new Aaa();
for(var attr in Aaa.prototype){
    alert(attr);//可以获取到name,但是不能获取到系统自带的constructor
    }

注意3:避免修改constructor属性。

function Aaa(){}
Aaa.prototype.name='晓明';
Aaa.prototype.age='24';
var a=new Aaa();
alert(a.constructor);//Aaa

如果把上面的属性改写成json的形式

function Aaa(){}
Aaa.prototype={
    name:'晓明',
    age:'24'
    };
var a=new Aaa();
alert(a.constructor);//Object

Aaa.prototype.constructor被改写了!因为Aaa.prototype={};//Aaa.prototype=json,所以Aaa.prototype.constructor==Object。
正确的json写法中应重写constructor属性

function Aaa(){}
Aaa.prototype={
    constructor:Aaa,//json中重写constructor属性
    name:'晓明',
    age:'24'
    };
var a=new Aaa();
alert(a.constructor);//Aaa

八、instanceof:查看对象与构造函数是否在同一条原型链上。

例1:

function Aaa(){}
var a=new Aaa();
alert(a instanceof Aaa);//true,对象a和构造函数Aaa在同一条原型链上
alert(a instanceof Object);//true,对象a和构造函数Object在同一条原型链上

例2:

var arr=[];
alert(arr instanceof Array);//true

arr instanceof Array可用于数组类型的判断,但不是最好方法。

九、toString() :把对象转成字符串

1.系统对象自带toString,自定义的对象都是通过原型链找到Object.prototype的toString。
例1,对于自己写的对象

function Aaa(){}
var a=new Aaa();
alert(a.toString==Object.prototype.toString);//true

例2,对于系统对象

var arr=[];
alert(arr.toString==Object.prototype.toString);//false
alert(arr.toString==Array.prototype.toString);//true

2.toString()的用法
1)把对象转化成字符串。

var arr=[1,2,3];
alert(arr.toString());//'1,2,3'

2)进制转换

var num=255;
alert(num.toString(16));//'ff',将255转化为16进制

3)类型判断
例1,数组

var a=[];
alert(Object.prototype.toString.call(a));//[object Array]

例2,json

var a={};
alert(Object.prototype.toString.call(a));//[object Object]

例3,日期

var a=new Date();
alert(Object.prototype.toString.call(a));//[object Date]

例4,正则表达式

var a=new RegExp();
alert(Object.prototype.toString.call(a));//[object RegExp]

Object.prototype.toString.call(arr)=='[object Array]'可用于数组类型的判断,是最好方法。

拓展:哪种判断数组类型的方法最好呢?
toString方法最好,因为在iframe中创建数组,跨页面时,constructor方法和instanceof方法会失效。

window.onload=function(){
    var oF=document.createElement('iframe');
    document.body.appendChild(oF);
    var ifArray=window.frames[0].Array;
    var arr=new ifArray();//在iframe中创建数组,跨页面
    alert(arr.constructor==Array);//false
    alert(arr instanceof Array);//false
    alert( Object.prototype.toString.call(arr)=='[object Array]');//true
    };

十、对象的继承

1.什么是继承?
1)在原有对象的基础上,略作修改,得到一个新的对象。
2)不影响原有对象的功能
2.拷贝继承(通用型,有new或无new的时候都可以)
1)属性的继承:调用父类的构造函数call
2)方法的继承:for in 拷贝继承(jQuery中采用的也是拷贝继承)

function  Father(name,age){
    this.name=name;
    this.age=age;
    }
Father.prototype.showName=function(){
        alert(this.name);
        };
        
function Son(name,age,job){
    Father.call(this,name,age);//属性继承,用call方法修改this指向
    this.job=job;
    }   
extend(Son.prototype,Father.prototype);//方法继承,采用for in拷贝
//继承。虽然函数是对象,但是函数具有只能重新赋值(开辟新空间,变成新对
//象),不能被修改(在原来空间上修改旧对象)的特点,使它可以通过for in 
//拷贝继承。
Son.prototype.showJob=function(){
    alert(this.job);
    };      
function extend(objson,objfather){
    for(var attr in objfather){
        objson[attr]=objfather[attr];
        }
    }

var person=new Son('晓明','24','学生');
person.showName();//晓明

3.类式继承(适合new构造函数)
利用构造函数继承的方式。
JS中没有类的概念,把JS的构造函数看做类。

js面向对象_第2张图片
Paste_Image.png
function  Father(){
    this.name='晓明';
    }
Father.prototype.showName=function(){
        alert(this.name);
        };      
function Son(){}    

Son.prototype=new Father();//一句话实现继承,但存在很多问题

var s1=new Son();
s1.showName();//晓明
alert(s1.constructor);//Father

存在问题:
1.person.constructor指向Father而不是Son.
这是因为Son.prototype=new Father();这句话重写了Son.prototype,Son.prototype下原有的constructor等属性被覆盖。
解决:修正Son.prototype.constructor,Son.prototype.constructor=Son;
2.子类实例的属性均指向父类中的属性,会相互影响。
解决:属性和方法分别单独继承。

Paste_Image.png

1)创建一个没有属性的空函数F,专门用来继承父类的方法。
2)属性采用call方法继承。
类式继承完整例子:

function  Father(){
    this.name=[1,2,3];
    }
Father.prototype.showName=function(){
        alert(this.name);
        };
        
function Son(){
    Father.call(this);//属性继承,用call方法修改this指向    
    }   
    
//方法继承
var F=function(){};//创建一个没有属性的空函数F,专门用来继承父类的方法。
F.prototype=Father.prototype;
Son.prototype=new F();//一句话实现继承
Son.prototype.constructor=Son;

var s1=new Son();
s1.name.push(4);
s1.showName();//1,2,3,4

var s2=new Son();
alert(s2.name);//1,2,3。属性单独继承后,不同实例的属性相互独立,互不影响。

4.原型继承(适合无new的对象)

var father={
    name:'晓明'
    };
var son=extend(father);
son.name='小强';
alert(father.name);//晓明
alert(son.name);//小强

function extend(obj){
    var F=function(){};
    F.prototype=obj;
    return new F();
    }

你可能感兴趣的:(js面向对象)