1. 原型對(duì)象和原型鏈
prototype
的主要作用是繼承,prototype
中定義的屬性和方法是留給自己的“后代”用的。子類(lèi)可以完全訪(fǎng)問(wèn)prototype
中的屬性和方法
function f(){}
f.prototype.foo = "abc";
console.log(f.foo); //undefined
通過(guò)例子可以看出,自身是訪(fǎng)問(wèn)不到自己的prototype
的
__proto__
通常是把父類(lèi)的prototype
賦值給它,這樣的話(huà),就可以通過(guò)這種父類(lèi)的prototype
賦值給新對(duì)象的__proto__
屬性的形式,一代代傳承
function f(){}
f.prototype.foo = "abc";
var obj = new f();
console.log(obj.foo); //abc
obj對(duì)象擁有這樣一個(gè)原型鏈以后利诺,當(dāng)obj.foo執(zhí)行時(shí),obj會(huì)先查找自身是否有該屬性剩燥,但不會(huì)查找自己的prototype
,當(dāng)找不到foo時(shí)慢逾,obj就沿著原型鏈依次去查找...
function Animal(name){
this.name = name;
}
Animal.color = "black";
Animal.prototype.say = function(){
console.log("I'm " + this.name);
};
var cat = new Animal("cat");
console.log(
cat.name, //cat
cat.color //undefined
);
cat.say(); //I'm cat
console.log(
Animal.name, //Animal
Animal.color //back
);
Animal.say(); //Animal.say is not a function
cat.color -> cat會(huì)先查找自身的color,沒(méi)有找到便會(huì)沿著原型鏈查找灭红,在上述例子中侣滩,我們僅在Animal對(duì)象上定義了color,并沒(méi)有在其原型鏈上定義,因此找不到变擒。
cat.say -> cat會(huì)先查找自身的say方法君珠,沒(méi)有找到便會(huì)沿著原型鏈查找,在上述例子中娇斑,我們?cè)贏nimal的prototype
上定義了say,因此在原型鏈上找到了say方法策添。
1. 原型鏈的形成真正是靠__proto__
而非prototype
,當(dāng)JS引擎執(zhí)行對(duì)象的方法時(shí)材部,先查找對(duì)象本身是否存在該方法,如果不存在唯竹,會(huì)在原型鏈上查找乐导,但不會(huì)查找自身的prototype
。
2. 一個(gè)對(duì)象的__proto__
記錄著自己的原型鏈浸颓,決定了自身的數(shù)據(jù)類(lèi)型物臂,改變__proto__
就等于改變對(duì)象的數(shù)據(jù)類(lèi)型。
3. 函數(shù)的prototype
不屬于自身的原型鏈产上,它是子類(lèi)創(chuàng)建的核心棵磷,決定了子類(lèi)的數(shù)據(jù)類(lèi)型,是連接子類(lèi)原型鏈的橋梁晋涣。
4. 在原型對(duì)象上定義方法和屬性的目的是為了被子類(lèi)繼承和使用仪媒。
2. 作用域
JS中有種特殊情況
如果一個(gè)變量沒(méi)有使用var聲明,window便擁有了該屬性姻僧,因此這個(gè)變量的作用域不屬于某一個(gè)函數(shù)體规丽,而是window對(duì)象
functtion varscope(){
foo = "I‘m in function";
console.log(foo);//I‘m in function
}
varscope();
console.log(window.foo);//I‘m in function
作用域鏈就是一個(gè)函數(shù)體中嵌套了多層函數(shù)體蒲牧,并在不同的函數(shù)體中定義同一變量撇贺,當(dāng)其中一個(gè)函數(shù)訪(fǎng)問(wèn)這個(gè)變量時(shí),便會(huì)形成一條作用域鏈
foo = "window";
function first(){
var foo = "first";
function second(){
var foo = "second",
console.log(foo);
}
function third(){
console.log(foo);
}
second(); //second
third(); //first
}
first();
當(dāng)執(zhí)行second時(shí)冰抢,JS引擎會(huì)將second的作用域放置鏈表頭部松嘶,其次是first的作用域,最后是window對(duì)象
second形成的作用域鏈:second->first->window
third形成的作用域鏈:third->first->window
var foo = "window";
var obj = {
foo : "obj",
getFoo : function(){
return function(){
return this.foo;
};
}
};
var f = obj.getFoo();
f(); //window
在實(shí)例化obj.getFoo方法的時(shí)候挎扰,在getFoo方法作用域里,this
代表getFoo函數(shù)
但是在輸出的時(shí)候翠订,又定義了一個(gè)匿名函數(shù),所以this
就代表了這個(gè)匿名函數(shù)
相當(dāng)于賦值給f的是這個(gè)匿名的函數(shù)遵倦,所以找到的是window,即
var foo = "window";
var f = function(){
return this.foo;
}
3. 閉包
當(dāng)一個(gè)內(nèi)部函數(shù)被其外部函數(shù)之外的變量引用時(shí)尽超,就形成了閉包
function A(){
var count = 0;
function B(){
count ++;
console.log(count);
}
return B;
}
var c = A();
c();// 1
c();// 2
c();// 3
因?yàn)楸灰盟裕珹對(duì)象不會(huì)被GC回收(GC回收的機(jī)制是:如果一個(gè)對(duì)象不再被引用梧躺,那么這個(gè)對(duì)象就會(huì)被GC回收似谁,否則這個(gè)對(duì)象一直會(huì)保存在內(nèi)存中)
var f = function(document){
var viewport;
var obj = {
init:function(id){
viewport = document.querySelector("#"+id);
},
addChild:function(){
viewport.appendChild(child);
},
removeChild:function(child){
viewport.removeChild(child);
}
}
}
f(document);
obj 是在 f 中定義的一個(gè)對(duì)象,這個(gè)對(duì)象中定義了一系列方法掠哥, 執(zhí)行window.jView = obj 就是在 window 全局對(duì)象定義了一個(gè)變量 jView巩踏,并將這個(gè)變量指向 obj 對(duì)象,即全局變量 jView 引用了 obj . 而 obj 對(duì)象中的函數(shù)又引用了 f 中的變量 viewport ,因此 f 中的 viewport 不會(huì)被GC回收续搀,會(huì)一直保存到內(nèi)存中塞琼,所以這種寫(xiě)法滿(mǎn)足閉包的條件。
參考的博客文一像素博客