js面向對象學習

純屬筆記,增強記憶,不是教程,歡迎糾錯,沒有邏輯,不太適合學習使用。javascript

--------------java

繼承多態等太多概念難以理解,仍是從實踐中慢慢學吧!爭取能大體看懂網上的開源的代碼。數組

--------------瀏覽器

對象的組成:方法和屬性函數

屬性關鍵詞:靜止的,狀態學習

方法關鍵詞:動態的,過程,處理,帶括號測試

--------------this

js中的面向對象不是其餘語言那樣的面向對象。spa

 1         <script type="text/javascript">
 2         //定義arr爲一個數組(數組也是一個對象實例,因此arr是個對象實例)
 3         var my_arr=[];
 4         //之前變量這樣用,var number=10; 
 5         //如今定義屬性,arr.number = 10; 就是用「點」便可!
 6         my_arr.number = 10;
 7         //定義對象的方法
 8         my_arr.test = function(){
 9             console.log(this); 
10             //這裏this就是這個數組,直接用數組名也能夠
11             //alert(my_arr.number);
12             //alert(this.number);
13         }
14         //這樣使用方法
15         my_arr.test();
16     </script>
17 
18     

這裏須要注意的是,能不能將第6行放在第3行前面?prototype

不能夠,沒有到第3行賦值,my_arr仍是undefined,而undefined是不能有特性的。

1         <script type="text/javascript">
2             var a ='ddd';
3             a.kkk = 'eee';
4             console.log(a.kkk); //火狐,打印出undefined ,可見,a不是一個對象類型的數據時,還不能夠直接加「點」呢
5             a.ka =  function (){
6                 console.log('aaaaaaaaaaaaaaaaaa');
7             }
8             a.ka(); //報錯,a.ka is not a function 可見,a不是一個對象類型的數據時,還不能夠直接加「點」賦予方法呢
9         </script>
 1         <script type="text/javascript">
 2             var a ='ddd';
 3             String.prototype.kkk = 'eee';
 4             a.kkk = 'eeeddd';
 5             console.log(a.kkk); //火狐,打印出eee ,可見,a不是一個對象類型的數據時,還不能夠直接加「點」呢,可是從字符串的原型上能夠加
 6             String.prototype.ka =  function (){
 7                 console.log('aaaaaaaaaaaaaaaaaa');
 8             }
 9             a.ka(); //aaaaaaaaaaaaaaaaaa
10         </script>

 

結果是數組有個number屬性和test方法,可是數組內容爲空,length爲0,可是這樣alert(my_arr['number']);也能夠彈出10

//TODO 之後再研究數組,可是可見,數組的內容是內容,屬性和內容不是一回事,內容是數組裏面存了啥,屬性是這個數組實例有什麼屬性。如同,一個是汽車裏裝了誰誰,一個是汽車有車大燈的感受。

------------

新建一個純淨的對象實例

 1     <script type="text/javascript">
 2         var my_obj = new Object(); //新建一個對象實例my_obj,換成 var my_obj = {}; 也行,一個意思
 3         my_obj.name = '張三'; //加個屬性
 4         my_obj.test = function(){ //加個方法
 5             this.test2(); //對象的A方法中用到對象的B方法
 6         }
 7         my_obj.test2 = function(){
 8             console.log(this.name);
 9         }
10         my_obj.test(); //使用
11     </script>

 對象中思考變量做用域的問題

之前學到變量做用域,都是函數和變量,如今加入對象,看看是怎麼回事

1     <script type="text/javascript">
2         console.log(my_obj); // 顯示undefined,說明解析器中和其餘類型同樣,根據var,先放個undefined再說
3         var my_obj = {};
4         console.log(my_obj); // 顯示 Object {}
5         my_obj.name = '張三';
6         console.log(my_obj); // 顯示Object {name:"張三"}
7     </script>

其實能夠這樣理解,js解析器,預解析,根據var找到了my_obj,賦值undefined,若是放到不用對象的時候,出個name,須要var name一下,這裏因爲對象var了,對象下各個目前未定義的屬性就至關於已經var但沒賦值了,一旦測試都是undefined。第4行,因爲尚未賦予name屬性,若是查看my_obj.name的話,就是undefined,而第5行賦值,第6行再看,就是「張三」了。

