純屬筆記,增強記憶,不是教程,歡迎糾錯,沒有邏輯,不太適合學習使用。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>