1.函數(shù)的定義和調(diào)用
1.1 函數(shù)的定義方式
1.1.1 函數(shù)聲明
語法:
function func() {};
1.1.2 函數(shù)表達(dá)式
語法:
var func = function() {};
1.1.3 構(gòu)造函數(shù)
語法:
var func = new Function("參數(shù)1", "參數(shù)2",..., "函數(shù)體");
注意:
-
Function
里面參數(shù)都必須是字符串格式 - 第三種方式執(zhí)行效率低,也不方便書寫胯甩,所以使用較少。
- 所有函數(shù)都是
Function
的實例(對象) - 函數(shù)也屬于對象命贴。
1.2 函數(shù)的調(diào)用
// 1.函數(shù)聲明
function fn() {
console.log("人生巔峰");
}
// fn();
// fn.call();
// 2.對象的方法
var o = {
sayHi: function() {
console.log("hi~");
}
}
// o.sayHi();
// 3.構(gòu)造函數(shù)
function Star() {};
// var star = new Star();
// 4.綁定事件函數(shù)
// btn.onclick = function() {}; // 點(diǎn)擊了按鈕就可以調(diào)用
// 5.定時器函數(shù)
// setInterval(function() {}, 1000); // 定時器 1s 調(diào)用一次
// 6.立即執(zhí)行函數(shù)
(function() {
console.log("立即執(zhí)行函數(shù)");
})();
2.this
2.1 函數(shù)內(nèi)部的 this 指向
這些 this
的指向,是當(dāng)我們調(diào)用函數(shù)的時候確定的抢埋,調(diào)用方式不同決定了不同的 this
指向,一般指向調(diào)用者。
// 函數(shù)不同的調(diào)用方式?jīng)Q定了 this 不同的值
// 1.普通函數(shù)的 this 指向 window
function func() {
console.log("普通函數(shù)的 this " + this);
}
func();
// 2.對象的方法的 this 指向 對象 o
var o = {
sayHi: function() {
console.log("對象方法的 this " + this);
}
}
o.sayHi();
// 3.構(gòu)造函數(shù)的 this 指向 star 這個實例對象裳食,
// 原型對象里面的 this 指向的也是 star 這個實例對象。
function Star() {};
Star.prototype.sing = function() {}
var star = new Star();
// 4.綁定事件函數(shù)的 this 指向的是函數(shù)的調(diào)用者芙沥,也就是 btn 這個按鈕對象
var btn = document.querySelector("button");
btn.onclick = function() {
console.log("綁定事件函數(shù)? this " + this);
}
// 5.定時器函數(shù)的 this 指向的是 window
setInterval(function() {
console.log("定時器的 this " + this);
}, 1000);
// 6.立即執(zhí)行函數(shù)的 this 指向的是 window
(function() {
console.log("立即執(zhí)行函數(shù)額 this " + this);
})();
2.2 改變函數(shù)內(nèi)部 this 指向
2.2.1 使用 call 方法
call()
方法簡單理解為調(diào)用函數(shù)的方式诲祸,但是它可以改變函數(shù)的 this
指向。
應(yīng)用場景:使用 call
完成繼承
function Father(uname, age, sex) {
this.uname = uname;
this.age = age;
this.sex = sex;
}
function Son(uname, age, sex) {
Father.call(this, uname, age, sex);
}
var son = new Son("ldh", 18, "男");
console.log(son);
2.2.2 使用 apply 方法
apply()
方法簡單理解為調(diào)用函數(shù)的方式憨愉,但是它可以改變函數(shù)的 this
指向烦绳。
應(yīng)用場景:經(jīng)常跟數(shù)組有關(guān)
var arr = [1, 66, 4, 99];
console.log(Math.max.apply(Math, arr));
apply
和 call
主要的不同在于參數(shù)傳遞的形式不同卿捎,前者必須指定每一個參數(shù)配紫,后者則是以數(shù)組的形式傳遞的。
2.2.3 使用 bind 方法
bind()
方法不會調(diào)用函數(shù)午阵,但是能改變函數(shù)內(nèi)部的 this
指向躺孝,返回的是原函數(shù)改變 this
之后產(chǎn)生的新函數(shù),如果只是想改變 this
指向底桂,并且不想調(diào)用這個函數(shù)的時候植袍,可以使用 bind
。
語法:
fun.bind(thisArg, arg1, arg2, ...);
- thisArg:在
fun
函數(shù)運(yùn)行時指定的this
值 - arg1籽懦,arg2:傳遞的其它參數(shù)
- 返回由指定的
this
值和初始化參數(shù)構(gòu)造的 原函數(shù)拷貝于个。
應(yīng)用場景:不調(diào)用函數(shù)改變 this
指向。
var o = {
name:"lyman"
}
function fn() {
console.log(this);
}
var f = fn.bind(o);
f();
2.2.4 call暮顺、apply厅篓、bind三者異同
- 共同點(diǎn):都可以改變
this
指向 - 不同點(diǎn)
-
call
和apply
都會調(diào)用函數(shù),并改變this
指向 -
call
和apply
需要傳遞的參數(shù)不同捶码,call
傳遞參數(shù)使用逗號分開羽氮,apply
傳遞數(shù)組。 -
bind
不能調(diào)用函數(shù)惫恼,但是可以改變this
指向档押。
-
- 應(yīng)用場景:
-
call
經(jīng)常用于繼承 -
apply
經(jīng)常跟數(shù)組有關(guān)系,比如借助數(shù)學(xué)對象實現(xiàn)最大值和最小值函數(shù) -
bing
不會調(diào)用函數(shù),但是還想改變this
指向令宿,比如改變定時器內(nèi)部的this
指向叼耙。
-
3.嚴(yán)格模式
3.1 什么是嚴(yán)格模式
JavaScript 除了提供正常模式外,還提供了嚴(yán)格模式(strict mode)粒没。ES5 的嚴(yán)格模式是采用具有限制性 JavaScript 變體的一種方式旬蟋,即在嚴(yán)格的條件下運(yùn)行 JS 代碼。
嚴(yán)格模式在 IE10 以上的瀏覽器中才被支持革娄,舊版本的瀏覽器會忽略嚴(yán)格模式倾贰。
嚴(yán)格模式對正常的 JavaScript 語義做了一些更改:
- 消除了 JavaScript 語法的一些不合理,不嚴(yán)謹(jǐn)之處拦惋,減少了一些怪異行為匆浙。
- 消除代碼的一些不安全之處,保證代碼運(yùn)行的安全厕妖。
- 提高編譯器效率首尼,增加運(yùn)行速度。
- 禁用了在 ECMAScript 的未來版本中可能會定義的一些語法言秸,為未來新版本的 JavaScript 做好鋪墊软能。比如一些保留字:
class
,enum
举畸,export
查排,extends
,import
抄沮,super
不能當(dāng)作變量名跋核。
3.2 開啟嚴(yán)格模式
嚴(yán)格模式可以應(yīng)用到整個腳本或個別函數(shù)中,因此在使用時叛买,我們可以將嚴(yán)格模式分為為腳本開啟嚴(yán)格模式和為函數(shù)開啟嚴(yán)格模式兩種情況砂代。
- 為腳本開啟嚴(yán)格模式
有的script
腳本是嚴(yán)格模式,有的script
腳本是正常模式率挣,這樣不利于文件合并刻伊,所以將整個腳本文件放在一個立即執(zhí)行的匿名函數(shù)中,這樣獨(dú)立創(chuàng)建一個作用域而不影響其它script
腳本文件椒功。<script> "use strict"; // 下面的 JS 代碼就會按照嚴(yán)格模式執(zhí)行 </script>
- 為函數(shù)開啟嚴(yán)格模式
要給某個函數(shù)開啟嚴(yán)格模式捶箱,需要把"use strict";
放在函數(shù)體內(nèi)所有語句之前。<script> (function() { // 在這個自調(diào)用函數(shù)中開啟嚴(yán)格模式蛾茉,但是在函數(shù)外還是普通模式 "use strict"; })() </script>
3.3 嚴(yán)格模式中的變化
嚴(yán)格模式對 JavaScript 的語法和行為讼呢,都做出了一些改變。
3.3.1 變量規(guī)定
- 在正常模式中谦炬,如果一個變量沒有聲明就賦值悦屏,默認(rèn)是全局變量节沦。嚴(yán)格模式下禁用這種寫法,變量必須先用
var
命令聲明在使用础爬。
這種寫法將會報錯甫贯。"use strict"; num = 10; console.log(num);
- 嚴(yán)禁刪除已經(jīng)聲明了的變量
"use strict"; var num = 10; console.log(num); delete num;
3.3.2 嚴(yán)格模式下 this 指向問題
- 以前在全局作用域函數(shù)中的
this
指向window
對象,嚴(yán)格模式下全局作用域函數(shù)中的this
指向undefined
看蚜。"use strict"; function fn() { console.log(this); } fn();
- 在普通模式下叫搁,如果調(diào)用構(gòu)造函數(shù)不加
new
,會當(dāng)作普通函數(shù)來調(diào)用供炎。嚴(yán)格模式下不加new
調(diào)用構(gòu)造函數(shù)渴逻,this
會報錯。"use strict"; function Star() { this.sex ="男"; } Star();
- 定時器中的
this
還是指向window
音诫。"use strict"; setTimeout(function() { console.log(this); }, 2000)
3.3.3 函數(shù)相關(guān)
- 在非嚴(yán)格模式下函數(shù)可以擁有兩個同名參數(shù)惨奕,但是在嚴(yán)格模式下會報錯。
"use strict"; function fn(a, a) { console.log(a + a); } fn(1, 2);
- 新版本的 JavaScript 會引入“塊級作用域”(ES6中已引入)竭钝,為了與新版本接軌梨撞,不允許在非函數(shù)代碼塊中聲明函數(shù)。
4.高階函數(shù)
高階函數(shù)是對其它函數(shù)操作的函數(shù)香罐,它接收函數(shù)作為參數(shù)或將函數(shù)作為返回值輸出卧波。
例如:
function fn(callback) {
callback && callback();
}
fn(function() {console.log("hi~")})
或者
function fn(callback) {
return function() {};
}
fn();
此時 fn()
就是一個高階函數(shù),函數(shù)也是一種數(shù)據(jù)類型庇茫,同樣可以作為參數(shù)傳遞給另外一個參數(shù)使用港粱。最典型的就是作為回調(diào)函數(shù)。
需求:將 div
移動港令,移動完成后將顏色改變?yōu)樽仙?/p>
$("div").animate({left: 500, top: 500}, function() {
$("div").css("backgroundColor", "purple");
})
5.閉包
5.1 變量作用域
變量根據(jù)作用域的不同分為兩種:全局變量和局部變量啥容。
- 函數(shù)內(nèi)部可以使用全局變量
- 在函數(shù)外面不可以使用局部變量锈颗。
- 當(dāng)函數(shù)執(zhí)行完成后顷霹,函數(shù)內(nèi)部的局部變量就會被銷毀。
5.2 什么是閉包
閉包(closure) 指有權(quán)訪問另一個函數(shù)作用域中變量的函數(shù)击吱。
例如:
function fn() {
var num= 10;
function fun() {
console.log(num);
}
fun();
}
fn();
以上例子中淋淀,函數(shù) fun
訪問到了 fn
中定義的 num
,所以 fn
是一個閉包覆醇。
注意:被訪問的變量所在的函數(shù)被稱為閉包函數(shù)朵纷。
5.3 閉包的作用
需求:在 fn
外部訪問 fn
內(nèi)部定義的變量
function fn() {
var num= 10;
function fun() {
console.log(num);
}
return fun;
}
var f = fn();
f();
返回的變量 ·f· 類似于
var f = function() {
console.log(num);
}
總結(jié):閉包的作用就是延伸了變量的作用范圍。
6.遞歸
6.1 什么是遞歸
如果一個函數(shù)內(nèi)部可以調(diào)用其本身永脓,那么這個函數(shù)就是遞歸函數(shù)袍辞。
6.2 使用遞歸求階乘
// 利用遞歸計算 1~n 的階乘
function calculate(n) {
if (n == 0) return 0;
if (n == 1) return 1;
return calculate(n- 1) * n;
}
6.3 使用遞歸求斐波那契數(shù)列
// 利用遞歸求斐波那契數(shù)列 1, 1, 2, 3, 5, 8, 13
function fibonacci(n) {
if (n == 1 || n == 2) return 1;
return fibonacci(n - 1) + fibonacci(n - 2);
}
console.log(fibonacci(6));
6.4 使用遞歸遍歷數(shù)據(jù)
var data = [{
id: 1,
name: "家電",
goods: [{
id: 11,
gname: "冰箱"
}, {
id: 12,
gname: "洗衣機(jī)"
}]
}, {
id: 2,
name: "服飾"
}]
// 輸入 id 號,就返回數(shù)據(jù)對象常摧。
// 1. 利用 forEach 遍歷里面的每一個對象
function getId(json, id) {
var o = {};
json.forEach(function(value) {
if (value.id === id) {
o = value;
return value;
} else if (value.goods && value.goods.length != 0) {
o = getId(value.goods, id);
}
})
return o;
}
console.log(getId(data, 1));
console.log(getId(data, 2));
console.log(getId(data, 11));
console.log(getId(data, 12));
6.5 深拷貝和淺拷貝
- 淺拷貝只是拷貝一層搅吁,更深層次對象級別的只拷貝引用威创。
- 深拷貝拷貝多層,每一級別的數(shù)據(jù)都會拷貝谎懦。
6.5.1 使用 for-in 實現(xiàn)淺拷貝
var obj = {
id: 1,
name: "lyman",
msg: {
age: 18
}
}
var o = {};
for (var key in obj) {
o[key] = obj[key];
}
o.msg.age = 20;
console.log(obj);
console.log(o);
6.5.2 使用 Object.assign 實現(xiàn)淺拷貝(ES6新增)
語法:
Object.assign(target, source);
例如:
Object.assign(o, obj);
o.msg.age = 20;
console.log(obj);
console.log(o);
6.5.3 使用遞歸實現(xiàn)深拷貝
var obj = {
id:1,
name: "lyman",
msg: {
age: 18
},
color: ["pink", "purple"]
}
var o = {};
// 封裝函數(shù)
function deepCopy(newObj, oldObj) {
for (var k in oldObj) {
// 判斷屬性值屬于哪種數(shù)據(jù)類型
// 1.獲取屬性值
var item = oldObj[k];
// 2.判斷這個值是否是數(shù)組
if (item instanceof Array) {
newObj[k] = [];
deepCopy(newObj[k], item);
} else if (item instanceof Object) {
// 3.判斷這個值是否是對象
newObj[k] = {};
deepCopy(newObj[k], item);
} else {
// 4.簡單數(shù)據(jù)類型
newObj[k] = item;
}
}
}
deepCopy(o, obj);
o.msg.age = 20;
console.log(o);
console.log(obj);