1     <script type="text/javascript">
2         var my_obj = {};
3         my_obj.name = '張三';
4         console.log(my_obj.test); //undefined
5         my_obj.test(); //瀏覽器提示出錯,說test不是一個函數。可見my_obj.test = function(){...} 只是一個賦值,並無由於是function,就扔到預解析倉庫中
6         my_obj.test = function(){
7             console.log(this.name);
8         }
9     </script>
1     <script type="text/javascript">
2         var my_obj = {};
3         my_obj.name = '張三';        
4         my_obj.test = xxx;
5         my_obj.test(); //這樣寫是能夠執行的,由於函數xxx扔到預解析倉庫了,上一行又賦予test這個函數了,顯示張三
6         function xxx(){
7             console.log(this.name);
8         }
9     </script>
<script type="text/javascript">
        var my_obj = {};
        my_obj.name = '張三';        
        my_obj.test = function xxx(){
            console.log(this.name);
        };
        my_obj.test(); // 正常運行
    
        
    </script>
 1 <script type="text/javascript">
 2         var my_obj = {};
 3         my_obj.name = '張三';        
 4         my_obj.test = function xxx(){
 5             console.log(this.name);
 6         };
 7         xxx(); //瀏覽器報錯,火狐認爲,xxx未定義,也就是說,在等號後面的函數不會被預解析,這裏不求預解析,連解析都沒有
 8     </script>

 

 1     <script type="text/javascript">
 2         var my_obj = {
 3             name : "張三",
 4             test : function(){
 5                 //對象也是個變量做用域,這裏面是可使用對象外面的函數的
 6                 //console.log(name); 不能夠這樣用,不能由於name和test平級,就不加this,屬性名和變量是不一樣的,要加上對象名才能用
 7                 console.log(this.name); //console.log(my_obj.name); 這樣也行
 8             }
 9         };
10         my_obj.test(); //顯示張三
11         console.log(my_obj.name); //想使用對象的屬性,就要加對象名
12         
13     </script>

-----------------------

這裏新建對象不夠靈活,若是要建的對象名不是張三呢,而是好幾個,張三,李四,王二,麻子等不少人,那麼就要用到工廠方式

還按照上面的方式就是以下代碼

 1         <script type="text/javascript">
 2             var my_obj1 = {
 3                 name: "張三",
 4                 test: function() {
 5                     console.log(this.name); //若是是console.log(my_obj2.name); 將顯示李四,也就是用到了其餘對象的屬性。
 6                 }
 7             };
 8             
 9             var my_obj2 = {
10                 name : "李四",
11                 test : function(){
12                     console.log(this.name);
13                 }
14             }
15             my_obj1.test(); //顯示張三
16             my_obj2.test(); //顯示李四
17         </script>

js並非其餘語言那樣的面向對象,這裏的對象,實際上是其餘語言中 對象實例的意思。

上面代碼怎麼精簡呢,共同部分用一個函數來生成便可,也就是所謂的工廠模式,以下

 1         <script type="text/javascript">
 2             function CreatePerson(name){ //這個function就至關於一個生產對象的工廠
 3                 var obj = new Object();
 4                 obj.name = name;
 5                 obj.test = function() {
 6                     console.log(this.name);
 7                 }
 8                 return obj;
 9             }
10             
11             var my_obj1 = CreatePerson('張三'); //開始生產了
12             var my_obj2 = CreatePerson('李四');
13             my_obj1.test();//使用工廠生產出來的對象
14             my_obj2.test();
15         </script>

在js中,用new去調用一個函數的話,這個函數中的this就是建立出來的對象,並且函數的返回值直接就是this  隱式返回

難以理解這句吧,就是js規定的,函數加new, 函數中的this就是對象實例自己,而且函數返回該對象實例(不用你操做了,js幫你搞定)。

