一、面向對象編程(OOP)的特色:javascript
抽象:抓住核心問題html
封裝:只能經過對象來訪問方法java
繼承:從已有的對象下繼承出新的對象編程
多態:多對象的不一樣形態windows
注:本文引用於 http://www.cnblogs.com/yuxingyoucan/p/5797142.html數組
1、建立對象的幾種方式app
javascript 建立對象簡單的來講,無非就是使用內置對象或各類自定義對象,固然還可使用JSON,但寫法有不少,也能混合使用。函數
一、工廠方式建立對象:面向對象中的封裝函數(內置對象)性能
function createPerson(name){ //一、原料 var obj=new Object(); //二、加工 obj.name=name; obj.showName=function(){ alert(this.name); } //三、出場 return obj; } var p1=createPerson('小米'); p1.showName();
與系統對象的區別:this
var arr=new Array();//生成一個系統數組對象
一、系統對象是直接用 new 在外面生成,而工廠定義的是在函數內部生成
二、工廠定義的函數名稱第一個是小寫開頭,而系統定義的是大寫開頭
工廠模式的優缺點:雖然解決了建立類似對象的問題,可是卻沒有解決對象識別問題(即怎樣知道一個對象的類型)。
二、構造函數建立對象
當new去調用一個函數,這個時候函數中的this就是建立出來的對象,並且函數的返回值就是this(隱式返回)
new後面的函數叫作構造函數
<1>有參數的構造函數
function CreatePerson(name){ this.name=name; this.showName=function(){ alert(this.name); } } var p1=new CreatePerson('小米');
<2>無參數的構造函數
function CreatePerson(){} var p1=new CreatePerson(); p1.name="小米"; p1.showName=function(){ alert(p1.name); } p1.showName();
構造函數模式的優缺點:
一、優勢:建立自定義函數意味着未來能夠將它的實例標識爲一種特定的類型,這是構造函數賽過工廠模式的地方
二、缺點:每一個方法都要在每一個實例上從新建立一遍
三、對象字面量方式建立對象
person={
name:"小米",
age:23
};
四、用原型方式
一、原型對象:只要建立了一個新函數,就會爲該函數建立一個prototype屬性,這個屬性指向函數的原型對象。在默認狀況下,全部的原型對象都會自動得到一個constructor(構造函數)屬性,這個屬性是一個指向prototype屬性所在函數的指針
二、能夠經過isPrototypeOf()方法來肯定對象之間是否存在這種關係
function Person(){} Person.prototype.name="小米"; Person.prototype.showName=function(){ alert(this.name); } var p1=new Person(); p1.showName();
原型模式的優缺點:
一、優勢:可讓全部的對象實例共享它所包含的屬性和方法
二、缺點:原型中是全部屬性都是共享的,可是實例通常都是要有本身的單獨屬性的。因此通常不多單獨使用原型模式。
5.混合模型
構造函數模式定義實例屬性,而原型模式用於定義方法和共享的屬性
function CreatePerson(name){ this.name=name; } Create.prototype.showName=function(){ alert(this.name); } var p1=new CreatePerson('小米'); p1.showName();
var p2=new CreatePerson('小米'); p2.showName();
alert(p1.showName==p2.showName);//true;緣由:都是在原型下面,在內存中只存在一份,地址相同
總結:
function 構造函數(){
this.屬性;
}
構造函數.原型.方法=function(){};
var 對象1=new 構造函數();
對象1.方法();
原型:去改寫對象下面公用的的方法或屬性,讓公用的方法或屬性在內存中存在一份(提升性能)
原型:prototype:要寫在構造函數的下面
var arr=[]; arr.number=10; Array.prototype.number=20; alert(arr.number);//10,
//緣由:普通定義的要比原型定義的權重大,先會找自身的,自身沒有的話再沿着原型鏈找原型上是否有
屬性是否要放在原型下面,就要看該屬性是不是可變的,若是不是可變的,就能夠放在原型下面,用來公用屬性,可變的話放在構造函數下面。
this的指向問題:在事件或者定時器下比較容易出問題
2、包裝對象
一、咱們把系統自帶的對象,叫作系統對象。例如:Array,Date
二、包裝對象:基本類型都有本身對應的包裝對象:String,Number,Boolean
var str='hello';//基本類型:字符串類型
str.charAt(0);//基本類型會找到對應的包裝對象類型,而後包裝對象把全部的屬性和方法給了基本類型,而後包裝對象消失。
str.number=10;//在包裝對象下創一個對象,將屬性建立在對象下面,而後包裝對象就消失了,
alert(str.number);//會彈出undefined;緣由:會在包裝對象下從新建立一個對象
3、原型鏈
原型鏈:實例對象與原型之間的鏈接,叫作原型鏈
_proto_(隱式鏈接)
Object對象類型是原型鏈的最外層
實例對象->先查找本身自己下面的屬性和方法->自身沒找到會沿着原型鏈找到該對象的原型,再查看原型上是否有要查找的屬性或方法->依次繼續查找若是找到的話則返回,不然找到最頂層Object上尚未就真沒有了
4、面向對象中的屬性和方法
一、hasOwnProperty():看是否爲對象自身下面的屬性和方法
只有對象本身定義的屬性和方法則返回true,若是在prototype下定義發屬性和方法爲公用的,因此返回爲false;
二、constructor:查看對象的構造函數
(能夠用來檢測函數類型例如檢測是不是數組)
每一個原型函數都會自動添加constructor屬性(只會生成這一個屬性)
for in的時候有些屬性是找不到的(系統自帶的屬性是for in找不到的,本身定義的能夠找到)
避免修改constructor屬性
function Aaa(){} //Aaa.prototype.name='小米'; //Aaa.prototype.age=6; //alert(a1.constructor);//Aaa 緣由:只是給原型添加了屬性,並非從新賦值了,自動添加的constructor屬性還在。 Aaa.prototype={ // constructor:'Aaa',//須要手動修正指向問題 name:'小米', age:6 } var a1=new Aaa(); alert(a1.constructor);//Object 緣由:將原型的prototype從新賦值了,但裏面沒有constructor
注意:以這種方式重設constructor屬性會使它的[Enumerable]特性被設置爲true,默認狀況下,原生的constructor屬性是不可枚舉的。能夠經過Object.defineProperty()來修改。
三、instanceof:運算符
對象與構造函數在原型鏈上是否有關係,也能夠用做類型判斷但不是最好的方案,最好的方案是用toString 方法來判斷。
四、toString():object上的方法,把對象轉化爲字符串
var arr=[]; alert(arr.toString==Object.prototype.toString);//false //緣由:系統對象下面都是自帶的(例如數組的toString在Array.prototype下),本身寫的對象都是經過原型鏈找到object下面的toString function Aaa(){} var a1=new Aaa(); alert(a1.toString==Object.prototype.toString);//true
1>利用toString 進制轉化
Number.toString(進制);
var num=255; alert(num.toString(16));//ff---轉化爲16進制,默認不寫轉化爲十進制
2>利用toString作類型判斷:
//跨頁面的狀況下上面兩種狀況會失效 var oF=document.createElement('iframe'); document.body.appendChild('oF'); var ifArray=windows.frames[0].Array;//iframe下的Array數組 var arr=new ifArray(); alert(arr.constructor==Array);//false alert(arr instanceof Array);//false alert(Object.prototype.toString.call(arr)=='[object Array]');//true
var arr=[]; alert(Object.prototype.toString.call(arr));//[Object Array] var arr={}; alert(Object.prototype.toString.call(arr));//[Object Object] var arr=new Date; alert(Object.prototype.toString.call(arr));//[Object Date] var arr=new RegExp; alert(Object.prototype.toString.call(arr));//[Object RegExp] var arr=null; alert(Object.prototype.toString.call(arr));//[Object Null]
五 、繼承
一、繼承方式:
一、拷貝繼承:通用型 有new無new均可以用
二、類式繼承:new構造函數---利用構造函數(類)繼承的方式
三、原型繼承:無new的對象---藉助原型來實現對象繼承對象
屬性繼承:調用父類的構造函數call
方法繼承:用for in的形式 拷貝繼承(jq也用拷貝繼承)
var a = { name: '小米' }; //拷貝繼承 function extend(obj1, obj2) { for (var attr in obj2) { obj1[attr] = obj2[attr]; } } //原型繼承 var b=cloneObj(a); b.name='小喬'; alert(a.name); alert(b.name); function cloneObj(obj) { var F=function () {}; F.prototype=obj; return new F(); } //類式繼承 function A() {//父類 this.name='小米'; } A.prototype.showName=function () { alert(this.name); } function B() {//子類 A.call(this);//屬性和方法分開繼承 } //B.prototype=new A();//一句話實現繼承,但會有不少問題,好比指向問題,屬性會互相影響 //類式繼承改進:至少由如下四句實現方法的繼承,屬性須要分開繼承 var F=function () {}; F.prototype=A.prototype; B.prototype=new F(); B.prototype.constructor=A;//修正指向問題 var b1=new B(); b1.name='笑笑'; b1.showName();