2016-12-23 26 views
2

我犯了這樣的目標:如何更改JavaScript中的「this」指針?

var MyObj = function(arg) 
{ 
    var PublicMethods = { 
      SomeMethod: function(someArg) 
      { 
      if(SomeCheck(arg) 
      { 
       PublicMethods.SomeFunc2 = somethingElse; 
      } 
      } 
     }; 

    return PublicMethods; 
}; 

然而MyObj似乎並不具有持久性和通話之間,PublicMethods犯規保存添加到它的新方法,所以我試圖將其移動到全球範圍內,但此後它不再承認從MyObj傳遞的'args'。

如果我讓MyObj這樣的:

var MyObj = (function() 
{ 
//.. 
}()); 

然後它變成一個持久化對象,但我不知道 - 我可以再次調用它的功能? jQuery似乎有一個持久對象,同時它可以被稱爲一個函數,它們是如何實現的?

我希望能夠做到這一點:

MyObj("Something Here").SomeMethod("Something Else"); 

,從而能夠創建一個SomeFunc2的方法,我以後可以叫過:

MyObj("Something Here").SomeFunc2("Something Else"); 

回答

1

只是存儲的結果初始MyObj呼叫在本地變量:

var obj = MyObj("Something Here"); 
obj.SomeMethod("Something Else"); 
obj.SomeFunc2("Something else"); 

PublicMethods變量特定於每個呼叫MyObj,因此當您第二次呼叫MyObj時,會得到PublicMethods的不同實例。通過使用變量來存儲第一個MyObj調用的結果,您可以對SomeMethodSomeFunc2函數使用PublicMethods的相同實例。

作爲一個方面說明,你可能想看看constructor functions這將允許你更簡單地定義函數,而不是返回一個對象。例如:

function Example() { 
    this.a = function() { 
     return "a"; 
    }; 
    this.b = function() { 
     this.a = function() { 
      return "b"; 
     } 
    } 
} 

var example = new Example(); 
example.a(); // => "a" 
example.b(); 
example.a(); // => "b" 
+0

所以是jQuery的一個構造函數?我看到jQuery對象可以用參數調用並保持其狀態,並且可以像普通對象一樣訪問成員變量。 這基本上是我試圖模仿的模式 - jQuery模式。 –

+0

種。 'jQuery'函數被定義爲返回一些東西的普通函數。因爲JavaScript中的所有內容(甚至是函數)都是對象,所以可以將自定義屬性附加到函數中。 jQuery使用它將'prototype'對象附加到'jQuery'函數對象。然後,通過向'jQuery.prototype'對象添加'constructor'函數,可以使用'jQuery(「something」)'和'new jQuery(「something」)''。 – Shadowfacts

+0

是的,我認爲函數instanceof可以用來檢查函數是否正常調用,或者用'新'來調用嗎?基本上你可以有2個不同的代碼路徑來調用Foo(arg)和新的Foo(arg)? –

0

可以創建其延伸jQueryjQuery.fn一個jQuery方法,並且還可以設置在方法中this上下文。

(function($) { 
 

 
    jQuery.addMethod = function addMethod({methodName, method, type}) { 
 
    
 
    let bool = { 
 
     [type]: false 
 
    }; 
 
    
 
    let _jQuery_jQueryFn_ = Object.keys(bool).pop(); 
 
    
 
    if (type === "jQuery") { 
 
     for (let prop in jQuery) { 
 
     if (prop === methodName 
 
      || prop.toUpperCase() === methodName.toUpperCase()) { 
 
       bool[type] = true; 
 
       break; 
 
     } 
 
     } 
 
    } 
 

 
    if (type === "fn") { 
 
     for (let prop in jQuery.fn) { 
 
     if (prop === methodName 
 
      || prop.toUpperCase() === methodName.toUpperCase()) { 
 
       bool[type] = true; 
 
       break; 
 
     } 
 
     } 
 
    } 
 

 
    if (type === "jQuery" && bool[_jQuery_jQueryFn_] === false) { 
 
     jQuery[methodName] = method; 
 

 
    } 
 

 
    if (type === "fn" && bool[_jQuery_jQueryFn_] === false) { 
 
     jQuery[type][methodName] = method; 
 
     
 
    } 
 
    
 
    if (bool[_jQuery_jQueryFn_] === true) { 
 
     return Promise.reject(
 
     new ReferenceError(
 
      methodName 
 
      + " previously defined at " 
 
      + _jQuery_jQueryFn_ 
 
    )); 
 
     
 
    } else { 
 
     console.log(methodName + " defined at " + _jQuery_jQueryFn_); 
 
    } 
 

 
    return {methodName:methodName, type}; 
 
    } 
 
})(jQuery); 
 

 
$(function() { 
 

 
    Promise.resolve($.addMethod({ 
 
     methodName: "add", 
 
     method: function add(a, b, context) { 
 
     console.log(a + b); 
 
     return (context || this) 
 
     }, 
 
     type: "jQuery" 
 
    })) 
 
    .then(function({methodName, type}) { 
 
     if (type === "jQuery" && methodName in window[type]) { 
 
      jQuery[methodName](10, 10) 
 
     } else { 
 
     if (methodName in window["jQuery"][type]) { 
 
      jQuery[type][methodName](10, 10); 
 
     } 
 
     }     
 
    }) 
 
    .catch(function(err) { 
 
     console.error(err) 
 
    }); 
 

 
}); 
 

 
$(function() { 
 

 
    Promise.resolve($.addMethod({ 
 
     methodName: "add", 
 
     method: function add(a, b, context) { 
 
     console.log(a + b); 
 
     return (context || this) 
 
     }, 
 
     type: "fn" 
 
    })) 
 
    .then(function({methodName, type}) { 
 
     if (methodName === "jQuery" && methodName in window[type]) { 
 
     jQuery[methodName](10, 10) 
 
     } else { 
 
     if (methodName in window["jQuery"][type]) { 
 
      jQuery("span")[methodName](10, 10); 
 
     } 
 
     }  
 
    }) 
 
    .catch(function(err) { 
 
     console.error(err) 
 
    }); 
 

 
}); 
 

 
$(function() { 
 
    
 
    
 
    Promise.resolve(
 
     $.addMethod({ 
 
     methodName: "reverseText", 
 
     method: function reverseText(_text, context) { 
 
      let text = [...(_text || this.text())].reverse().join(""); 
 
      (context || this).text(text); 
 
      return (context || this) 
 
     }, 
 
     type: "fn" 
 
     })) 
 
    .then(function({methodName, type}) { 
 
     if (type === "jQuery" && methodName in window[type]) { 
 
     jQuery[methodName]() 
 
     } else { 
 
     if (methodName in window["jQuery"][type]) { 
 
      // set context `this` to `span` 
 
      let span = jQuery("section")[methodName]("321", $("span"))  
 
      .css("color", "sienna");  
 
      
 
      console.log(
 
      span.is(document.querySelector("span")) 
 
     ); 
 
     
 
      jQuery("section")[methodName]() 
 
      .css("color", "green"); 
 
     } 
 
     } 
 
    }) 
 
    .catch(function(err) { 
 
     console.error(err) 
 
    }); 
 

 
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"> 
 
</script> 
 
<section>section</section> 
 
<span>span</span>