1         <script type="text/javascript">
2             function CreatePerson(name){
3                 this.name = name;
4                 console.log(this); //打印出的this就是張三  這裏就至關於js幫你作了 var my_obj1 = new Object(); 最後return my_obj1;
5             }
6             var my_obj1 = new CreatePerson('張三');
7             console.log(my_obj1); //打印出的my_obj1就是張三
8         </script>

這樣調用 

var my_obj1 = new CreatePerson('張三'); 是否是很像  var date = new Date();
 1         <script type="text/javascript">
 2             function CreatePerson(name){
 3                 this.name = name;
 4                 this.test = function(){
 5                     console.log(this.name);
 6                 }
 7             }
 8             
 9             var my_obj1 = new CreatePerson('張三');
10             my_obj1.test();
11         </script>

 可是這樣仍是有問題,每一個對象實例的方法,都是在內存總新建的,用prototype來對相同的對象實例方法進行定義,使之共用內存。改造以下

 1         <script type="text/javascript">
 2             function CreatePerson(name){
 3                 this.name = name;
 4             }
 5             
 6             CreatePerson.prototype.test = function(){
 7                 console.log(this.name);
 8             }
 9             
10             var my_obj1 = new CreatePerson('張三');
11             var my_obj2 = new CreatePerson('李四');
12             
13             alert(my_obj1.test == my_obj2.test); //true
14             my_obj1.test(); // 張三
15             my_obj2.test(); // 李四
16             
17         </script>

這裏面的對象這樣去記憶理解容易點。 my_obj1和my_obj2是具體的某我的,是對象的實例。而CreatePerson是人這一類,是構造函數。在CSS中,有行內樣式 <div style="...."></div> 或者寫成 <div class="..."></div>這裏。用構造函數加上prototype的方式,相似於class,能普遍用於不少個個體對象實例,而直接加在個體上的方法就只能用於個體,同時,兩者有重名衝突的時候,個體上的方法優先級較高。

 

 1         <script type="text/javascript">
 2             function CreatePerson(name){
 3                 this.name = name;
 4             }
 5             
 6             CreatePerson.prototype.test = function(){
 7                 console.log(this.name);
 8             }
 9             
10             var my_obj1 = new CreatePerson('張三');
11             var my_obj2 = new CreatePerson('李四');
12             
13             //爲my_obj1這個個體又單獨加個test。prototype定義的test對該個體來講失效
14             my_obj1.test = function(){
15                 console.log(this.name+'111');
16             }
17 
18             alert(my_obj1.test == my_obj2.test); //false
19             my_obj1.test(); // 張三111
20             my_obj2.test(); // 李四
21             
22         </script>

再看看最開始怎麼定義my_obj1,直接 var my_obj1 = new Object(); 或者寫 var obj = {};這也是js的面向對象,到如今用構造函數的方式,一個是直接定義到個體,一個是先定義一個種類,而後再出個體。

使用原型再舉個例子,求數組中元素的和,以下

 1         <script type="text/javascript">
 2             var arr_1 = [1,9,3,5];
 3             Array.prototype.sum = function(){
 4                 var result = 0;
 5                 for (var i=0;i<this.length;i++) {
 6                     result += this[i];                    
 7                 }
 8                 return result;
 9             }
10             
11             console.log(arr_1.sum());//18
12         </script>

原型要加在構造函數上

 1         <script type="text/javascript">
 2             var arr_1 = [1,9,3,5];
 3             var arr_2 = [3,5,7];
 4             Array.prototype.sum = function(){
 5                 var result = 0;
 6                 for (var i=0;i<this.length;i++) {
 7                     result += this[i];                    
 8                 }
 9                 return result;
10             }
11             arr_1.sum = function(){
12                 return '我要覆蓋prototype的方法!';
13             }
14             
15             console.log(arr_1.sum());//我要覆蓋prototype的方法!
16             console.log(arr_2.sum());//15
17         </script>

----------------

js是基於原型的程序

每一個基本類型數據都有一個原型,字符串 String  數字 Number 布爾值 Boolean 數組 Array 

儘可能不要去修改系統對象下面的方法和屬性。

