2016-12-23 51 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>