原型和闭包
原型和閉包
一切皆對(duì)象
一切皆對(duì)象(類型值除外)
undefined, number, string, boolean屬于簡(jiǎn)單的值類型
函數(shù)、數(shù)組、對(duì)象、new Number(10)都是對(duì)象。他們都是引用類型
Null是基本數(shù)據(jù)類型,不是引用數(shù)據(jù)類型
基本數(shù)據(jù)類型的值就是它本身的值,引用數(shù)據(jù)類型是存放的對(duì)這個(gè)對(duì)象引用的指針,Null本身的值就是Null,所以不是引用類型
不同的對(duì)象在底層都表示為二進(jìn)制,在 JavaScript 中二進(jìn)制前三位都為 0 的話會(huì)被判
斷為 object 類型, null 的二進(jìn)制表示是全 0,自然前三位也是 0,所以執(zhí)行 typeof 時(shí)會(huì)返回“ object ”。
http://www.cnblogs.com/xiaoheimiaoer/p/4572558.html
判斷值類型的類型用typeof,引用類型的類型用instanceof
javascript為弱類型,里一切皆是對(duì)象,對(duì)象里面都是屬性,而它的方法也是一種屬性,用鍵值對(duì)的形式來(lái)表示,且javascript中的對(duì)象可以隨意擴(kuò)展屬性,沒(méi)有class的約束。
簡(jiǎn)單示例
var a1={b:10,c:function(n){alert(this.a+n);},d:{car:"000000",long:"五十"} };雖然函數(shù)是一種對(duì)象,但函數(shù)和對(duì)象那個(gè)之間更像是一種相互生成的關(guān)系
對(duì)象都由函數(shù)來(lái)創(chuàng)建,我們平時(shí)所寫的var let等其實(shí)是一種“語(yǔ)法糖”其本質(zhì)還是函數(shù)
prototype原型
每一個(gè)函數(shù)都有一個(gè)屬性叫prototype
prototype的屬性值是一個(gè)對(duì)象,只有一個(gè)默認(rèn)的叫constructor屬性,指向函數(shù)本身,而還我們可以自己采用自定義的形式在prototype中新增自己的屬性
function F1(){} F1.prototype.age="1982"; F1.prototype.sex=function(){return "man"; };而這樣做的作用就要聯(lián)系到j(luò)Query了
var $("div"); $div.attr('myAge','18');上面代碼中,$('div')返回的是一個(gè)對(duì)象,而對(duì)象被函數(shù)創(chuàng)建的而他的實(shí)現(xiàn)過(guò)程如下
myjQuery.prototype.attr=function(){}; $('div')=new myjQuery();其本質(zhì)就是
function F1(){} F1.prototype.age="1982"; F1.prototype.sex=function(){return "man"; }; var f2=new F1(); console.log(f2.age); console.log(f2.sex());F1是一個(gè)函數(shù),f2對(duì)象是從F1函數(shù)new出來(lái)的,這樣f2對(duì)象就可以調(diào)用F1.prototype中的屬性。
因?yàn)槊總€(gè)對(duì)象都有一個(gè)隱藏的屬性——“proto”,這個(gè)屬性引用了創(chuàng)建這個(gè)對(duì)象的函數(shù)的prototype。即:
f2.__proto__ === F1.prototype這里的"______proto_______"成為“隱式原型”
__ proto__ 原型
每個(gè)函數(shù)function都有一個(gè)prototype,即原型。同時(shí)每個(gè)對(duì)象都有一個(gè)__ proto__
其指向創(chuàng)建該對(duì)象的函數(shù)的prototype
個(gè)__ proto __是一個(gè)隱藏的屬性,javascript不希望開發(fā)者用到這個(gè)屬性值,有的低版本瀏覽器甚至不支持這個(gè)屬性值
自定義函數(shù)的prototype都是被Object創(chuàng)建,所以它的_ _proto__指向的就是Object.prototype
但是Object.prototype確實(shí)一個(gè)特例——它的__ proto__指向的是null,切記切記
函數(shù)也有原型
function fn(x,y){return x+y; }; console.log(fn(10,20));var f1= new Function("x","y","return x+y;"); console.log(f1(8,7));第二種為new Function僅作理解使用,Function作為函數(shù),也是一種對(duì)象,所以也有 __ proto__ 屬性,而函數(shù)本身是被Function創(chuàng)建,所以Function是被自身創(chuàng)建,他的 __ proto __指向了自身的Prototype。
同理Function.prototype指向的對(duì)象,它的__ proto __也指向Object.prototype
instanceof
instanceof 用于對(duì)引用類型的判斷
Instanceof的判斷隊(duì)則是:
function Foo(){} var f1=new Foo();console.log(f1 instanceof Foo);//true console.log(f1 instanceof Object);//true設(shè)第一個(gè)變量為A,設(shè)第二個(gè)函數(shù)為B
沿著A的__ proto__這條線來(lái)找,同時(shí)沿著B的prototype這條線來(lái)找,如果兩條線能找到同一個(gè)引用,即同一個(gè)對(duì)象,那么就返回true。如果找到終點(diǎn)還未重合,則返回false
將前面的整合為整體如下圖,通過(guò)此圖,可以捋清為何返回值為true了
其實(shí)instanceof表示的就是一種繼承關(guān)系,或者原型鏈的結(jié)構(gòu)
繼承
javascript中的繼承是通過(guò)原型鏈來(lái)體現(xiàn)的
js是原型繼承,C#是類型繼承。
原型繼承比類型繼承更加靈活,但是又不如類型繼承可控
f1是Foo函數(shù)new出來(lái)的對(duì)象f1.a是f1對(duì)象的基本屬性而非。b從Foo.prototype得來(lái)
f1.__ proto __指向的是Foo.prototype
**訪問(wèn)一個(gè)對(duì)象的屬性時(shí),先在基本屬性中查找,如果沒(méi)有,再沿著__ proto__這條鏈向上找,這就是原型鏈 **
訪問(wèn)f1.b時(shí),f1的基本屬性中沒(méi)有b,于是沿著__ proto__找到了Foo.prototype.b
可使用hasOwnProperty區(qū)分一個(gè)屬性是基本屬性還是原型
原型的靈活性
對(duì)象屬性可以隨時(shí)改動(dòng)
在對(duì)象或函數(shù)new出來(lái)后可以隨時(shí)加屬性
繼承方法不合適也可以隨時(shí)修改
缺少你所要用的方法時(shí),可以隨時(shí)去創(chuàng)建
執(zhí)行上下文
- 變量、函數(shù)表達(dá)式——變量聲明,默認(rèn)賦值為undefined;
- this——賦值;
- 函數(shù)聲明——賦值;
這三種數(shù)據(jù)的準(zhǔn)備情況我們稱之為“執(zhí)行上下文”或者“執(zhí)行上下文環(huán)境”。
函數(shù)每被調(diào)用一次,都會(huì)產(chǎn)生一個(gè)新的執(zhí)行上下文環(huán)境。因?yàn)椴煌恼{(diào)用可能就會(huì)有不同的參數(shù)
另外一點(diǎn)不同在于,函數(shù)在定義的時(shí)候(不是調(diào)用的時(shí)候),就已經(jīng)確定了函數(shù)體內(nèi)部自由變量的作用域
大白話理解:在執(zhí)行代碼之前,把將要用到的所有的變量都事先拿出來(lái),有的直接賦值了,有的先用undefined占個(gè)空
了解了執(zhí)行上下文環(huán)境中的數(shù)據(jù)信息,你就不用再去死記硬背那些可惡的面試題了
this
? 在函數(shù)中this到底取何值,是在函數(shù)真正被調(diào)用執(zhí)行的時(shí)候確定的,函數(shù)定義的時(shí)候確定不了,因?yàn)閠his的取值是執(zhí)行上下文環(huán)境的一部分,每次調(diào)用函數(shù),都會(huì)產(chǎn)生一個(gè)新的執(zhí)行上下文環(huán)境。
構(gòu)造函數(shù)
所謂構(gòu)造函數(shù)就是用來(lái)new對(duì)象的函數(shù)。其實(shí)嚴(yán)格來(lái)說(shuō),所有的函數(shù)都可以new一個(gè)對(duì)象,但是有些函數(shù)的定義是為了new一個(gè)對(duì)象,而有些函數(shù)則不是。另外注意,構(gòu)造函數(shù)的函數(shù)名第一個(gè)字母大寫(規(guī)則約定)
函數(shù)作為對(duì)象的一個(gè)屬性
如果函數(shù)作為對(duì)象的一個(gè)屬性時(shí),并且作為對(duì)象的一個(gè)屬性被調(diào)用時(shí),函數(shù)中的this指向該對(duì)象
函數(shù)用call或者apply調(diào)用
當(dāng)一個(gè)函數(shù)被call和apply調(diào)用時(shí),this的值就取傳入的對(duì)象的值。
全局 & 調(diào)用普通函數(shù)
全局環(huán)境下,this永遠(yuǎn)是window
普通函數(shù)在調(diào)用時(shí),其中的this也都是window
其實(shí),不僅僅是構(gòu)造函數(shù)的prototype,即便是在整個(gè)原型鏈中,this代表的也都是當(dāng)前對(duì)象的值。
執(zhí)行上下文棧
? 執(zhí)行全局代碼時(shí),會(huì)產(chǎn)生一個(gè)執(zhí)行上下文環(huán)境,每次調(diào)用函數(shù)都又會(huì)產(chǎn)生執(zhí)行上下文環(huán)境。當(dāng)函數(shù)調(diào)用完成時(shí),這個(gè)上下文環(huán)境以及其中的數(shù)據(jù)都會(huì)被消除,再重新回到全局上下文環(huán)境。處于活動(dòng)狀態(tài)的執(zhí)行上下文環(huán)境只有一個(gè)。
其實(shí)這是一個(gè)壓棧出棧的過(guò)程——執(zhí)行上下文棧
作用域
通常大家認(rèn)為“javascript沒(méi)有塊級(jí)作用域”。所謂“塊”,就是大括號(hào)“{}”中間的語(yǔ)句
javascript除了全局作用域之外,只有函數(shù)可以創(chuàng)建的作用域。
? 所以,我們?cè)诼暶髯兞繒r(shí),全局代碼要在代碼前端聲明,函數(shù)中要在函數(shù)體一開始就聲明好。除了這兩個(gè)地方,其他地方都不要出現(xiàn)變量聲明。而且建議用“單var”形式
作用域有上下級(jí)的關(guān)系,上下級(jí)關(guān)系的確定就看函數(shù)是在哪個(gè)作用域下創(chuàng)建的
作用域最大的用處就是隔離變量,不同作用域下同名變量不會(huì)有沖突
作用域在函數(shù)定義時(shí)就已經(jīng)確定了。而不是在函數(shù)調(diào)用時(shí)確定
? 作用域只是一個(gè)“地盤”,一個(gè)抽象的概念,其中沒(méi)有變量。要通過(guò)作用域?qū)?yīng)的執(zhí)行上下文環(huán)境來(lái)獲取變量的值。同一個(gè)作用域下,不同的調(diào)用會(huì)產(chǎn)生不同的執(zhí)行上下文環(huán)境,繼而產(chǎn)生不同的變量的值。所以,作用域中變量的值是在執(zhí)行過(guò)程中產(chǎn)生的確定的,而作用域卻是在函數(shù)創(chuàng)建時(shí)就確定了。
所以,如果要查找一個(gè)作用域下某個(gè)變量的值,就需要找到這個(gè)作用域?qū)?yīng)的執(zhí)行上下文環(huán)境,再在其中尋找變量的值
自由變量到作用域鏈
將變量在作用域外聲明在作用域中調(diào)用的變量為自由變量
要到創(chuàng)建這個(gè)函數(shù)的那個(gè)作用域中取值——是“創(chuàng)建”,而不是“調(diào)用”,無(wú)論函數(shù)將在哪里調(diào)用
閉包
閉包,可理解為:函數(shù)作為返回值,函數(shù)作為參數(shù)傳遞
有些情況下函數(shù)在被調(diào)用完后其上下文環(huán)境不會(huì)被銷毀,如返回值唯一個(gè)函數(shù),函數(shù)的特別之處在于可以創(chuàng)建一個(gè)獨(dú)立的作用域
使用閉包會(huì)增加內(nèi)容開銷,只有在所有閉包相關(guān)作用域執(zhí)行完畢后才會(huì)銷毀
圖片來(lái)源于網(wǎng)絡(luò)
轉(zhuǎn)載于:https://www.cnblogs.com/baiyang2292/p/11175619.html
總結(jié)
- 上一篇: Scrum之成败——从自身案例说起,仅供
- 下一篇: 【转载】 安卓版手机微信如何清理微信空间