例子:重寫數組的push方法

 1         <script type="text/javascript">
 2             var arr = [1,2,3];
 3             Array.prototype.push = function(){//這裏系統自帶的push就被覆蓋了
 4                 for(var i=0; i<arguments.length;i++){
 5                     this[this.length] = arguments[i];
 6                 }
 7                 return this.length;
 8             }
 9             
10             arr.push(9,8,7,6,5);
11             console.log(arr);
12         </script>

---------------

包裝對象:基本類型(除了null 和 undefined)都有本身對應的包裝對象,如String Number  Boolean,這裏也就知道了,null空對象和undefined未定義是不能再添加屬性和方法的

        <script type="text/javascript">
            var str1 ='hello123';            
            var str2 = new String('hello123');//經過new建立的都是對象
            
            console.log(typeof str1);//string
            console.log(typeof str2);//object
        </script>
 1         <script type="text/javascript">
 2             var str1 = 'hello123';
 3             var str2 = new String('hello123'); //經過new建立的都是對象
 4 
 5             console.log(typeof str1); //string
 6             console.log(typeof str2); //object
 7             str2.lastvalue = function() {
 8                 return this.charAt(this.length - 1);
 9             }
10             console.log(str2.lastvalue());//最後一個字符3
11             
12             str1.lastvalue = function() { //報錯,由於str1是字符串,不是對象,不能添加方法,只能使用其包裝對象給予的方法
13                 return this.charAt(this.length - 1);
14             }
15             console.log(str1.lastvalue());
16         </script>

若是str1這個字符串類型數據,要添加方法,那能夠添加到它的包裝對象上。以下

1         <script type="text/javascript">
2             var str1 = 'hello123';
3             String.prototype.lastvalue = function(){
4                 return this.charAt(this.length-1);
5             }
6             console.log(str1.lastvalue());
7         </script>

-----------------------------

原型鏈:個體實例和原型之間的連接 , 原型鏈的最外層是Object.prototype

 舉例:個體人物:張三 / 原型:男人 

張三具備屬性:姓名:張三;

 1     <script type="text/javascript">
 2         function Man(name){
 3             this.name = name;
 4         }
 5         Man.prototype.name = '男人';
 6         Object.prototype.name = '人類';
 7         
 8         var Zhanshan = new Man('張三');
 9         console.log(Zhanshan.name); //顯示張三,若是沒有第3行代碼,則根據原型鏈,顯示爲男人,若是連第5行也沒有,則顯示爲人類
10         //console.log(Man.prototype.name); //顯示男人,若無第5行,則顯示爲人類
11     </script>

 也就是注意層級關係。沒有找到的屬性就往原型鏈上找,優先級固然是內層優先。

 

-------------------

------------------

面向對象的一些屬性和方法

hasOwnProperty  :  對象個體實例自身是否是有某個屬性?若是是個體自身的屬性返回true; 若是屬性是原型下的,返回false;

1     <script type="text/javascript">
2         function Man(name){
3             this.name = name;
4         }
5         Man.prototype.name = '男人';
6         
7         var Zhanshan = new Man('張三');
8         console.log(Zhanshan.hasOwnProperty('name')); //true
9     </script>
1     <script type="text/javascript">
2         function Man(name){
3             //this.name = name;
4         }
5         Man.prototype.name = '男人';
6         
7         var Zhanshan = new Man('張三');
8         console.log(Zhanshan.hasOwnProperty('name')); //false
9     </script>
    <script type="text/javascript">
        function Man(name){
            //this.name = name;
        }
        Man.prototype.name = '男人';
        
        var Zhanshan = new Man('張三');
        Zhanshan.name = '張三三';
        console.log(Zhanshan.hasOwnProperty('name')); //true
    </script>
    <script type="text/javascript">
        function Man(){
            this.name = '張三';
        }
        Man.prototype.name = '男人';
        
        var Zhanshan = new Man('張三');
        console.log(Zhanshan.hasOwnProperty('name')); //true 雖然新建個其餘的個體實例,name也會是張三,可是該個體實例自身有name屬性,因此仍是true
        
    </script>

 

 constructor : 查看對象的構造函數

