簡單介紹 Javascript 裡面的 this and prototype
在Javascript 裡面 function 有四種的調用方式,只有在function裡面才會用到 this
1.當作函式調用
2.當作方法調用
3.間接調用
4.當作建構式調用
1.當作函式調用:
最常見的function用法,定義一個function ,然後直接調用
function Demo1()
{
console.log('Demo1');
console.log(this);
}
Demo1();
當作函式調用的情境下,this又分為兩種模式
在非嚴格模式下,this 表示全域"跟"物件,
誰呼叫這個物件=>也就是window
上面的寫法就是會印出window
在 嚴格模式 下,this = undefined,如下面的範例:
(function(){
'use strict';
function Demo1()
{
console.log('Demo1');
console.log(this);
}
Demo1();
})();
2.當作方法調用:
function 當作方法調用的情境如下:
使用 object literal 的方式件建立名為 Article 的物件
在物件內定義方法,調用物件的方法,這時候的this ,代表的是 function 執行時期的所屬物件,
調用這個function的是物件=>Article
var Article = {
id:'1',
name:'Test Article',
Printf:function(){
// 在這個function 裡面,this 代表執行時期的所屬物件
console.log(this);
console.log(this.id);
}
};
Article.Printf();
執行結果:
第一個console.log=> 呈現Article整個物件(1對應結果區的2)
第二個console.log=> 印出這個物件的屬性id(3對應結果區的4)
3.間接調用
只要是function ,就會有內建的call()、apply()
假設我定義了一個function:
這個function 有三個參數:x,y,z
function Demo1(x, y, z) {
console.log(this);
console.log(`X value is ${x},Y value is${y},Z value is ${z}`);
}
如果是用call() 來間接調用這個function,
我可以在第一個參數傳入一個物件,function內部的this指的就是這個物件:
例如:
Demo1.call({
id: 1,
Name: 'Test Call'
}, 'x1', 'x2', 'x3');
我先傳入一個物件 {id:1,Name:'Test Call'},然後在依序傳入這個function 所需要的參數x,y,z
由執行結果可以看到
1的執行結果就是對應2,3的執行結果就是對應4
4.當作建構式調用:
把function 當作是一個物件,還可以透過prototype繼續擴充物件的方法或是屬性
裡面的this,在每次new的時候都會產生一個全新的物件
function Car()
{
this.name = 'Car Name';
}
// 透過 prototype 擴充屬性ID
Car.prototype.ID = 'ID';
// 透過 prototype 擴充方法
Car.prototype.Boot = function(){
console.log(this.ID);
console.log(this.name);
}
var car1 = new Car();
var car2 = new Car();
// 修改 car1 物件內的屬性,不影響到car2,證明new 出來的實體不屬於同一個物件
car1.name = 'Car 1 Name';
car1.Boot();
car2.Boot();
執行結果如下:
這時候可以看一下 Car 這個Function 是看不到透過prototype擴充的屬性,
需要用 Car.prototype 才可以看到,
New出來的物件(car1、car2)則是可以使用 __propt__ 看看一共擴充了那些屬性
使用prototype去擴充方法有一個好處,就是不管你new出幾個物件,
都是共用相同的記憶體,
如果是把function 寫在Car裡面的話,則是不同的記憶體,在New的時候就重新產生全新的記憶體
可以用以下的Code測試一下
function Car()
{
this.name = 'Car Name';
// 把boot2 寫在Car裡面
this.boot2 = function(){
console.log('boot2');
}
}
// 透過 prototype 擴充屬性ID
Car.prototype.ID = 'ID';
// 透過 prototype 擴充方法
Car.prototype.Boot = function(){
console.log(this.ID);
console.log(this.name);
}
var car1 = new Car();
var car2 = new Car();
console.log(car1.boot2 === car2.boot2);
console.log(car1.Boot === car2.Boot);
執行結果:
boot2 不相等,因為每次New的時候都會產生一個全新的記憶體,Javascript在比對物件是否相同的時候是比較記憶體位置
Boot 則是相等,因為擴充在ptototype的方法只會產生一次,節省記憶體空間。