JS介紹 數據輸出\輸入 JS變數 JS數據類型 進位介紹 數字(Number) 字元串(String) Boolean類型/Undefined類型/Null類型 類型轉換 運算符 流程式控制制 break與continue關鍵字 數組(Array) 函數(function) 函數中的幾個參數 sort ...
JS介紹
// JavaScript的發明人 // 布蘭登·艾奇(Brendan Eich),用了十天時間發明瞭JavaScript模型 // JavaScript簡稱JS // JavaScript是什麼? // 1.腳本語言 // 編譯語言:需要把代碼編譯成電腦所認知的二進位語言才能執行 // 腳本語言:不需要編譯,直接執行 // 2.解釋性語言 // 解釋性語言:遇到一行代碼就解釋一行代碼 // 其他語言:把所有代碼編譯完成後在執行代碼 // 3.動態類型的語言 // 4.基於對象的語言 // 5.弱類型語言 // 弱類型語言:聲明變數都用var,會自動辨別類型:var num = 10; var num2 = 10.23; // 強類型語言:聲明變數的時候必須寫上對應變數的類型:int num = 10; double num2 = 10.23; // JS分三個部分: // 1.ECMAScript js的基本語法 // 2.DOM Document Object Model 文檔對象模型 // 3.BOM Browser Object Model 瀏覽器對象模型 // js代碼註意問題 // 1.如果script的標簽中有錯誤的js代碼,那麼這對script標簽就不會執行 // 2.如果有一個script標簽代碼錯誤,但它不會影響其他的script標簽 // 3.script標簽在頁面中可以多對出現 // 4.script標簽一般放在body標簽內容的最後,可以放在head中 // 5.如果script標簽引用外部js文件,那麼就不要在這對標簽裡面放任何js代碼
數據輸出\輸入
// 在瀏覽器彈出的提示框中顯示 alert(); // 在瀏覽器的控制臺中顯示 console.log(); // 在瀏覽器頁面中顯示 document.write(); // 在瀏覽器中彈出輸入框 prompt();
JS變數
/*什麼是變數: 變數是電腦記憶體中存儲數據的標識符,根據變數名可以獲取到記憶體中存儲的數據*/ /*為什麼使用變數: 使用變數可以方便的獲取或者修改記憶體的數據*/ // 變數的作用: // 操作數據:存儲數據、讀取數據 /*變數名的規範: 一般以字母,$符號,下劃線開頭 變數名一般都是小寫,如果是多個單詞,那麼第一個單詞的首字母小寫,後面的單詞首字母大寫 變數名不能是關鍵字 區分大小寫*/ // 變數聲明 var name;// 有var 有變數名字但沒有賦值 // 聲明多個變數 var name,age,sex; // 變數的初始化:聲明變數同時賦值 var xiu = undefined;// 聲明變數沒有賦值預設為undefined:未定義 var number = 20;// 存儲一個數字(number) var name = "修抗";// 存儲一個字元串(string) 字元串應該用單引號或者雙引號包裹起來 var flag = true;// 存儲一個真(true) 假(false) var nll = null;// 存儲一個空(null) // 聲明多個變數依次賦值 var num1,num2,num3; num1 = 10; num2 = 20; num3 = 30; // 聲明多個變數並賦值 var num1 = 10,num2 = 20,num3 = 30; // 變數的交換(1) var num1 = 10,num2 = 20; var num3;//重新聲明一個變數 num3 = num1;//num3 = num1 = 10 num1 = num2;//num1 = num2 = 20 num2 = num3;//num2 = num3 = 10 // 變數的交換(2)一般適用於數字的交換 var num4 = 10,num5 = 20; num4 = num4 + num5;//10+20=30 num5 = num4 - num5;//30-20=10 num4 = num4 - num5;//30-10=20 // 變數的交換(3) var num6 = 10,num7 = 20; num6 = num6 ^ num7; num7 = num6 ^ num7; num6 = num6 ^ num7;
JS數據類型
/* 原始數據類型:number,string,boolean,undefined,null,object 基本類型:number,string,boolean 複雜類型:object 空類型:undefined,null 基本類型的值在棧空間存儲 復類類型的值在堆空間存儲,然後在棧空間引用堆空間的地址 */ // 獲取變數的數據類型 var xiu = "修抗"; console.log(typeof(xiu)); //string
進位介紹
// 八進位(數字前面加一個0代表八進位) var num = 012; // 十進位 var num2 = 10; // 十六進位(數字前面加一個0x代表十六進位) var num3 = 0xa; /*二進位-->十進位 1----1----0----0----1----0----1----0----1(二進位) 256--128--64---32---16---8----4----2----1 256--128--0----0----16---0----4----0----1(十進位) 二進位:110010101 = 256+128+0+0+16+0+4+0+1 = 405:十進位 */ /*二進位-->八進位 110----010----101(二進位) 6------2------5(八進位/每三位二進位為一組) 二進位:110010101 = 625:八進位 */ /*二進位-->十六進位 1----1001----0101(二進位) 1----9-------5(十六進位/每四位二進位為一組) 二進位:110010101 = 195:十六進位 */ /*十進位-->二進位 405-202-101-50--25--12--6---3---1 1---0---1---0---1---0---0---1---1(倒敘) 十進位:405 = 110010101:二進位 */
數字(Number)
// 小數類型和整數類型都是數字類型(Number) //數字的最大值和最小值 console.log(Number.MAX_VALUE);//最大值 console.log(Number.MIN_VALUE);//最小值 // Infinity 無窮大 // -Infinity 無窮小 // 小數的bug console.log(0.1+0.2);//結果不是0.3而是0.30000000000000004 // 不要用NaN驗證NaN var xiu; console.log(xiu+10);//返回NaN console.log("你好" == "我好");//false:都是字元串,但是字元串內容不一樣 console.log(xiu+10 == NaN);//false:都是NaN,但是裡面的值不一樣 // isNaN()判斷是否不是數字,如果不是數字返回true
console.log(isNaN(NaN));
字元串(String)
// 字元串可以使用單引號,也可以使用雙引號 var str = "xiu "; var str2 = 'kang'; // 查看字元串的長度 console.log(str.length); // 字元串拼接,用+鏈接 // 如果兩邊只要有一邊為字元串,那麼+就為拼接 // 如果兩邊都是數字。那麼就是算術功能 var str3 = "1"; var str4 = '2'; console.log(str3 + str4);//12
Boolean類型/Undefined類型/Null類型
// Boolean類型 // 布爾類型只有兩個值 true(真) false(假) var flag = true; // Undefined // 表示聲明一個變數沒有賦值,變數只有聲明的時候值預設為undefined var unde = undefined; // null類型 // 表示一個空,變數的值如果為空,必須手動設置 var str = null;
類型轉換
// 其他類型轉為數字類型:三種方式 // parseInt();轉整數 console.log(parseInt("8sa"));//8 console.log(parseInt("as8"));//NaN console.log(parseInt("8.9"));//8 console.log(parseInt("8.2as"));//8 console.log(parseInt("sa6.8"));//NaN // parseFloat();轉小數 console.log(parseFloat("8sa"));//8 console.log(parseFloat("as8"));//NaN console.log(parseFloat("8"));//8 console.log(parseFloat("8.9as"));//8.2 console.log(parseFloat("sa6.8"));//NaN // Number();轉數字 console.log(Number("8sa"));//NaN console.log(Number("as8"));//NaN console.log(Number("8"));//8 console.log(Number("8.9as"));//NaN console.log(Number("sa6.8"));//NaN // 其他類型轉為字元串類型:兩種方式 // toString;不能轉換沒有意義的變數:null、undefined var xiu = 10; console.log(xiu.toString()); // String(); var kang = 20; console.log(String(kang)); // 其他類型轉為布爾類型 // Boolean(); console.log(Boolean(0));//false console.log(Boolean(""));//false console.log(Boolean(null));//false console.log(Boolean(undefined));//false
運算符
// x+y // x和y是操作數 +是操作符 // 算術運算符(+、-、*、/、%) 10%4;//10除於4的餘數 // 一元運算符(++、--) // 這個運算符只需要一個操作數就可以運算的表達式 // 前+ 後+ 前- 後- var x = 2; var y = 2; console.log(x++ +3);//5,後+,先參與運算,運算結束後在+1 console.log(x);//3 console.log(++y +3);//6,前+,先+1,然後在參與運算 console.log(y);//3 // 二元運算符() // 這個運算符需要兩個個操作數就可以運算的表達式 // 三元運算符() // 這個運算符需要三個操作數就可以運算的表達式 // var 變數 = 表達式1 ? 表達式2 : 表達式3 // 如果表達式1結果為true,就執行表達式2,然後把表達式2的結果給變數 // 如果表達式1結果為false,就執行表達式3,然後把表達式3的結果給變數 var sear = true ? 1 : 2;//sear=1 // 複合運算符(+=、-=、*=、/=、%=) var num; num+=10;//num=num+10; // 關係運算符(<、>、<=、>=、!=、==、===、!=、!==) var xiu = "10"; var kang = 10; console.log(xiu==kang);//兩個值都一樣所以為true console.log(xiu===kang);//值一樣,但是類型不一樣所有為false // 邏輯運算符($$與-並且、 ||或-或者、 !非-取反、) console.log(true && true);//兩個為true則為true console.log(true || false);//一個為true則為true console.log(!false);//false為true,true為false /* 運算符的優先順序 1.() 優先順序最高 2.一元運算符 ++ -- ! 3.算術運算符 先* / 後 + - 4.關係運算符 < <= > >= 5.相等運算符 == != === !== 6.邏輯運算符 先&& 在|| 7.賦值運算符 = */
流程式控制制
// 流程式控制制:代碼的執行過程 // 流程式控制制的三種方式: // 1.順序結構 // 從上到下,從左往右執行的順序叫順序結構(不嚴謹) // var xiu = 2;(不嚴謹的原因:先找到2,然後在將2賦值給xiu) // 2.分支結構 // if語句 /* if(表達式1) { 代碼塊1 }else if(表達式2) { 代碼塊2 }else { 代碼塊3 } 先運行表達式1,如果表達式1為true就執行的代碼塊1,如果為false就執行表達式2 如果表達式2,如果表達式2為true就執行的代碼塊2,如果為false就執行代碼塊3 else if()可以多次出現,也可以不寫 else 只能出現一次,也可以不寫 */ var x = prompt("請輸入數字");//prompt()彈出一個輸入框 if(x > 5){ console.log("大於5"); }else if(x < 5) { console.log("小於5"); }else if(x == 5) { console.log("等於5"); }else { console.log("請輸入數字"); } // switch-case /* switch(表達式){ case 值1: 代碼塊;break; case 值2: 代碼塊;break; case 值3: 代碼塊;break; default:代碼4; } 獲取表達式的值,然後和值依次比較,如果和值相等執行相對應的代碼塊,遇到break跳出switch語句 如果和值都不相等,那麼就執行default語句 表達式的值跟case的值比較是嚴格模式的比較(===) default可以省略 break可以省略:省略後不會跳出語句 會依次往下執行 */ var y = prompt("請輸入1到3的整數"); switch(y){ case "1":console.log(y); break;//該語句為跳出語句 case "2":console.log(y); break; case "3":console.log(y); break; default:console.log("請輸入1到3的整數"); } // 三元表達式 // 3.迴圈結構 // while /* var 變數 = 0; while(條件){ 迴圈體; 計數器; } 如果條件為false,就不執行while大括弧裡面的內容 如果條件為true,就執行迴圈體,然後執行計數器,迴圈結束後計數器+1,然後又去判斷條件,直到條件為false停止迴圈 */ var xiu = 0;//計數器 while(xiu<10){ console.log(xiu);//迴圈體 xiu++;//計數器+1 } // do-while /* do { 迴圈體 }while(條件); 先執行迴圈體,然後在判斷條件是否成立,如果為true繼續執行迴圈體,然後在判斷條件,直到條件為false跳出迴圈 */ var kang = 0; do { console.log(kang); kang++; }while(kang<0); // for /* for(表達式1;表達式2;表達式3;){ 迴圈體; } 先獲取表達式1的值,然後判斷表達式2,如果為false跳出迴圈,如果為true就執行迴圈體然後在執行表達式3,然後繼續執行表達式2,直到條件為false */ for (var i = 1; i <= 10; i++) { console.log(i); }
break與continue關鍵字
// break關鍵字 // 作用:在迴圈中使用,遇到break則跳出當前迴圈 while(true){ console.log("修抗"); break;//本來是一個死迴圈,但是遇到break就跳出迴圈,所有就執行一次 } // continue關鍵字 // 作用:在迴圈中使用,遇到continue直接執行下次迴圈 // 輸出10以內的奇數 var i = 0; while(i<10){ if(i%2==0){ i++; continue;//如果為偶數就繼續下次迴圈 } document.write(i); i++; }
數組(Array)
// 數組:存儲一組有序的數據 // 作用:可以一次性存儲多個數據 // 數組的定義: /* 1.通過構造函數創建數組 var 數組名 = new Array(); var 數組名 = new Array(長度); 如果Array中只有一個值(整數),那麼這個值就是該數組的長度(元素就個數) 如果有多個值,那麼這些值就是該數組的數據(數組的長度就是有多少個值) */ var array = new Array();//創建一個空數組,沒有數據 var array2 = new Array("25");//如果數組中沒有數據,但有長度,那麼數組的每個值就是undefined /* 2.通過字面量的方式創建數組 var array = []; */ var array3 = [];//創建空數組 var array4 = [3,34,46,7];//創建數組並添加數據 /* 數組元素:就是數組中存儲的數據 數組個數:就是數組中元素的個數 數組下標:從0開始,到數組長度減1結束 通過下標設置數組元素值:數組名[下標] = 值 通過下標訪問數組元素值:數組名[下標] */ // 獲取數組的長度 array.length; // 註意: 數組中的數據類型可以不一樣,但一般存儲一樣的數據,數組的長度可以任意改變 var array5 = [10,"哈哈",true,undefined,null,new Object()]; // 遍曆數組 var array6 = [2,5,72,58,3,52]; for(var i=0;i<array6.length;i++){ console.log(array6[i]); } // 求數組的和 var array7 = [1,2,3,4,5]; var sum = 0; for(var i=0;i<array7.length;i++){ sum+=array7[i]; } console.log(sum); // 求數組的平均值 var array8 = [1,2,3,4,5]; var avg = 0; for(var i=0;i<array8.length;i++){ avg+=array8[i]; } console.log(avg/array8.length); // 求數組的最大值 var array9 = [1,2,3,4,5]; var max = array9[0]; for(var i=1;i<array9.length;i++){ if(max<array9[i]){ max=array9[i]; } } console.log(max); // 數組的倒敘 var array10 = [1,2,3,4,5]; for(var i=array10.length-1;i>=0;i--){ console.log(array10[i]); } // 去掉數組中的0 var array11 = [1,0,3,0,5]; var newArray11 = []; for(var i=0;i<array11.length;i++){ if(array11[i] != 0){ newArray11[newArray11.length] = array11[i]; } } console.log(newArray11); // 冒泡排序:把所有數據按照一定順序進行排序(從大到小,從小到大) var arr = new Array(3,36,2,47,42,436,54); for (var i=0;i<arr.length-1;i++) { for(var j=0;j<arr.length-1-i;j++){ if(arr[j]>arr[j+1]){ var tame = arr[j]; arr[j] = arr[j+1]; arr[j+1] = tame; } } } console.log(arr);
函數(function)
/* 函數:將重覆的代碼進行封裝,在需要的時候進行調用 定義函數: function 函數名(){ 函數體; } 調用函數: 函數名(); 函數參數: 定義函數的時候,函數名後面的小括弧里的變數就是參數 function 函數名(x,y){ 函數體; } 形參:定義函數時小括弧裡面的參數 function 函數名(x,y){ 函數體; } 實參:調用函數時小括弧裡面的參數 函數名(x,y); 函數的返回值: 在函數內部有return關鍵字並且關鍵字後面有內容,那麼這個內容就是返回值 在調用的時候,如果需要返回值,就定義變數接收就行了 function 函數名(){ return 520; } var fun = 函數名();//此時fun變數的值就是函數返回的值 無參數無返回值的函數 function xiu(){ console.log("修抗"); } 無參數有返回值的函數 function xiu(){ return "修抗"; } 有參數無返回值的函數 function xiu(x,y){ console.log(x+y); } 有參數有返回值的函數 function xiu(x,y){ return x+y; } 命名函數:函數有名字 匿名函數:函數沒有名字 定義匿名函數: function(){ 函數體; } 匿名函數不能直接調用,需要賦值給變數才能調用(這就是函數表達式) var fun = function(){ 函數體; } fun();//在變數後面添加小括弧就可以調用匿名函數了 函數的自調用: (匿名函數)(); (function(){alert("修抗");})(); 函數做為參數使用: 如果一個函數作為參數使用,那麼這個參數(函數)就是回調函數 function xiu(){ kang(); } function kang(){ 函數體; } 函數做為返回值使用: function xiu(){ return function(){ 函數體; }; } var kang = xiu();//將xiu的返回值賦值給變數,現在變數就是一個函數 kang();//直接加小括弧掉用就行了 註意: 函數一旦重名,就會把前面的函數覆蓋 匿名函數就不會出現重名的問題 形參和實參的個數可以不一致 函數沒有明確返回值,但調用的時候接收了,那麼接收的值為undefined 沒有明確返回值:沒有return或者return後面沒有跟任何內容 return後面的代碼不會執行 函數也有數據類型:function類型 */
函數中的幾個參數
function f1(x,y){ //獲取的函數的名字,只讀 console.log(f1.name); // 獲取實參的個數 console.log(f1.arguments.length); // 獲取形參的個數 console.log(f1.length); // 調用者,如果該函數被其他函數調用,那麼該屬性就輸出其他函數的源碼 console.log(f1.caller); } f1(1,2);
sort()
// sort()對數組的元素進行排序,並返回數組 var arr = ["dfg","dgh","dsgar"]; arr.sort(function(x,y){ if(x>y){ return 1; }else if(x==y){ return 0; }else { return -1; } }); console.log(arr);
閉包
/* 閉包的概念: 在函數A中有一個函數或者對象,該函數或者對象可以訪問函數A中定義的變數或者數據,此時形成了閉包 閉包的模式: 函數模式的閉包,對象模式的閉包 閉包的作用: 緩存數據,延長作用域鏈 閉包的優點缺點: 優點:可以緩存數據,缺點:緩存數據的同時不能釋放空間 局部變數是在函數中,函數使用結束後,局部變數就會被自動釋放 閉包後,裡面的局部變數的使用作用域就會被延長,不會被釋放 */ // 函數模式的閉包:在一個函數中有一個函數 function f1(){ var num = 10; function f2(){ console.log(num); } f2(); } f1(); // 對象模式的閉包:在一個函數中有一個對象 function f3(){ var num = 3; var obj = {age:num}; console.log(obj.age); } f3(); // 列子: function person(){ var num = 1; return function(){ num++; console.log(num); } } var per = person(); per();//2 per();//3 per();//4
沙箱
作用域
/* 局部變數:在函數內部定義的變數叫局部變數,只能在函數內部才能使用 全局變數:除了函數以外在其他任意位置定義的變數叫全局變數,可以在頁面任意位置使用 隱式全局變數:聲明變數的時候沒有var就是隱式全局變數(可以在頁面任意位置使用) 局部作用域:局部變數的使用範圍 全局作用域:全局變數的使用範圍 塊級作用域:大括弧裡面定義的變數只能在當前大括弧裡面使用,而js不支持塊級作用域(函數除外) 註意: 定義全局變數,只要頁面不關閉就會一直占空間,消耗記憶體(就是卡),只有在頁面隔壁的時候才會釋放空間 定義局部變數,就只有在調用的時候占空間,調用完後就會釋放空間(所以儘量使用局部變數) 全局變數不能被刪除而隱式全局變數可以被刪除,刪除變數(delete 變數名;) 作用域鏈: var sum = 0; function f1(){ var sum = 1; f2(); function f2(){ var sum = 2; f3(); function f3(){ var sum = 3; alert(sum); } } } 如果當前沒有變數就會去上一級找變數,沒有繼續去上一級,直到全局變數,這就是作用域鏈 */
預解析
// 預解析:提前解析代碼 // 提前解析變數 console.log(sum);//輸出undefined var sum = 0; /* 理解:瀏覽器幫我們做的事,瀏覽器將聲明變數提前了,但沒有把賦值提前 var sum; console.log(sum);//因為聲明變數沒有賦值,所以就是undefined sum = 0; */ // 提前解析函數 xiu(); function xiu(){ console.log("愛心"); } /* 理解:瀏覽器幫我們做的事,瀏覽器將聲明的函數提前了 function xiu(){ console.log("愛心"); } xiu(); */ // 同時解析函數和變數 kang(); function kang(){ console.log(str); } var str = "埃辛"; /* 理解:瀏覽器幫我們做的事,瀏覽器先將聲明的變數提前然後在將聲明的函數提前 var str; function kang(){ console.log(str); } kang(); str = "埃辛"; */
函數聲明出現的問題
/* 函數的聲明 function f1(){} 函數表達式 var f1 = function(){}; */ if(true){ function f1(){ console.log("true"); } }else { function f1(){ console.log("false"); } } f1(); // 在IE10及之前輸出的結果都是false,因為會把函數的聲明提前 // 解決辦法就是使用函數表達式,函數表達式不會被提前 var f2; if(true){ f2 = function(){ console.log("true"); } }else { f2 = function(){ console.log("false"); } } f2();
創建對象
/* 編程思想: 把一些生活中的經驗融入到程式中 面向過程: 每件事的具體過程要知道,註重的是過程 面向對象: 所有的事都用對象來做,註重的是結果 面向對象的基本特性: 封裝,繼承,多態(抽象性) 對象的特征: 有屬性或者方法
面向對象的編程思想:
根據需求,找出相關的對象,總結對象的特征和行為,把特征變成屬性,行為變成方法,然後定義構造函數,實例化對象,通過對象調用屬性或者方法,完成對應的需求,這就是編程思想 js不是面向對象的語言,但是可以模擬面向對象的思想 js是一門基於對象的語言 */ // 第一種方式創建對象:調用系統自帶的構造函數 new Object() var obj = new Object(); obj.name = "修抗"; //添加屬性1 obj.sex = "男"; //添加屬性2 obj.xiu = function(){ //添加方法1 console.log("方法1"); } obj.kang = function(){ //添加方法2 console.log("方法2"); } // 調用屬性的兩種方式 console.log(obj.name); //對象.屬性 console.log(obj["sex"]); //對象["屬性"] // 調用方法的兩種方式 obj.xiu(); //對象.方法名() obj["kang"](); //對象["方法名"]() // 第二種方式創建對象:自定義一個構造函數,然後在創建對象 // 創建自定義構造函數,構造函數與函數的區別在於首字母是否大寫 function Person(name,age){ //添加屬性 this.name = name; this.age = age; //添加方法 this.type = function(){ console.log("我叫"+this.name+",今年"+this.age+"歲"); }; } //調用自定義的構造函數創建對象,同時對屬性進行初始化(實例化對象) var obj2 = new Person("修抗",24); // 調用屬性和方法 console.log(obj2.name); obj2.type(); // 第三種方式創建對象:工廠模式創建對象 // 把創建對象的代碼放在函數中,返回值就是這個對象, function createObject(name,age){ var obj3 = new Object(); obj3.name = name; obj3.age = age; obj3.xiu = function(){ console.log("我叫"+this.name+",今年"+this.age+"歲"); } return obj3; } var kang = createObject("修抗",20); kang.xiu(); // 第四種方式創建對象:字面量創建對象 // 方式1: var obj4 = {}; obj4.name = "修抗";// 添加屬性 obj4.type = function(){// 添加方法 alert("方法"); } // 方式2: var obj5 = { name: "修抗", type:function(){ alert("方法2") } };
遍歷對象的屬性和值
var obj = { name : "修抗", age : 20 } for(key in obj){ console.log(key);//屬性 console.log(obj[key]);//值 }
工廠模式和自定義構造函數的區別
// 自定義創建對象 function Penson(name){ this.name = name; } var obj = new Penson("修抗"); console.log(obj.name); //工廠模式創建對象 function createObj(){ var obj2 = new Object(); obj2.name = "愛心"; return obj2; } var obj3 = createObj(); console.log(obj3.name); /* 自定義創建對象與工廠模式創建對象的區別 自定義創建對象: 函數名是大寫(首字母) 沒有new 沒有返回值 this是當前對象 通過new的方式創建對象 工廠模式創建對象: 函數名是小寫 有new 有返回值 new之後的對象是當前對象 直接調用函數就可以創建對象 他們的共同點:都是函數,都可以創建對象,都可以傳入參數 */
構造函數和實例對象之間的關係
// 自定義構造函數創建對象 function Person(name){ this.name = name; } //實例化對象 var obj = new Person("修抗"); // console.dir()可以把對象的構造顯示出來 console.dir(Person);//輸出構造函數 console.dir(obj);//輸出實例化對象 console.log(Person.prototype.constructor == Person);//true console.log(obj.__proto__.constructor == Person);//true console.log(obj.constructor == Person);//true console.log(obj instanceof Person);//true /* 實列對象和構造函數的關係 實列對象是通過構造函數來創建的,創建的過程叫實例化 判斷對象的數據類型(自定義對象) 1. 通過構造器的方式: 實列對象.構造器(constructor) == 構造函數的名字 obj.constructor == Person 2. 對象 instanceof 構造函數名字 obj instanceof Person */
構造函數創建對象帶來的問題
function Person(name,age){ this.name = name; this.age = age; this.type = function(){ console.log("修抗"); } } var obj1 = new Person("修抗",20); var obj2 = new Person("修抗",20); // 他們指向的方法不是同一個方法,那麼就開闢了不同的空間,浪費記憶體 console.log(obj1.type == obj2.type);//false // 解決辦法 function f1(){ console.log("修抗"); } function Person2(name){ this.name = name; this.type = f1; } var obj3 = new Person2("修"); var obj4 = new Person2("修"); // 此時他們指的是同一個方法,節省空間,但函數可能重名,發生不必要的問題 console.log(obj3.type == obj4.type);//true // 可以使用原型解決該辦法:原型的作用之一就是數據共用,節省記憶體空間
原型及原型鏈
//構造函數 function Person(name,age){ this.name = name; this.age = age; } // 實例化對象並初始化 var p1 = new Person("修抗",20); var p2 = new Person("愛惜",20); console.dir(Person);//查看構造函數的結構 console.dir(p1);//查看實列對象的結構 /* 實列對象中有兩個屬性(這兩個屬性是通過構造函數獲取的) 構造函數中並沒有name和age這兩個屬性 實列對象中有個屬性,__proto__,也是對象,叫原型,不是標準屬性,瀏覽器使用的 構造函數中有個屬性,prototype,也是對象,叫原型,是標準屬性,程式員使用的 constructor:構造函數 */ // 實列對象和構造函數的原型指向的是同一個構造函數 console.log(Person.prototype.constructor == p1.__proto__.constructor);//true // 通過原型添加方法 Person.prototype.type = function(){ console.log("修抗"); } // 因為他們指向的是同一個原型裡面的構造函數裡面的方法,是同一個方法 console.log(p1.type == p2.type);//true // 原型鏈:是一種關係,實列對象和原型對象之間的關係,關係是通過原型(__proto__)來聯繫的
改變原型的指向和添加改變後的原型方法
function Person(){}; Person.prototype.sayHi = function(){ console.log("打招呼"); }; function Student(){}; Student.prototype.eat = function(){ console.log("牛皮"); }; Student.prototype = new Perso