1     <script type="text/javascript">
2         function Man(name){
3             this.name = '張三';
4         }
5         Man.prototype.name = '男人';
6         
7         var Zhanshan = new Man('張三');
8         console.log(Zhanshan.constructor == Man); //true
9     </script>
1     <script type="text/javascript">
2         var a1 = [1,2,3];
3         console.log(a1.constructor = Array); //true
4     </script>

當咱們寫一個函數時,程序自動會生成constructor

1     <script type="text/javascript">
2         function Aaa(){    
3         }
4         //注意,下面這句話是系統內部自動實現的,這裏寫出來,好看到系統作了什麼,只要定義一個函數,系統都會"自動生成"下面一句
5         //Aaa.prototype.constructor = Aaa; //這裏能夠自行更改,將覆蓋,如Aaa.prototype.constructor = Array;可是亂改後將影響使用
6         console.log(Aaa.prototype);
7         //只有constructor是函數原型自身的,hasOwnProperty這個方法是Object上的,是經過原型鏈找到的
8     </script>

如今知道不要更改constructor,可是有時候,不注意咱們就更改了,以下:

1     <script type="text/javascript">
2         function Aaa(){    
3         }
4         Aaa.prototype.name = '張三';
5         Aaa.prototype.age = 30;
6         
7         var a1 = new Aaa();
8         console.log(a1.constructor); //Aaa
9     </script>

上面咱們知道,Aaa.prototype也是一個對象,上面的改寫爲以下形式,就更改了constructor

 1     <script type="text/javascript">
 2         function Aaa(){    
 3         }
 4         //這裏更改了,不是更改屬性,而是從新對Aaa.prototype進行了賦值,也就弄丟了constructor屬性
 5         Aaa.prototype = {
 6             name:"張三",
 7             age :30
 8         }        
 9         var a1 = new Aaa();
10         console.log(a1.constructor); //Object
11 
12     </script>

 因此,當咱們按照上面這張方法寫的時候,要加上修正的,變成以下

 1     <script type="text/javascript">
 2         function Aaa(){    
 3         }
 4         //弄丟的constructor屬性再找回來
 5         Aaa.prototype = {
 6             constructor:Aaa, //注意不要加引號,注意這句話就是爲了修正對象constructor屬性
 7             name:"張三",
 8             age :30
 9         }        
10         var a1 = new Aaa();
11         console.log(a1.constructor); //Aaa
12     </script>

 

 還有一個地方注意:用for in循環對象的屬性的時候,系統自帶的屬性是循環不到的

 1     <script type="text/javascript">
 2         function Aaa(){    
 3         }
 4         Aaa.prototype.name = '張三';
 5         Aaa.prototype.age = 30;
 6         Aaa.prototype.constructor = Aaa;    
 7         var a1 = new Aaa();
 8         for (var attr in Aaa.prototype) {
 9             console.log(attr); //顯示了name和age,可是不顯示constructor,即便還單獨寫一次
10         }
11     </script>

 可是,若是用= 從新賦值的方式,再循環打印是能夠打印出來的哦!以下

 1     <script type="text/javascript">
 2         function Aaa(){    
 3         }
 4         //這種方式是從新賦值
 5         Aaa.prototype = {
 6             constructor:Aaa, //注意不要加引號,注意這句話就是爲了修正對象constructor屬性
 7             name:"張三",
 8             age :30
 9         }        
10         var a1 = new Aaa();
11         for (var attr in Aaa.prototype) {
12             console.log(attr); //顯示constructor  name  age
13         }
14     </script>

 instanceof 運算符,判斷個體對象和原型函數 是否有原型鏈上的關係,返回true或false 以下

 1     <script type="text/javascript">
 2         function Man(name){
 3             this.name = name;
 4         }
 5         function Woman(name){
 6             this.name = name;
 7         }
 8         var zhanshan = new Man();
 9         console.log(zhanshan instanceof Man); //true
10         console.log(zhanshan instanceof Object); //true
11         console.log(zhanshan instanceof Woman); //false
12     </script>

 

用instanceof判斷某變量是不是數組

