第一部分
第2章
- 什么是詞法作用域?動(dòng)態(tài)作用域?js所采用的作用域模型是哪種?
首先什么是作用域译荞,簡(jiǎn)單來(lái)說(shuō)就是限定一段代碼的作用范圍滑进,詞法作用域就是作用域是由你在寫(xiě)代碼聲明時(shí)決定的,動(dòng)態(tài)作用域則是由調(diào)用時(shí)決定的.js采用的是詞法作用域 - 欺騙詞法方式有?
eval,with
第3章
- 什么是函數(shù)作用域?塊級(jí)作用域?
在js的es6之前,大多數(shù)情況下只有兩種作用域,函數(shù)作用域和全局作用域,就是在一個(gè)函數(shù)function里面會(huì)產(chǎn)生一個(gè)作用域.塊級(jí)作用域則是在{...},在es6出現(xiàn)了塊級(jí)作用域. - 函數(shù)中作用域有什么用?
函數(shù)中的作用域可以使內(nèi)容私有化,規(guī)避沖突,外部無(wú)法訪問(wèn) - 匿名函數(shù)和具名函數(shù)有啥區(qū)別?
匿名函數(shù)可讀性差,調(diào)試?yán)щy,引用自身比較麻煩(類(lèi)似在遞歸里) - 只有函數(shù)作用域會(huì)帶來(lái)一些什么問(wèn)題?
比較明顯的類(lèi)似if語(yǔ)句,在if語(yǔ)句里面申明一個(gè)變量,會(huì)導(dǎo)致變量聲明的提示,污染全局
if(false){
var a = 2;
}
console.log(a); //undefined 不是a is not defined,
//不管if是否執(zhí)行,var a都會(huì)提升到作用域的最頂端,一不小心很容易出問(wèn)題
for (var i = 0; i < 5; i++) {}
console.log(i);//5 這種也會(huì)造成一定程度的內(nèi)存泄漏和全局污染
- let,const作用?
提供塊級(jí)作用域,聲明變量不會(huì)提示,同一個(gè)作用域內(nèi)不能多次聲明 - 在es6前如何制造塊級(jí)作用域?
可以利用try catch
try{
throw undefined
}catch (a){
a = 2;
console.log(a); //2
}
console.log(a);//a is not defined
- 什么是變量聲明的提升?
在es5里函數(shù)聲明和變量聲明都會(huì)提升到當(dāng)前作用域的頂端,其中函數(shù)聲明的優(yōu)先級(jí)會(huì)高于變量聲明,如果函數(shù)聲明的名字和變量一樣,不管順序如何,函數(shù)的聲明會(huì)覆蓋變量的聲明 - 什么是閉包?
好像到今天,我才真正懂什么是閉包,閉包不是什么特別牛逼的東西,大致來(lái)說(shuō)就是一個(gè)函數(shù)里面的子函數(shù)能訪問(wèn)父函數(shù)里面的變量,本質(zhì)上就是外部函數(shù)和內(nèi)部函數(shù)連接的橋梁.
function a() {
var num = 1;
function b() {
console.log(num);//這種現(xiàn)象就是閉包
}
}
function a() {
var num = 1;
function b() {
console.log(num);//這就是閉包
}
return b
}
var b = a();
b(); //2,這里就是利用閉包的特性獲取到里面
console.log(num);//num is not defined
- IIFE自執(zhí)行函數(shù)是什么?
(function(){})(),其實(shí)和聲明一個(gè)變量賦值要執(zhí)行的函數(shù)再執(zhí)行是一樣的
(function () {
var a = 1;
})();
function foo() {
var a= 1;
}
foo();
就是利用函數(shù)會(huì)生成函數(shù)作用域的特性,自執(zhí)行函數(shù)可以寫(xiě)匿名函數(shù),比較方便,也少一個(gè)污染
第二部分
- this是什么時(shí)候確定下來(lái)的?
this是調(diào)用時(shí)確定的,根據(jù)調(diào)用時(shí)的綜合情況確定下來(lái)的 - this的綁定方式有多少種?優(yōu)先級(jí)是?
默認(rèn)綁定: 非嚴(yán)格模式下是window,嚴(yán)格模式下是undefined
隱式綁定: 大概的說(shuō)是誰(shuí)調(diào)用指向誰(shuí),有時(shí)候會(huì)有多層引用的情況
const obj0 = {
a: 0,
foo: function () {
console.log(this.a);
}
};
const obj1 = {
a:1,
obj0:obj0
};
const obj2 = {
a:2,
obj1:obj1
};
obj2.obj1.obj0.foo();//0
這個(gè)時(shí)候就是最近的那層,像上面的例子就是obj0最近的一層調(diào)用的,還有一點(diǎn)要注意的就是函數(shù)的賦值會(huì)導(dǎo)致this的變化或者丟失
const obj0 = {
a:0,
foo:function () {
console.log(this.a);
}
};
const obj1 = {
a:1,
foo:obj0.foo
};
const obj2 = obj0.foo;
obj1.foo();////1 這里和上面有所不同的地方是obj0.foo這個(gè)函數(shù)直接賦值給obj1.foo和obj2
obj2();// undefined
顯式綁定:apply,call,bind,this指向傳入的參數(shù)
new綁定:this指向new新建的對(duì)象
- apply,call,bind區(qū)別是?
首先apply和call作用是一樣的,傳參方式不一樣apply(obj,[arg0,arg1,arg2]),call(obj,arg0,arg1,arg2),apply和call和bind的區(qū)別就是,apply和call是綁定了立即執(zhí)行返回且undefined,bind是綁定了不執(zhí)行返回綁定后的函數(shù) - new在函數(shù)里發(fā)生了什么?
1,創(chuàng)建一個(gè)新的對(duì)象
2.把這個(gè)對(duì)象的proto連接到構(gòu)造函數(shù)的prototype上
3.把this指向這個(gè)對(duì)象
4.若無(wú)renturn就返回這個(gè)對(duì)象 - 箭頭函數(shù)this?前面4種方式?
箭頭函數(shù)的this做過(guò)處理,在進(jìn)入函數(shù)前this指向哪里,進(jìn)入函數(shù)后就指向哪里,前面四種綁定this的方式在箭頭函數(shù)里面是無(wú)效的 - null是否是Object類(lèi)型?
嚴(yán)格上來(lái)說(shuō)null不是object類(lèi)型,typeof null為object只是js的一個(gè)bug,原因是因?yàn)閖s的變量存儲(chǔ)為2進(jìn)制.typeof會(huì)根據(jù)前面三位是否都為0判斷是否是object,而null前三位剛好為0 - 為什么簡(jiǎn)單基本類(lèi)型能調(diào)用一些方法或者屬性?
類(lèi)似str,num,boolean基本類(lèi)型本來(lái)是沒(méi)有屬性和方法的,但是在調(diào)用屬性和方法的時(shí)候,就是會(huì)自動(dòng)包裝成對(duì)應(yīng)的對(duì)象,然后引用后會(huì)銷(xiāo)毀 - 對(duì)象的key是什么類(lèi)型的,不是會(huì)怎么樣?
對(duì)象的key都是字符串類(lèi)型的,如果穿的不是字符串類(lèi)型也會(huì)轉(zhuǎn)化成字符串類(lèi)型,之前還想過(guò)利用對(duì)象key的唯一性去去重,但是key只能是字符串也就是'1',1,true,'true'這種類(lèi)型就會(huì)區(qū)分不了了 - 數(shù)組下標(biāo)是什么類(lèi)型,若不是會(huì)怎么樣
數(shù)組的下標(biāo)是數(shù)字類(lèi)型的,若傳的不是數(shù)字類(lèi)型,但是正整數(shù)的字符串形式,會(huì)轉(zhuǎn)化成對(duì)應(yīng)的數(shù)字 - 深拷貝和淺拷貝有啥區(qū)別
淺拷貝基本只是第一層斷開(kāi)聯(lián)羹唠,如果對(duì)象里面還有類(lèi)似對(duì)象數(shù)組之類(lèi)的引用類(lèi)型就會(huì)失效,深拷貝是完全的斷開(kāi)聯(lián)系,無(wú)論多少層 - JSON.parse(JSON.stringify())的方式深拷貝對(duì)象有啥問(wèn)題?
這樣確實(shí)在一定程度上能實(shí)現(xiàn)深層的深拷貝,但是會(huì)有一些問(wèn)題,例如如果有函數(shù)會(huì)消失,new Date對(duì)象會(huì)變成單純的字符串之類(lèi)的問(wèn)題 - 淺拷貝的方式
可以用for in循環(huán),object.assign,es6里面的{...} - 如何獲取屬性描述符?有什么屬性?有什么用?
用getOwnPropertyDescriptor獲取
const obj1 = {a:[1],b:2};
console.log(Object.getOwnPropertyDescriptor(obj1, 'a'));
//configurable: true enumerable: true value: [1] writable: true
有writable,value,enumerable,configurable,還可以設(shè)置set和get
value顯而易見(jiàn)就是值了,writable就是限制能否修改值也就是value的權(quán)限,enumerable就是可枚舉,如果設(shè)置為false,for in循環(huán)是拿不到的,es6的for of循環(huán)也一樣,但是hasOwnProperty判斷還是返回true的,in判斷也是返回true的.configurable就是能否配置,為false的時(shí)候,就不能修改屬性描述符了,而且是不可逆的,并且也不能刪掉這個(gè)屬性
- 如何設(shè)置上述的特性
用defineProperty設(shè)置
const obj1 = {a:[1],b:2};
Object.defineProperty(obj1,'a',{
value: 2,
writable:false
});
console.log(Object.getOwnPropertyDescriptor(obj1, 'a'));
//configurable: true enumerable: true value: 2 writable: false
- get,set是什么?怎么設(shè)置?
const obj1 = {
get a(){
return 2
}
};
Object.defineProperty(obj1,'b',{
get(){
return this.a*2
}
});
console.log(obj1.a); //2
console.log(obj1.b); //4
兩種方法設(shè)置,get和set最好成對(duì)出現(xiàn),否則會(huì)吃出現(xiàn)一些意料之外的問(wèn)題.這里附上嘗試?yán)胓et和set實(shí)現(xiàn)雙向數(shù)據(jù)綁定鏈接
- 如何判斷屬性是不存在還是設(shè)置值為undefined
利用hasOwnProperty判斷一下就可以了 - 原型對(duì)象是什么
新建一個(gè)對(duì)象的時(shí)候會(huì)創(chuàng)建一個(gè)新的空對(duì)象并和新建的對(duì)象產(chǎn)生關(guān)聯(lián),那個(gè)就是原型對(duì)象 - 原型對(duì)象作用是什么
構(gòu)造函數(shù)的原型對(duì)象的屬性和方法都可以被這個(gè)構(gòu)造函數(shù)創(chuàng)建的實(shí)例調(diào)用 - 原型鏈?zhǔn)鞘裁?br> 每一個(gè)對(duì)象都有自己的原型對(duì)象,obj.proto會(huì)指向他構(gòu)造函數(shù)Obj.prototype,Obj.prototype也是一個(gè)對(duì)象,所以也有自己的原型對(duì)象,所以它指向Object.prototype,最后Object.prototype會(huì)指向null,也就是原型鏈的盡頭
- for in循環(huán)會(huì)檢查原型鏈上面的屬性嗎?那我只要自身的怎么辦?
for in會(huì)遍歷自身和整條原型鏈上面enumerable為true的所有屬性,如果只想要自身的屬性可以用hasOwnProperty判斷一下 - 分析myObject.foo = 'bar'的幾種情況
1.自身如果有這個(gè)屬性的,會(huì)去判斷writable是否為true,如果為true則直接替換,如果不為true則修改失敗,嚴(yán)格模式下會(huì)報(bào)錯(cuò),普通模式下會(huì)忽略
2.自身沒(méi)有這個(gè)屬性的,會(huì)去原型鏈上面找,如果找到這個(gè)屬性的,判斷writeable,true則發(fā)送屏蔽屬性,就是在自身新建一個(gè)這個(gè)屬性,原型鏈上面那個(gè)就拿不到了.如果為false同樣會(huì)修改失敗
3.如果自身和原型鏈上面都找不到這個(gè)屬性,則就直接添加到自身上 - 如果writable阻止了我添加屬性,但是我又想添加怎么辦?
只讀只是限制了=的方式修改屬性,我們可以用Object.defineProperty