您好,登錄后才能下訂單哦!
一、作用域
js中作用域是指可訪問變量,對象,函數(shù)的集合,也就是調(diào)用它們能生效的代碼區(qū)塊。在js中沒有塊級作用域,只有全局作用域和函數(shù)作用域
1、全局,函數(shù)作用域
var a = 10
function f1(){
var b = c = 20;
console.log(a); ? ? //10
console.log(c); ? ? //20
function f2() {
console.log(b); //20
}f2();
}
f1();
console.log(a); ? ? //10
console.log(c); ? ? //20
console.log(b); ? ? //error
var b = c = 20 是指 var b = c; c = 20
在f1函數(shù)中c沒使用var聲明,所以c為全局變量,b為局部變量,綁定在f1函數(shù)下,外部訪問不到。
2、模仿塊級作用域
沒有塊級作用域,但是有if(),for()等塊語句,在塊語句內(nèi)部定義的變量會保留在它們已經(jīng)存在的作用域內(nèi),舉個栗子:
if(true) {
var word = 'hello';
console.log(word); //hello
}
console.log(word); //hello
if()語句存在全局作用域下,所以內(nèi)部定義的變量存在于全局作用域中,無論在哪都可以訪問。
function add(num) {
if(num > 10) {
var num = 10;
console.log(num); //10
}
console.log(num); //10
}
add(11);
console.log(num); //Uncaught ReferenceError: num is not defined
此時if()在add函數(shù)中,內(nèi)部定義的變量存在于add函數(shù)的作用域中,只有在add函數(shù)和塊語句中才可以訪問到,外部無法訪問。
3、使用自執(zhí)行的匿名函數(shù)包裹塊語句構(gòu)建塊作用域,也叫私有作用域
function add(num) {
for(var i = 0; i < num; i++) {
console.log(i); //0,1,2,3,4,5,6,7,8,9
}
console.log(i); //10
}
add(10);
將代碼改為
function add(num) {
(function () {
for(var i = 0; i < num; i++) {
console.log(i); //0,1,2,3,4,5,6,7,8,9
}
})()
console.log(i); //Uncaught ReferenceError: i is not defined
}
add(10);
此時變量i只能在for()循環(huán)中訪問到,在add函數(shù)和外部都無法訪問,并且在匿名函數(shù)中定義的任何變量都會在執(zhí)行結(jié)束時被銷毀,所以變量i只能在for()循環(huán)中使用。
二、執(zhí)行上下文
javascript運(yùn)行的代碼環(huán)境有三種:
function f1() {
var f1Context = 'f1 context';
function f2() {
var f2Context = 'f2 context';
function f3() {
var f3Context = 'f3 context';
console.log(f3Context);
}
f3();
console.log(f2Context);
}
f2();
console.log(f1Context);
}
f1();
//結(jié)果:
//f3 context
//f2 context
//f1 context
全局上下文:擁有f1()
f1()的執(zhí)行上下文:有變量f1Context和f2()
f2()的執(zhí)行上下文:有變量f2Context和f3()
f3()的執(zhí)行上下文:有變量f3Context
ECS:執(zhí)行環(huán)境棧,可以理解為代碼執(zhí)行的土壤,即代碼執(zhí)行的地方
js是單線程,任務(wù)都為同步任務(wù)的情況下某一時間只能執(zhí)行一個任務(wù)
執(zhí)行一段代碼首先會進(jìn)入全局上下文中,并將其壓入ECS中棧頂
首先執(zhí)行f1(),為其創(chuàng)建執(zhí)行上下文,進(jìn)入到棧頂位置,全局上下文被往下壓
f1()中有f2(),再為f2()創(chuàng)建f2()的執(zhí)行上下文,f2()進(jìn)入到棧頂位置,f1()被往下壓,
依次,最終全局上下文被壓入到棧底,f3()的執(zhí)行上下文在棧頂
f3()執(zhí)行完后,ECS就會彈出其執(zhí)行上下文(內(nèi)部變量隨之被銷毀),f3()上下文彈出后,f2()上下文來到棧頂,開始執(zhí)行f2(),依次,最后ECS中只剩下全局上下文,它等到應(yīng)用程序退出,例如瀏覽器關(guān)閉時銷毀。
function foo(i) {
if(i == 3) {
return;
}
foo(i+1);
console.log(i);
}
foo(0);
ECS棧頂為foo(3)的的上下文,直接return彈出后,棧頂變成foo(2)的上下文,執(zhí)行foo(2),輸出2并彈出,執(zhí)行foo(1),輸出1并彈出,執(zhí)行foo(0),輸出0并彈出,關(guān)閉瀏覽器后全局EC彈出,所以結(jié)果為2,1,0。
三、原型和原型鏈
1、對象(普通對象、函數(shù)對象)
2、構(gòu)造函數(shù)
//創(chuàng)建構(gòu)造函數(shù)
function Word(words){
this.words = words;
}
Word.prototype = {
alert(){
alert(this.words);
}
}
//創(chuàng)建實(shí)例
var w = new Word("hello world");
w.print = function(){
console.log(this.words);
console.log(this); //Person對象
}
w.print(); //hello world
w.alert(); //hello world
print()方法是w實(shí)例本身具有的方法,所以w.print()打印hello world;alert()不屬于w實(shí)例的方法,屬于構(gòu)造函數(shù)的方法,w.alert()也會打印hello world,因?yàn)閷?shí)例繼承,構(gòu)造函數(shù)原型上的方法。
實(shí)例w的隱式原型指向它構(gòu)造函數(shù)的顯式原型,指向的意思是恒等于
w.proto === Word.prototype
當(dāng)調(diào)用某種方法或查找某種屬性時,首先會在自身調(diào)用和查找,如果自身并沒有該屬性或方法,則會去它的proto屬性中調(diào)用查找,也就是它構(gòu)造函數(shù)的prototype中調(diào)用查找。所以很好理解實(shí)例繼承構(gòu)造函數(shù)的方法和屬性:
w本身沒有alert()方法,所以會去Word()的顯式原型Word.prototype中調(diào)用alert(),即實(shí)例繼承構(gòu)造函數(shù)的方法。 ?
3、原型和原型鏈
Function.prototype.a = "a";
Object.prototype.b = "b";
function Person(){}
console.log(Person); //function Person()
let p = new Person();
console.log(p); //Person {} 對象
console.log(p.a); //undefined
console.log(p.b); //b
實(shí)例p上面并沒有a屬性,那么會通過proto向上查找,根據(jù):
p.proto == Person.prototype,然后Person.prototype上也沒有a屬性,Person.prototype仍然是一個對象,上面仍然具有proto屬性,根據(jù):
Person.prototype.proto == Function.prototype //false
Person.prototype.proto == Object.prototype //true
Object.prototype.proto == null //再上一級就是null了
此時,Object.prototype.b = "b",所以p.a是undefined,而p.b是"b",
因?yàn)闆]有定義Object.prototype.a,只定義了Function.prototype.a
總結(jié):
1.查找屬性,如果本身沒有,則會去proto中查找,也就是構(gòu)造函數(shù)的顯式原型中查找,如果構(gòu)造函數(shù)中也沒有該屬性,因?yàn)闃?gòu)造函數(shù)也是對象,也有proto,那么會去它的顯式原型中查找,一直到null,如果沒有則返回undefined
2.p.proto.constructor? == function Person(){}
3.p._proto.proto_== Object.prototype
4.p.proto.proto.proto== Object.prototype.proto == null ????????
5.通過proto__形成原型鏈而非protrotype
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。