1     <script type="text/javascript">
2         var a1 = [1,2,3,4,5];
3         console.log(a1 instanceof Array); //true;
4         
5         var b1 = 'hi';
6         console.log(b1 instanceof Array); //false;
7     </script>

toString 方法  把對象轉成字符串 。 系統對象下面都是自帶的,而本身建立的對象toString在object上

以下

1     <script type="text/javascript">
2         var a1 = [1,2,3,4,5];
3         console.log(a1.toString == Object.prototype.toString); //false 系統對象下面都是自帶的,不是Object上的;
4         console.log(a1.toString == Array.prototype.toString); //true 系統對象下面都是自帶的,在Array上 不在Object
5         function Bbb(){
6         }
7         var b1 = new Bbb();
8         console.log(b1.toString == Object.prototype.toString); //true 本身建立的對象toString在object上
9     </script>

 

 

1     <script type="text/javascript">
2         var a1 = [1,2,3,4,5];
3         console.log(a1.toString()); //1,2,3,4,5
4         console.log(typeof a1.toString()); //string
5     </script>

 

 1     <script type="text/javascript">
 2         var a1 = [1,2,3,4,5];
 3         console.log(a1.toString()); //1,2,3,4,5
 4         console.log(typeof a1.toString()); //string
 5         
 6         //按照系統toString生成的1,2,3,4,5 若是不符合咱們使用的格式的話,咱們還能夠本身去改寫
 7         Array.prototype.toString = function(){
 8             return this.join('+'); //將數組內容按照加號鏈接
 9         }
10         console.log(a1.toString()); //1+2+3+4+5
11     </script>

 

1     <script type="text/javascript">
2         var num = 255;
3         console.log(num.toString(16)); //ff, 參數16是16進制的意思,輸出16進制的數據  rgb色彩能夠用~~
4         console.log(num.toString(2)); // 11111111  參數2是2進制的意思 
5     </script>

 

上面是利用toString轉換數字進制

toString還能夠用來判斷變量的數據類型,比typeof   instanceof  更精準,以下

 1     <script type="text/javascript">
 2         var num = 255;
 3         console.log(Object.prototype.toString.call(num)); // [object Number]
 4         console.log(Object.prototype.toString.call(num) == '[object Number]');  // true;
 5         
 6         var str = 'hello';
 7         console.log(Object.prototype.toString.call(str)); // [object String]
 8         var arr = [1,2,5];
 9         console.log(Object.prototype.toString.call(arr)); // [object Array]    
10         
11         console.log(Object.prototype.toString.call({name:'張三'})); //[object Object]
12         
13     </script>

 -------------

對象的繼承  繼承要求原類不變,新出子類

如何作?

 

 1     <script type="text/javascript">
 2         function CreateUser(name,age){
 3             this.name = name;
 4             this.age = age;
 5         }
 6 
 7         CreateUser.prototype.dosometing = function(){
 8             console.log(this.name+'dosometing');
 9         }
10 
11         var Zhanshan = new CreateUser('張三',39);
12         Zhanshan.dosometing();
13 
14         function CreateStar(name,age,job){
15             CreateUser.call(this,name,age); //這句話完成了屬性的繼承
16             this.job = job;//這句話添加父級沒有的新屬性
17         }
18 
19         CreateStar.prototype = CreateUser.prototype; //這句話完成了方法的繼承,可是根據對象賦值可知,這裏,子類對象的變化,父類對象亦變。不是完美的方式。
20         
21 
22         var Lichen = new CreateStar('李晨',40,'演員');
23         console.log(Lichen.name + '是個' + Lichen.job);
24         Lichen.dosometing();
25         
26         console.log(Lichen.constructor); //CreateUser 由於直接CreateStar.prototype = CreateUser.prototype; 因此這裏不是CreateStar
27         
28         console.log(CreateStar.prototype.constructor); //CreateUser
29         console.log(CreateUser.prototype.constructor); //CreateUser
30         console.log(CreateUser.prototype.constructor == CreateStar.prototype.constructor); //true;
31         
32     </script>
相關文章
相關標籤/搜索