摘要:上一章前端教學(xué)講義基礎(chǔ)閉包高階函數(shù)閉包是一種打通兩個(gè)作用域的能力,在和中都有類(lèi)似的功能,中的閉包和他們沒(méi)有太大的差別。在中任何函數(shù)都可以當(dāng)作構(gòu)造函數(shù)并搭配關(guān)鍵詞使用。再將作為運(yùn)行構(gòu)造函數(shù)。
上一章:前端教學(xué)講義:JS基礎(chǔ)
閉包、高階函數(shù)閉包是一種打通兩個(gè)作用域的能力,在 Java 和 OC 中都有類(lèi)似的功能,JS 中的閉包和他們沒(méi)有太大的差別。
不過(guò)因?yàn)?JS 的函數(shù)是一等公民,所以使用起來(lái)會(huì)更加靈活。
在數(shù)學(xué)和計(jì)算機(jī)科學(xué)中,高階函數(shù)是至少滿足下列一個(gè)條件的函數(shù):
接受一個(gè)或多個(gè)函數(shù)作為輸入
輸出一個(gè)函數(shù)
下面的例子就是個(gè)典型的高階函數(shù)
const multiple = function(a, b) { return a * b; } const plus = function(a, b) { return a + b; } const express = function(operator, a, b) { return operator(a)(b); } [ [plus, 1, 2], [multiple, 3, 4], ].map(function(formula) { return express.apply(null, formula) }); // [3, 12]call,apply,bind
在 JS 中經(jīng)常會(huì)遇到 this 指向錯(cuò)亂的問(wèn)題:
var obj = { value: 1234, log: function() { console.log(this.value) } } var log = obj.log; log(); // 這個(gè)函數(shù)執(zhí)行的時(shí)候沒(méi)有上下文,this 會(huì)默認(rèn)為 window 或者 global // undefined
JS 提供了兩個(gè)方法,call 和 apply,能夠指定一個(gè)函數(shù)執(zhí)行時(shí)候的上下文
log.call(obj); // 1234 log.apply(obj); // 1234
call 和 apply 同時(shí)還可以指定傳給函數(shù)的參數(shù)是什么,他們的區(qū)別就是后面的傳參數(shù)形式不一樣;
function fn(arg1, arg2){} fn.call(obj, arg1, arg2) fn.apply(obj, [arg1, arg2]) // apply 是將參數(shù)當(dāng)作數(shù)組傳入
bind 函數(shù)通過(guò)閉包的形式,來(lái)強(qiáng)制的將某個(gè)上下文綁定到函數(shù)上:
log = bind(log, obj); // 返回一個(gè)新函數(shù),此函數(shù)的 this 強(qiáng)制被綁定為 obj log() 1234
bind 的實(shí)現(xiàn)大概如下(省略傳參的功能):
function bind(fn, ctx) { return function() { return fn.apply(ctx); } }
和上面舉例有點(diǎn)區(qū)別的是 JS 提供的 bind 方法是 Function 類(lèi)的一個(gè)方法,調(diào)用方法如下:
function log() {} log = log.bind(obj)原型鏈
JS 的原型鏈(prototype chain)是為了實(shí)現(xiàn)面向?qū)ο蠖嬖诘?,?dāng)訪問(wèn)一個(gè)對(duì)象的方法的時(shí)候,首先會(huì)遍歷對(duì)象本身,是否存在這個(gè)鍵,然后在查找父類(lèi)是否有這個(gè)鍵,再一直追溯到頂層。
「父類(lèi)」中包含的方法和屬性,都存放在對(duì)象的 「__proto__」對(duì)象上(在舊的 JS 規(guī)范中,「__proto__」是隱藏屬性,但是 ES6 將它標(biāo)準(zhǔn)化并暴露出來(lái)了)。
var c = { somekey: 1, } var b = { __proto__: c, } var a = { __proto__: b } a.somekey // 1
當(dāng)訪問(wèn) 「a.somekey」 的時(shí)候,會(huì)沿著原型鏈一直向上查找,相當(dāng)于做了如下計(jì)算:
function getValue(obj, key) { while (obj) { if (key in obj) { return obj[key] } if (obj.__proto__) { obj = obj.__proto__; } else { return undefined; } } } getValue(a, "somekey")類(lèi)
在最早期的 JS 版本中是沒(méi)有類(lèi)的,后來(lái)加入了原型鏈和 new 關(guān)鍵詞才實(shí)現(xiàn)了類(lèi)。
function SubClass(value) { this.value = value; } SubClass.prototype = { log: function() { console.log(this.value); } } var sub = new SubClass(1234); sub.log(); // 1234
在 JS 中任何函數(shù)都可以當(dāng)作構(gòu)造函數(shù)并搭配 new 關(guān)鍵詞使用。
new 關(guān)鍵詞的作用就是新建一個(gè)空對(duì)象 a,然后把構(gòu)造函數(shù)上的 prototype 值掛載到 a.__proto__ 上。
再將 a 作為 context 運(yùn)行構(gòu)造函數(shù)。
如果我們將 new 作為一個(gè)函數(shù),它就是這樣:
function new(class, ...params) { var instance = {}; instance.__proto__ = class.prototype; var result = class.apply(instance, params); if (typeof result !== "undefined") { return result; } return instance; } var sub = new(SubClass, 1234);
從上面的代碼可以看出,在構(gòu)造函數(shù)中,可以指定 new 關(guān)鍵詞返回的類(lèi)型,也就是說(shuō) new A() 返回的結(jié)果不一定就是 A 的實(shí)例,這要看 A 的構(gòu)造函數(shù)內(nèi)部是如何實(shí)現(xiàn)的。
function A() { return 1234; } var a = new A(); console.log(a) // 1234
JS 用原型鏈的方式,曲線的實(shí)現(xiàn)了類(lèi)的行為和寫(xiě)法,所以在 JS 中,「類(lèi)」就是構(gòu)造函數(shù)。
instanceof如何判斷一個(gè)對(duì)象是否是一個(gè)類(lèi)的實(shí)例呢?
JS 實(shí)現(xiàn)的方法很粗糙,就是判斷實(shí)例的原型鏈上是否存在類(lèi)的原型。
function A() { } var a = new A(); a instanceof A true
我們甚至可以讓任意一個(gè)類(lèi)成為實(shí)例的父類(lèi)
function C() {} function A() {} var a = new A(); C.prototype = A.prototype; a instanceof A // true a instanceof C // true
我們甚至也可以讓一個(gè)父類(lèi)不是實(shí)例的父類(lèi)
function A() {} var a = new A(); A.prototype = {}; // 對(duì)原型重新賦值 a instanceof A false
總之就是很神奇
ES6 中對(duì)類(lèi)的改進(jìn)在 ES6 中新增了 class 關(guān)鍵詞,使得聲明一個(gè)類(lèi)更加簡(jiǎn)單,但只是寫(xiě)法上有改變,運(yùn)行機(jī)制還是一樣。
class A { constructor(value) { this.value = value; } log() { console.log(this.value); } } var a = new A(1234); a.log(); // 1234
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/96139.html
摘要:春招前端實(shí)習(xí)面試記錄從就開(kāi)始漸漸的進(jìn)行復(fù)習(xí),月末開(kāi)始面試,到現(xiàn)在四月中旬基本宣告結(jié)束。上海愛(ài)樂(lè)奇一面盒模型除之外的面向?qū)ο笳Z(yǔ)言繼承因?yàn)槭且曨l面試,只記得這么多,只感覺(jué)考察的面很廣,前端后端移動(dòng)端都問(wèn)了,某方面也有深度。 春招前端實(shí)習(xí)面試記錄(2019.3 ~ 2019.5) 從2019.1就開(kāi)始漸漸的進(jìn)行復(fù)習(xí),2月末開(kāi)始面試,到現(xiàn)在四月中旬基本宣告結(jié)束。在3月和4月經(jīng)歷了無(wú)數(shù)次失敗,沮...
摘要:從最開(kāi)始的到封裝后的都在試圖解決異步編程過(guò)程中的問(wèn)題。為了讓編程更美好,我們就需要引入來(lái)降低異步編程的復(fù)雜性。異步編程入門(mén)的全稱(chēng)是前端經(jīng)典面試題從輸入到頁(yè)面加載發(fā)生了什么這是一篇開(kāi)發(fā)的科普類(lèi)文章,涉及到優(yōu)化等多個(gè)方面。 TypeScript 入門(mén)教程 從 JavaScript 程序員的角度總結(jié)思考,循序漸進(jìn)的理解 TypeScript。 網(wǎng)絡(luò)基礎(chǔ)知識(shí)之 HTTP 協(xié)議 詳細(xì)介紹 HTT...
摘要:可能因?yàn)橄热霝橹?,在編程之中,往往不由自主地以的邏輯編程思路設(shè)計(jì)模式進(jìn)行開(kāi)發(fā)。這是原型模式很重要的一條原則。關(guān)于閉包與內(nèi)存泄露的問(wèn)題,請(qǐng)移步原型模式閉包與高階函數(shù)應(yīng)該可以說(shuō)是設(shè)計(jì)模式的基礎(chǔ)要領(lǐng)吧。在下一章,再分享一下的幾種常用設(shè)計(jì)模式。 前 在學(xué)習(xí)使用Javascript之前,我的程序猿生涯里面僅有接觸的編程語(yǔ)言是C#跟Java——忽略當(dāng)年在大學(xué)補(bǔ)考了N次的C與VB。 從靜態(tài)編程語(yǔ)言,...
講義內(nèi)容:JS 誕生的背景、基本類(lèi)型、運(yùn)算符 以下內(nèi)容只涉及 ES5 標(biāo)準(zhǔn),ES6 增加的新內(nèi)容可以在網(wǎng)上查找到。 JS 誕生的背景 上世紀(jì) 90 年代網(wǎng)景公司開(kāi)發(fā)的瀏覽器獨(dú)步天下 一個(gè)叫做 Brendan Eich 的工程師受命于開(kāi)發(fā)一款腳本語(yǔ)言,來(lái)增強(qiáng)瀏覽器的功能。 這名工程師花費(fèi)了 10 天時(shí)間設(shè)計(jì)出了第一個(gè)版本,名叫 LiveScript。 后來(lái)因?yàn)楫?dāng)時(shí) Java 正紅,公司將其改名為 J...
摘要:引言本期開(kāi)始介紹中的高階函數(shù),在中,函數(shù)是一種特殊類(lèi)型的對(duì)象,它們是。簡(jiǎn)單來(lái)說(shuō),高階函數(shù)是一個(gè)接收函數(shù)作為參數(shù)傳遞或者將函數(shù)作為返回值輸出的函數(shù)。我們來(lái)看看使用它們與不使用高階函數(shù)的方案對(duì)比。引言 本期開(kāi)始介紹 JavaScript 中的高階函數(shù),在 JavaScript 中,函數(shù)是一種特殊類(lèi)型的對(duì)象,它們是 Function objects。那什么是高階函數(shù)呢?本節(jié)將通過(guò)高階函數(shù)的定義來(lái)展...
閱讀 1783·2021-11-12 10:35
閱讀 1704·2021-08-03 14:02
閱讀 2771·2019-08-30 15:55
閱讀 2103·2019-08-30 15:54
閱讀 844·2019-08-30 14:01
閱讀 2491·2019-08-29 17:07
閱讀 2315·2019-08-26 18:37
閱讀 3106·2019-08-26 16:51