要用面向物件的方式去編程,而不要用面向程序的方式去編程
物件是各種型別的資料的集合,可以是數字、字串、陣列、函式、物件……
物件中的內容以鍵值對方式進行存盤
物件要賦值給一個變數
var cat={ "name":"喵1", "age":4, "family":["喵爸","喵媽"], "speak":function(){ console.log("喵喵~"); }, "friend":{ "name":"喵2", "age":5 } }
上面是物件的字面量的創建方式,簡單直接
除此之外,還有物件的建構式的創建方式
var cat=new Object();
還有JavaScript5新增的一種方式
該方式在老版本的瀏覽器中存在兼容性問題
Object.create();
獲取、設定、添加、修改物件的值:
物件.屬性名=屬性值
物件[ 屬性名 ]=屬性值
var cat={ "name":"喵1", "age":4, "family":["喵爸","喵媽"], "speak":function(){ console.log("喵喵~"); }, "friend":{ "name":"喵2", "age":5 } } cat.name="喵喵1"; cat.age=6; cat.type="英短"; console.log(cat.name);//喵喵1 console.log(cat["age"]);//6 console.log(cat.type);//英短
洗掉物件的屬性:
delete 物件.屬性
var cat={ "name":"喵1", "age":4, "family":["喵爸","喵媽"], "speak":function(){ console.log("喵喵~"); }, "friend":{ "name":"喵2", "age":5 } } cat.type="英短"; console.log(cat.type);//英短 delete cat.type; console.log(cat.type);//undefined
檢測物件是否擁有某個屬性:
屬性名 in 物件
var cat={ "name":"喵1", "age":4, "family":["喵爸","喵媽"], "speak":function(){ console.log("喵喵~"); }, "friend":{ "name":"喵2", "age":5 } } console.log("name" in cat);//true console.log("type" in cat);//false
物件的列舉,遍歷物件中的各個屬性
var cat={ "name":"喵1", "age":4, "family":["喵爸","喵媽"], "speak":function(){ console.log("喵喵~"); }, "friend":{ "name":"喵2", "age":5 } } for(var p in cat){ console.log(p); //name age family speak friend }
var cat={ "name":"喵1", "age":4, "family":["喵爸","喵媽"], "speak":function(){ console.log("喵喵~"); }, "friend":{ "name":"喵2", "age":5 } } for(var p in cat){ console.log(p+": "+cat[p]); console.log(p);//獲取屬性名 //console.log(cat.p);// 寫法錯誤 console.log(cat[p]);//獲取屬性值 寫法正確 console.log(cat["n"+"ame"]);//喵1 []中可以添加字串的拼接等操作 }
匿名函式,如:
window.onload=function(){ }
函式一次執行完畢之后,會將區域作用域和區域變數銷毀,因此外部無法呼叫到
但函式本身并沒有被銷毀,可以進行多次呼叫執行
為什么要使用函式:
代碼復用(自己的代碼和別人的代碼,如jquery)
統一修改和維護
增加程式的可讀性
函式的本質:物件
定義方式:字面量定義、建構式定義
//字面量定義 function add(n1,n2){ } //建構式定義 new Function("n1","n2","....");
函式和物件一樣,可以添加屬性和方法
function person(){ console.log("cyy"); } //添加屬性 person.age=25; //添加方法 person.speak=function(words){ console.log(words); } console.log(person.age);//25 person.speak("hh~");//hh~ person();//cyy
函式可以作為資料值使用:
作為資料值保存在一個變數中
var fn=function(){ return "這是一個函式"; } console.log(fn());//這是一個函式 console.log(fn); /* ? (){ return "這是一個函式"; } */
此時fn列印出來的就是函式本體
函式也可以作為引數來使用:
function fn(){ alert(1); } setTimeout(fn,1000);//此處需要傳函式本體 //此處不能加括號,如果加了括號,會立刻呼叫,而不是等到1秒之后
函式可以作為回傳值使用:
function fn(){ return function(){ console.log("fn中的fn"); } } //呼叫 var newFn=fn(); newFn();//fn中的fn // 或者 fn()();//fn中的fn
函式的三種定義方式
// 字面量方式 // function 宣告 function add(){ } // var 賦值運算式 var add=function(){ }; //建構式 var add=new Function("num1","num2","return num1+num2"); add();
區別:
字面量方式比建構式方式簡潔
最重要的是預決議的區別
funtion宣告的函式,可以先呼叫,再創建
函式預決議的時候會提前定義
add(); function add(){ return 1; }
用var賦值運算式創建的函式,如果先呼叫,再創建,會報錯
因為var在預決議時賦值為undefined
add(); var add=function(){ return 1; };
function宣告和var賦值運算式宣告,這兩種都是很好的選擇
建構式過于復雜,不推薦使用
函式定義的位置
全域作用域下的函式,在哪里都能呼叫
add(); function add(){ add(); } add(); function fn(){ add(); }
區域作用域下的函式
//fn(); 無法呼叫 function add(){ fn(); function fn(){ fn(); function fn3(){ fn(); } } function fn2(){ fn(); } } //fn(); 無法呼叫
里層可以訪問外層的函式,外層不能訪問里層的函式
代碼塊中定義的函式:
由于js中沒有塊級作用域,所以依然是處于全域作用域中
都會出現預決議中函式被提前宣告
if(true){ function fn1(){ } }else{ function fn2(){ } }
改成下面這樣就可以實作按照條件進行宣告,也是因為預決議的機制
if(true){ var fn1=function (){ } }else{ var fn2=function fn2(){ } }
物件中的函式
使用物件.函式名進行呼叫
var person={ name:"cyy", setAge:function(age){ this.age=age;//this指向當前物件 } } person.setSex=function(sex){ this.sex=sex; } person.setAge(25); person.setSex("girl"); console.log(person.age);//25 console.log(person.sex);//girl
普通函式的呼叫:
命名函式的呼叫
function add(){ } add();
匿名函式的呼叫:
如果直接在匿名函式后面加上括號進行呼叫,會報錯
function(){ alert(1); }();//Uncaught SyntaxError: Unexpected token (
解決方法是,將這段匿名函式執行的代碼,賦值給一個變數
var fn=function(){ alert(1); }();//1
第二種解決方法:
將函式用括號括起來,實作匿名函式自執行
(function(){ alert(1); })();//1
括號把整體括起來也能實作一樣的效果
(function(){ alert(1); }());//1
或者在function前加上合法的字符也可以,如!+-~
!function(){ alert(1); }();//1
或者放在console.log里面
console.log(function(){ alert(1); }());
以上這些方式的共同目的,就是不讓匿名函式的function在開頭位置出現
遞回呼叫:
自己呼叫自己
實作階乘
function fn(num){ if(num<=1) return 1; return num*fn(num-1); } console.log(fn(5)); /* return 5*fn(4) return 5*4*fn(3) return 5*4*3*fn(2) return 5*4*3*2*fn(1) return 5*4*3*2*1 */
匿名函式也是函式,當它自執行的時候,會創建自己的函式內部作用域,在執行完畢之后會被銷毀,因此在外部無法訪問到自執行的匿名函式內部
//此處創建函式內部作用域 (function add(n1,n2){ return n1+n2; })(); console.log(add(3,4));//在全域無法訪問到函式內部的函式add
方法的呼叫:
物件中的方法,使用物件.方法名進行呼叫
var operation={ add:function(n1,n2){ return n1+n2; }, sub:function(n1,n2){ return n1-n2; } } console.log(operation.add(3,4));//7
以下這種也是方法,是點擊瀏覽器時瀏覽器自動幫我們完成呼叫;
也可以使用方法呼叫的方式來進行呼叫
document.onclick=function(){ alert(1); } document.onclick();//等同于點擊螢屏的效果
關于物件中的屬性,什么時候加引號,什么時候不加引號
對于合法的識別符號,加不加引號都可以;
不合法的識別符號,必須加引號,否則會引起報錯
var operation={ add:function(n1,n2){ return n1+n2; },//合法的屬性名可以不加引號 sub:function(n1,n2){ return n1-n2; }, "@":function(){ }//不合法的屬性名,會引起報錯,必須加引號 }
合法的識別符號,呼叫時使用物件.方法名即可
非法的識別符號,呼叫時使用物件[ " 方法名 " ]
var operation={ add:function(n1,n2){ return n1+n2; },//合法的屬性名可以不加引號 sub:function(n1,n2){ return n1-n2; }, "@":function(word){ alert(word); }//不合法的屬性名,會引起報錯,必須加引號 } console.log(operation.add(2,5));//7 console.log(operation["@"]("hh~"));//hh~
[ ] 加引號和不加引號的區別
var operation={ add:function(n1,n2){ return n1+n2; },//合法的屬性名可以不加引號 sub:function(n1,n2){ return n1-n2; }, "@":function(word){ return word; },//不合法的屬性名,會引起報錯,必須加引號 key:function(n1,n2){ return "key~"; } } var key="add"; console.log(operation.key(2,3));//key~ console.log(operation["key"](2,3));//key~ console.log(operation[key](2,3));//5
方法的鏈式呼叫
如jquery
$("p").html("html").css("color","red")....
物件中要使用鏈式呼叫,則方法中需要回傳當前物件
var operation={ add:function(n1,n2){ console.log(n1+n2); return this; }, sub:function(n1,n2){ console.log(n1-n2); return this; } } operation.add(5,3).sub(4,2); //要保證operation.add(5,3)能夠回傳operation物件 //就需要添加return this

建構式的呼叫:
建構式命名時一般首字母大寫
呼叫時用new+函式名,回傳值是一個物件
function Person(){ } var obj=new Person();
js中內置的建構式,常見的有:
Object() new Object() Array() new Array()
通過new關鍵字來呼叫
用建構式的方式定義物件和陣列,并添加內容
var person=new Object(); person.name="cyy"; var arr=new Array(); arr[0]=1;
函式的間接呼叫
.call 第一個引數是改變this的指向,后面傳遞引數的方式就是一個一個傳
.apply 第一個引數是改變this的指向,后面傳遞引數的方式是通過陣列來傳遞(或者類陣列)
var name="cyy"; var person={}; person.name="cyy2"; person.getName=function(){ return this.name;//此處的this指向person物件 } console.log(person.getName());//直接呼叫 cyy2 console.log(person.getName.call(window));//間接呼叫,此時this被指向了window,回傳的是window.name cyy console.log(person.getName.apply(window));//間接呼叫 cyy
function add(n1,n2){ return n1+n2; } console.log(add(1,2));//直接呼叫 3 console.log(add.call(window,1,2));//間接呼叫 3 console.log(add.apply(window,[1,2]));//間接呼叫 3
function add(n1,n2){ return n1+n2; } var arr=[4,6]; console.log(add.apply(window,arr));//10
只有函式擁有call和apply方法,兩者唯一的區別在于它們的傳參方式
函式的引數
引數傳遞的本質是將實參賦值給形參
引數的個數
1、形參個數=實參個數
function add(n1,n2){ return n1+n2; } console.log(add(3,5));
2、實參個數 < 形參個數
多用于有可選引數的情況
function pow(base,pow=2){ return Math.pow(base, pow); } console.log(pow(3));//9 console.log(pow(3,3));//27
3、實參個數 > 形參個數
如果無法得知有多少個實參,可以使用arguments
arguments是一個類陣列,用于保存實參的資訊
通過arguments[index] 獲取某一個引數
arguments.length 實參的個數
function add(){ if(arguments.length==0) return; var sum=0; for(var i=0,len=arguments.length;i<len;i++){ sum+=arguments[i]; } return sum; } console.log(add());//undefined console.log(add(1,2,3,4,5));//15
arguments 是類陣列,實質上還是物件
索引是陣列下標,數字開頭的變數名不合法,因此需要加引號
{ '0': 1, '1': 2, '3': 4, length: 3 }
可以通過arguments來修改引數的值
function speak(m){ arguments[0]=""; return m; } console.log(speak("hh"));//空
arguments是每個函式中獨有的,不會跨函式
function fn1(){ console.log(arguments);//Arguments [1, callee: ?, Symbol(Symbol.iterator): ?] function fn2(){ console.log(arguments);//Arguments [2, callee: ?, Symbol(Symbol.iterator): ?] } fn2(2); } fn1(1);
arguments.callee 指代函式本身
function add(){ console.log(arguments.callee); } add();
arguments.callee 常用于遞回中
function factorial(num){ if(num==1) return 1; return num*factorial(num-1); } console.log(factorial(5));//120 function factorial(num){ if(num==1) return 1; return num*arguments.callee(num-1); } console.log(factorial(5));//120
不過在嚴格模式下,不允許使用arguments.callee(也不允許不使用var宣告變數)
此時的解決方法就是將函式賦值給一個變數,這樣函式本身的名字不會影響呼叫
"use strict"; var myfn=function factorial(num){ if(num==1) return 1; return num*factorial(num-1); } console.log(myfn(5));//120
實參的個數 arguments.length
形參的個數 函式名.length 或者arguments.callee.length
function add(n1,n2){ if(arguments.length != add.length) throw new Error("請傳入"+add.length+"個引數!"); } console.log(add(5));//Uncaught Error: 請傳入2個引數!
什么做引數
1、沒有引數
2、數字做引數
3、字串( 如選擇DOM節點,$("p") )
4、布林值(保持函式的純潔性,建議一個函式只做一件事情)
5、undefined(可選引數必須放在最后)
6、null
7、陣列
$.each(["a","b","c"],function(index,item)){ console.log(index);//0 1 2 console.log(item);//a b c }
8、物件
$.each({name:"cyy",age:24},function(index,item)){
console.log(index);//name age
console.log(item);//cyy 24
}
使用物件作為引數的好處(可以自由調換順序)
function fn(obj){ var person={}; person.name=obj.name||"cyy"; person.age=obj.age||24; person.tel=obj.tel||110, person.addr=obj.addr||"China"; return person; } var cyy={ name: "cyy1", age:25 } console.log(fn(cyy));//{name: "cyy1", age: 25, tel: 110, addr: "China"}
9、函式
回呼函式,如 setTimeout(fn, time);
函式的回傳值
return:
表示函式結束
將值回傳
什么可以做回傳值:
直接return ,回傳值是undefined
數字
字串 :alert() 輸出的都是字串,會默認呼叫.toString() 方法
布林值:常用于表單驗證
null 和 undefined
陣列
function add(n1,n2){ return [n1,n2,n1+n2]; } console.log(add(5,6));//(3) [5, 6, 11]
物件
function fn(){ return { name:"cyy", age:25 } }
注意return后面不要換行,否則默認是分號,到此結束;于是后面的會報錯
function fn(){ //return會默認后面是分號,結束 return { name:"cyy", age:25 } }
函式
需要用()()來呼叫
document.write() 執行時會呼叫.toString() 方法,嘗試將結果轉換為字串形式
document.write([1,2,3]);//1,2,3 document.write({ name:"cyy" });//[object Object] document.write({ name:"cyy", toString:function(){ return "hh~"; } });//hh~
function count(){ var num=1; return function(){ return num++; } } //每次呼叫count()時,num都會被初始化 //并且return num++ 是先回傳num,再執行++ console.log(count()());//1 console.log(count()());//1 console.log(count()());//1 //count()只執行了一次,因此num只初始化一次 //后面能夠每次都進行遞增+1 var fn=count(); console.log(fn());//1 console.log(fn());//2 console.log(fn());//3
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/149828.html
標籤:JavaScript
上一篇:JavaScript運動_封裝模板(支持鏈式運動、完美運動)
下一篇:判斷作用域輸出值
