this[.屬性]
如果 this 未包含屬性,則傳遞的是當前物件。var x = "window"; //定義全域性變數x,初始化字串為“window” function a () { //定義建構函式a this.x = "a"; //定義私有屬性x,初始化字元a } function b () { //定義建構函式b this.x = "b"; //定義私有屬性x,初始化為字元b } function c () { //定義普通函數,提示變數x的值 console.log(x); } function f () { //定義普通函數,提示this包含的x的值 console.log(this.x); } f(); //返回字串“window”,this指向window物件 f.call(window); //返回字串“window”,指向window物件 f.call(new a()); //返回字元a,this指向函數a的範例 f.call(new b()); //返回字元b,this指向函數b的範例 f.call(c); //返回undefined,this指向函數c物件
var obj = { //父物件 name : "父物件obj", func : function () { return this; } } obj.sub_obj = { //子物件 name : "子物件sub_obj", func : obj.func } var who = obj.sub_obj.func(); console.log(who.name); //返回“子物件sub_obj”,說明this代表sub_obj如果把子物件 sub_obj 的 func 改為函數呼叫。
obj.sub_obj = { name : "子物件sub_obj", func : obj.func() //呼叫父物件obj的方法func }則函數中的 this 所代表的是定義函數時所在的父物件 obj。
var who = obj.sub_obj.func; console.log(who.name); //返回“父物件obj”,說明this代表父物件obj
var obj = {}; obj.func = function () { if (this == obj) console.log("this = obj"); else if (this == window) console.log("this = window"); else if (this.contructor == arguments.callee) console.log("this = 範例物件"); } new obj.func; //範例化
function func () { //如果this的建構函式等於當前函數,則表示this為範例物件 if (this.contructor == arguments.callee) console.log("this = 範例物件"); //如果this等於window,則表示this為window物件 else if (this == window) console.log("this = window物件"); //如果this為其他物件,則表示this為其他物件 else console.log("this == 其他物件 n this.constructor =" + this.constructor); } func(); //this指向window物件 new func(); //this指向範例物件 cunc.call(1); //this指向數值物件在上面範例中,直接呼叫 func() 時,this 代表 window 物件。當使用 new 命令呼叫函數時,將建立一個新的範例物件,this 就指向這個新建立的範例物件。
<input type="button" value="測試按鈕" /> <script> var button = document.getElementsByTagName("put")[0]; var obj = {}; obj.func = function () { if (this == obj) console.log("this = obj"); if (this == window) console.log("this = window"); if (this == button) console.log("this = button"); } button.onclick = obj.func; </script>在上面程式碼中,func() 所包含的 this 不再指向物件 obj,而是指向按鈕 button,因為 func() 是被傳遞給按鈕的事件處理常式之後才被呼叫執行的。
if (window.attachEvent) { //相容IE模型 button.attachEvent("onclick", obj.func); } else { //相容DOM標準模型 button.addEventListener("click", obj.func, true); }在 IE 瀏覽器中,this 指向 window 物件和 button 物件,而在 DOM 標準的瀏覽器中僅指向 button 物件。因為,在 IE 瀏覽器中,attachEvent() 是 window 物件的方法,呼叫該方法時,this 會指向 window 物件。
if (window.attachEvent) { button.attachEvent("onclick", function () { //用閉包封裝call()方法強制執行func() obj.func.call(obj); }); } else { button.attachEventListener("onclick", function () { obj.func.call(obj); }, true); }當再次執行時,func() 中包含的 this 始終指向物件 obj。
var obj = {}; obj.func = function () { if (this == obj) console.log("this = obj"); else if (this == window) console.log("this = window物件"); else if (this.constructor == arguments.callee) console.log("this = 範例物件"); else console.log("this == 其他物件 n this.constructor =" + this.constructor); } setTimeOut(obj.func, 100);在 IE 中 this 指向 window 物件和 button 物件,具體原因與上面講解的 attachEvent() 方法相同。在符合 DOM 標準的瀏覽器中,this 指向 window 物件,而不是 button 物件。
setTimeOut (function () { obj.func.call(obj); }, 100);
<input type="button" value="按鈕1" onclick="func()" /> <input type="button" value="按鈕2" onclick="func()" /> <input type="button" value="按鈕3" onclick="func()" /> <script> function func() { console.log(this.value); } </script>如果把 this 作為引數進行傳遞,那麼它就會代表當前物件。
<input type="button" value="按鈕1" onclick="func(this)" /> <input type="button" value="按鈕2" onclick="func(this)" /> <input type="button" value="按鈕3" onclick="func(this)" /> <script> function func (obj) { console.log(obj.value); } </script>
function Base () { //基礎類別 var _this = this; //當初始化時,儲存範例物件的參照指標 this.func = function () { return _this; //返回初始化時範例物件的參照 }; this.name = "Base"; } function Sub () { //子類 this.name = "Sub"; } Sub.prototype = new Base(); //繼承基礎類別 var sub = new Sub(); //範例化子類 var _this = sub.func(); console.log(_this.name); //this始終指向基礎類別範例,而不是子類範例
//把this轉換為靜態指標 //引數obj表示預設定this所指代的物件,返回一個預備呼叫的函數 Function.prototype.pointTo = function (obj) { var _this = this; //儲存當前函數物件 return function () { //返回一個閉包函數 return _this.apply(obj, arguments); //返回執行當前函數,並強制設定為指定物件 } }為 Function 擴充套件一個原型方法 pointTo(),該方法將在指定的引數物件上呼叫當前函數,從而把 this 係結到指定物件上。
var obj1 = { name : "this = obj1" } obj1.func = (function () { return this; }).pointTo(obj1); //把this系結到物件obj1身上 var obj2 = { name : "this = obj2", func : obj1.func } var _this = obj2.func(); console.log(_this.name); //返回“this=obj1”,說明this指向obj1,而不是obj2
//把建構函式轉換為範例物件 //引數func表示建構函式,返回建構函式func的範例物件 function instanceFrom (func) { var _arg = [].slice.call(arguments, 1); //獲取建構函式可能需要的初始化函數 func.prototype.constructor = func; //設定建構函式的原型結構器指向自身 func.apply(func.prototype, _arg); //在原型物件上呼叫建構函式 //此時this指代原型物件,相當於範例物件 return func.prototype; //返回原型物件 }
function F () { this.name = "F"; } var f = instanceFrom(F); console.log(f.name);call() 和 apply() 具有強大的功能,它不僅能夠執行函數,也能夠實現 new 命令的功能。
function bind(fn, context) { return function () { return fn.apply(context, arguments); }; }bind() 函數接收一個函數和一個上下文環境,返回一個在給特定環境中呼叫給函數的函數,並且將返回函數的所有的引數原封不動地傳遞給呼叫函數。
<button id="btn">測試按鈕</button> <script> var handler = { //事件處理物件 message : 'handler', //名稱 click : function (event) { //時間處理常式 console.log(this.message); //提示當前物件的message值 } }; var btn = document.getElementById('btn'); btn.addEventListener('click', handler.click); </script>在上面範例中,為按鈕系結單擊事件處理常式,設計當單擊按鈕時,將顯示 handler 物件的 message 屬性值。。但是,實際測試發現,this 最後指向了 DOM 按鈕,而不是 handler。
var handler = { //事件處理常式 message : 'handler', //名稱 click : function (event) { //時間處理常式 console.log(this.message); //提示當前物件的message值 } }; var btn = document.getElementById('btn'); btn.addEventListener('click', function () { //使用閉包進行修正:封裝事件處理常式的呼叫 handler.click(); }); //'handler'改進方法:使用閉包比較麻煩,如果建立多個閉包可能會令程式碼變得難以理解和偵錯,而使用 bind() 係結函數就很方便。
var handler = { //事件處理常式 message : 'handler', //名稱 click : function (event) { //事件處理常式 console.log(this.message); //提示當前物件的message值 } }; var btn = document.getElementById('btn'); btn.addEventListener('click', bind(handler.click, handler)); //‘handler’
function.bind(thisArg [,arg1 [,arg2 [,argN]]]);
引數說明如下:var check = function (value ) { if (typeof value !== 'number') return false; else return value >= this.min && value <= this.max; } var range = {min : 10, max : 20}; var check1 = check.bind(range); var result = check1(12); console.log(result); //true
var obj = { min : 50, max : 100, check : function (value) { if (typeof value !== 'number') { return false; } else { return value >= this.min && value <= this.max } } } var result = obj.check(10); console.log(result); //false var range = {min : 10, max : 20}; var check1 = obj.check.bind(range); var result = check1(10); console.log(result); //true
var func = function (val1, val2, val3, val4) { console.log(val1 + " " + val2 + " " + val3 + " " + val4); } var obj = {}; var func1 = func.bind(obj, 12, "a"); func1 ("b", "c"); //12 a b c
Function.prototype.method = function (name, func) { if (!this.prototype[name]) { this.prototype.[name] = func; return this; } } String.method = ('trim', function () { return this.replace(/^s+|s+$/g, ''); }); String.method = ('writeln', function () { console.log(this); return this; }); String.method = ('log', function () { console.log(this); return this; }); var str = "abc"; str.trim().writeln().log();