函數(shù)
函數(shù):函數(shù)就是封裝了一段可以重復(fù)執(zhí)行的代碼塊。
function fn(){
console.log('我是函數(shù)')
}
fn();
function getSum(a,b){
return a +b;
}
console.log(getSum(1, 2));
- 函數(shù)不調(diào)用自己不執(zhí)行
- 調(diào)用函數(shù)的時候,千萬別忘了加小括號
- 一次聲明函數(shù),可以調(diào)用多次
- 封裝,就類似打包
返回值
- 代碼執(zhí)行到return 關(guān)鍵字后,會跳出當(dāng)前函數(shù),后續(xù)與代碼不再執(zhí)行
- 函數(shù)的返回值是什么。調(diào)用這個函數(shù)就相當(dāng)于調(diào)用了什么
- 沒有返回值的函數(shù)相當(dāng)于返回了undedined
function fn2(){
alert('fn2內(nèi)部的代碼')
}
console.log(fn2()) //先彈出'fn2內(nèi)部的代碼',然后控制臺打印undefined
小細節(jié) : break ,continue ,return 的區(qū)別
break 結(jié)束當(dāng)前的循環(huán)體 (for while )
continue跳出本次循環(huán),繼續(xù)執(zhí)行下次循環(huán)(for while )
return 返回return 中的值 同時結(jié)束當(dāng)前的函數(shù)體內(nèi)的代碼
arguments的使用
JavaScript中,arguments對象是比較特別的一個對象,實際上是當(dāng)前函數(shù)的一個內(nèi)置屬性。也就是說所有函數(shù)都內(nèi)置了一個arguments對象,arguments對象中存儲了傳遞的所有的實參。arguments是一個偽數(shù)組,因此及可以進行遍歷
偽數(shù)組定義:
a.具有l(wèi)ength屬性;
b.按索引方式儲存數(shù)據(jù);
c.不具有數(shù)組的push,pop等方法;
當(dāng)我們不確定有多少個參數(shù)傳遞的時候,可以用arguments 來獲取
定義函數(shù)有兩種方式
- 函數(shù)關(guān)鍵字自定義函數(shù)方式
// 命名函數(shù) 有函數(shù)名 為 fn
function fn() { ....}
// 調(diào)用 那個地方調(diào)用都可以
fn()
語法格式:
// 這是 函數(shù)表達式 寫法 匿名函數(shù)后面跟分號結(jié)束
var fn = function () { .... };
// 調(diào)用的方式 但是這個方式,函數(shù)調(diào)用必須寫到函數(shù)體下面
fn();
- 函數(shù)沒有名字,我們稱為匿名函數(shù)
- 這個fn 里面存儲的是一個函數(shù)
- 這個執(zhí)行的原理 跟我們 學(xué)的 變量使用一致的。
- 調(diào)用的方式 但是這個方式,函數(shù)調(diào)用必須寫到函數(shù)體下面
自執(zhí)行函數(shù)(了解)
- 匿名函數(shù)可以作為啟動函數(shù),定義后立即自執(zhí)行
(function () {
alert('我是匿名函數(shù),被自執(zhí)行啦~~!');
})();
匿名函數(shù)自動執(zhí)行寫法的,最大的好處,就是 防止命名沖突, 這種函數(shù)永遠不會沖突。
值類型和引用類型
var num1 = 10;
var num2 = num1;
num1 =20;
console.log(num1); //20
console.log(num2); //10
棧速度比堆快。
fnuction Person(name,age){
this.name = name;
this.age = age;
}
var p1 = new Person('zs',18);
var p2 = p1; //復(fù)制引用
p2.name = 'ls';
console.log(p1.name); //ls
console.log(p2.name); //ls
作用域
全局變量和局部變量
- 全局作用域
供所有代碼執(zhí)行的環(huán)境(整個script標(biāo)簽內(nèi)部) 或者一個獨立的js文件中
- 局部作用域(函數(shù)作用域)
會形成一個執(zhí)行函數(shù)內(nèi)代碼的新環(huán)境。
- 全局變量
- 在全局作用域下聲明的變量叫做全局變量(在函數(shù)外部定義的變量)
- 全局變量在代碼的任何位置都可以使用
- 特殊情況, 再函數(shù)內(nèi) 不var 聲明 的 變量 也是全局變量 (不建議使用)
- 局部變量
- 在局部作用域下聲明的變量叫做局部變量(在函數(shù)內(nèi)部定義的變量)
- 局部變量只能在該函數(shù)內(nèi)部使用
注意
-
在函數(shù)內(nèi)部不聲明直接賦值使用的變量也算是全局變量
-
函數(shù)的形參實際上就是局部變量
-
局部變量當(dāng)其所在的代碼塊被執(zhí)行時,會被初始化,當(dāng)代碼塊運行結(jié)束后,就被銷毀了,節(jié)省內(nèi)存空間。
-
全局變量因為任何一個地方都可以使用,只有再瀏覽器關(guān)閉才會銷毀,比較占內(nèi)存。
-
只要是代碼,就至少有一個作用域
-
寫在函數(shù)外部的是全局作用域
-
寫在函數(shù)內(nèi)部的局部作用域
-
如果函數(shù)中還有函數(shù),那么在這個作用域中就又可以誕生一個作用域。
-
根據(jù)在內(nèi)部函數(shù)可以訪問外部函數(shù)變量的這種機制,用鏈?zhǔn)讲檎覜Q定哪些數(shù)據(jù)能被內(nèi)部函數(shù)訪問。 就稱作作用域鏈。
-
局部變量,寫在函數(shù)內(nèi)部,當(dāng)我們函數(shù)執(zhí)行完畢后,里面的局部就會自動銷毀,釋放內(nèi)存,比較節(jié)省資源。
-
全局變量 只有瀏覽器關(guān)閉的時候才會銷毀,比較浪費資源。
-
作用域鏈:我們按照鏈?zhǔn)椒绞饺ゲ檎?,最終決定我們變量執(zhí)行那個值的過程(就近原則)
預(yù)解析
JavaScript代碼是由瀏覽器中的JavaScript解析器來執(zhí)行的。JavaScript解析器在運行JavaScript代碼的時候,分為兩步:預(yù)解析和代碼執(zhí)行
學(xué)習(xí)預(yù)解析能夠讓我們知道 為什么在變量聲明之前訪問變量 值是undefined 為什么在函數(shù)聲明之前就可以調(diào)用函數(shù)
-
預(yù)解析過程
- JavaScript解析器會在全局環(huán)境下查找 var、function關(guān)鍵字,變量只聲明不賦值,函數(shù)聲明不調(diào)用。
- 預(yù)解析只發(fā)生在當(dāng)前作用域下
-
預(yù)解析也叫做變量、函數(shù)提升
- 變量提升
定義變量的時候,變量的聲明會被提升到當(dāng)前作用域的最上面,變量的賦值不會提升。
- 函數(shù)提升
JavaScript解析器首先會把當(dāng)前作用域的函數(shù)聲明提前到整個作用域的最前面
- 變量名和函數(shù)名相同,優(yōu)先執(zhí)行 函數(shù)
-
執(zhí)行過程
- 變量賦值、函數(shù)調(diào)用、表達式運算等等。
- 首先把所有的var function 進行代碼提升。提升到當(dāng)前作用域的最前面
- 變量提升的是聲明并不賦值,函數(shù)只提升聲明,并不調(diào)用。
console.log(num2);
var num2 = 20;
//相當(dāng)于執(zhí)行了下面的代碼
var num2;
console.log(num2); //undefined;
num2 = 20;
什么是對象?
- 現(xiàn)實生活中:萬物皆對象,對象是一個具體的事物。 看得見摸得著實物。一本書、一輛汽車、一個人都可以是“對象”,一個數(shù)據(jù)庫、一張網(wǎng)頁、一個與遠程服務(wù)器的連接也可以是“對象”。
對象調(diào)用:
- 對象里面的屬性調(diào)用 : 對象.屬性名 這個小點 就理解為 的
- 對象里面的屬性另外調(diào)用方式 : 對象['屬性名'] 注意 方括號里面的屬性 必須加 引號 我們后面會用
- 對象里面的方法調(diào)用: 對象.方法名() 注意這個方法名字后面一定加括號
console.log(star.name) // 調(diào)用 名字屬性
console.log(star.age) // 調(diào)用 年齡屬性
star.sayHi(); // 調(diào)用 sayHi 方法 注意,一定不要忘記帶后面的括號
函數(shù)和方法的區(qū)別:
- 函數(shù)是單獨存在的, 調(diào)用的時候 函數(shù)名() 就可以了
- 方法是再對象里面, 調(diào)用的時候,對象.方法名()
new Object 創(chuàng)建對象
var stuObj = new Obect();
stuObj.name = 'james';
stuObj.age = 11;
stuObj.sex = true;
stuObj.sayHi = function(){
alert('大家好啊~');
}
- 跟我們前面學(xué)的 new Array() 一樣。
- Object() 是構(gòu)造函數(shù) 第一個字母大寫
- new Object() 是調(diào)用構(gòu)造函數(shù) 因為構(gòu)造函數(shù)需要new 來調(diào)用 同時再內(nèi)存中創(chuàng)建一個對象
- 注意里面使用的時候用點 . 不是 冒號 :
自定義構(gòu)造函數(shù)
我們可以和以前封裝函數(shù)一樣, 想創(chuàng)建多個對象,不用一個個的創(chuàng)造對象了。
抽象可以將具有相同或相似功能的js代碼獨立出來封裝成一個函數(shù),這樣可以提高代碼的重復(fù)利用率,提高代碼書寫的效率,也可以有效的減少代碼的冗余。
我們這個函數(shù)里面封裝的對象, 為了和以前區(qū)別顯示不同。 我們稱為構(gòu)造函數(shù)。
- 構(gòu)造函數(shù)用于創(chuàng)建某一大類對象,首字母要大寫。
- 構(gòu)造函數(shù)要和new一起使用才有意義。
function Person(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
this.sayHi = function() {
alert('我的名字叫:' + this.name + ',年齡:' + this.age + ',性別:' + this.sex);
}
}
var bigbai = new Person('大白', 100, '男');
var smallbai = new Person('小白', 21, '男');
console.log(bigbai.name);
console.log(smallbai.name);
new在執(zhí)行時會做四件事情
- new會在內(nèi)存中創(chuàng)建一個新的空對象
- new 會讓this指向這個新的對象
- 執(zhí)行構(gòu)造函數(shù)里面的代碼 目的:給這個新對象加屬性和方法
- new會返回這個新對象 (所以構(gòu)造函數(shù)里面不需要return)
this詳解
JavaScript中的this指向問題,有時候會讓人難以捉摸,隨著學(xué)習(xí)的深入,我們可以逐漸了解
現(xiàn)在我們需要掌握函數(shù)內(nèi)部的this幾個特點
1. 函數(shù)在定義的時候this是不確定的,只有在調(diào)用的時候才可以確定
2. 一般函數(shù)直接執(zhí)行,內(nèi)部this指向全局window
3. 函數(shù)作為一個對象的方法,被該對象所調(diào)用,那么this指向的是該對象(誰調(diào)用指向誰)
4. 構(gòu)造函數(shù)中的this 對象的實例
// 1. 普通函數(shù)
function fn() {
console.log(this); // this 指向 window
}
fn();
// 2 對象方法
var obj = {
name: 'zs',
dance: function() {
console.log(this);
that = this;
}
}
obj.dance(); // this 指向 obj
console.log(that === obj); // true
// 3 構(gòu)造函數(shù)
function Fn() {
this.age = '18';
console.log(this)
self = this;
}
var demo = new Fn(); // this 指向 demo
console.log(self === demo); // true
對象是封裝了相關(guān)屬性和方法的復(fù)雜數(shù)據(jù)類型
本質(zhì):對象就是一組無序的相關(guān)屬性和方法的集合
注意: 函數(shù)用來按功能封裝代碼,對象用來按功能封裝方法和屬性,都起到復(fù)用代碼和數(shù)據(jù)的作用。
|