JS 學(xué)習(xí)筆記 | 函數(shù)進(jìn)階

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));

applycall 主要的不同在于參數(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)
    • callapply 都會調(diào)用函數(shù),并改變 this 指向
    • callapply 需要傳遞的參數(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 做好鋪墊软能。比如一些保留字:classenum举畸,export查排,extendsimport抄沮,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);
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末肚豺,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子界拦,更是在濱河造成了極大的恐慌吸申,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件享甸,死亡現(xiàn)場離奇詭異截碴,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)蛉威,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進(jìn)店門隐岛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人瓷翻,你說我怎么就攤上這事聚凹。” “怎么了齐帚?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵妒牙,是天一觀的道長。 經(jīng)常有香客問我对妄,道長湘今,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任剪菱,我火速辦了婚禮摩瞎,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘孝常。我一直安慰自己旗们,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布构灸。 她就那樣靜靜地躺著上渴,像睡著了一般粹懒。 火紅的嫁衣襯著肌膚如雪啄巧。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天茉盏,我揣著相機(jī)與錄音半开,去河邊找鬼隔披。 笑死,一個胖子當(dāng)著我的面吹牛寂拆,可吹牛的內(nèi)容都是我干的奢米。 我是一名探鬼主播芥炭,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼恃慧!你這毒婦竟也來了园蝠?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤痢士,失蹤者是張志新(化名)和其女友劉穎彪薛,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體怠蹂,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡善延,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了城侧。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片易遣。...
    茶點(diǎn)故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖嫌佑,靈堂內(nèi)的尸體忽然破棺而出豆茫,到底是詐尸還是另有隱情,我是刑警寧澤屋摇,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布揩魂,位于F島的核電站,受9級特大地震影響炮温,放射性物質(zhì)發(fā)生泄漏火脉。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一柒啤、第九天 我趴在偏房一處隱蔽的房頂上張望倦挂。 院中可真熱鬧,春花似錦担巩、人聲如沸方援。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽肯骇。三九已至,卻和暖如春祖很,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背漾脂。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工假颇, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人骨稿。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓笨鸡,卻偏偏與公主長得像姜钳,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子形耗,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評論 2 355