`

js 方法调用

 
阅读更多

英文原版: http://devlicio.us/blogs/sergio_pereira/archive/2009/02/09/javascript-5-ways-to-call-a-function.aspx

 

Time after time I find JavaScript code that has bugs caused by lack of proper understanding of how functions work in JavaScript (a lot of that code has been written by me, by the way.) JavaScript has functional programming characteristics, and that can get in our way until we decide to face and learn it.

For starters, let's examine five ways to invoke a function. On the surface we might be tempted to think that functions work exactly like C#, but we will see that there are important differences and ignoring them will undoubtedly result in hard to track bugs.

Let's first create a simple function that we will be using through the rest of this post. This function will just return an array with the current value of this and the two supplied arguments.

    <script type="text/javascript">  
    function makeArray(arg1, arg2){  
        return [ this, arg1, arg2 ];  
    }  
    </script>  
 

Most common way, unfortunately, global function calls

When we are learning JavaScript we learn how to define functions using the syntax used in the example above. We learn that it's also very easy to call that function — all we need to do is:


    makeArray('one', 'two');  
    // => [ window, 'one', 'two' ]  
 

Wait a minute. What's that window object doing there? Why is it the value of this ? If you haven't stopped to think about it, please stay with me here.

In JavaScript, and I'm not talking specifically about the browser here, there's a default/global object. It's as if every code that we write which seems to be just "loose" inside your script (i.e. outside of any object declaration) is actually being written in the context of that global object. In our case, that makeArray function isn't just a loose "global" function, it's a method of the global object. Bringing ourselves back to the browser, the global object is mapped to the window object in this environment. Let's prove that.

    alert( typeof window.methodThatDoesntExist );  
    // => undefined  
    alert( typeof window.makeArray);  
    // => function  
 

What all this means is that calling makeArray like we did before is the same as calling as follows.


    window.makeArray('one', 'two');  
    // => [ window, 'one', 'two' ]  
 

I say it's unfortunate that this is the most common way because it leads us to declare our functions globally by default. And we all know that global members are not exactly the best practice in software programming. This is especially true in JavaScript. Avoid globals in JavaScript, you won't regret it.

JavaScript function invocation rule #1 In a function called directly without an explicit owner object, like myFunction() , causes the value of this to be the default object (window in the browser).

Method call

Let's now create a small object and use the makeArray function as one of its methods. We will declare the object using the literal notation. Let's also call this method.


    //creating the object  
    var arrayMaker = {  
        someProperty: 'some value here',  
        make: makeArray  
    };  
      
    //invoke the make() method  
    arrayMaker.make('one', 'two');  
    // => [ arrayMaker, 'one', 'two' ]  
    // alternative syntax, using square brackets  
    arrayMaker['make']('one', 'two');  
    // => [ arrayMaker, 'one', 'two' ]  
 

See the difference here? The value of this became the object itself. You may be wondering why isn't it still window since that's how the original function had been defined. Well, that's just the way functions are passed around in JavaScript. Function is a standard data type in JavaScript, an object indeed; you can pass them around and copy them. It's as if the entire function with argument list and body was copied and assigned to make in arrayMaker . It's just like defining arrayMaker like this:


    var arrayMaker = {  
        someProperty: 'some value here',  
        make: function (arg1, arg2) {  
            return [ this, arg1, arg2 ];  
        }  
    };  
 
JavaScript function invocation rule #2 In a function called using the method invocation syntax, like obj.myFunction() or obj['myFunction']() , causes the value of this to be obj .

This is a major source of bugs in event handling code. Look at these examples.


    <input type="button" value="Button 1" id="btn1"  />  
    <input type="button" value="Button 2" id="btn2"  />  
    <input type="button" value="Button 3" id="btn3"  onclick="buttonClicked();"/>  
      
    <script type="text/javascript">  
    function buttonClicked(){  
        var text = (this === window) ? 'window' : this.id;  
        alert( text );  
    }  
    var button1 = document.getElementById('btn1');  
    var button2 = document.getElementById('btn2');  
      
    button1.onclick = buttonClicked;  
    button2.onclick = function(){   buttonClicked();   };  
    </script>  
 

Clicking the first button will display "btn1" because it's a method invocation and this will be assigned the owner object (the button input element.) Clicking the second button will display "window" because buttonClicked is being called directly (i.e. not like obj.buttonClicked() .) This is the same thing that happens when we assign the event handler directly in the element's tag, as we have done for the third button. Clicking the third button does the same of the second button.

That's another advantage of using a library like jQuery. When defining event handlers in jQuery, the library will take care of overriding the value of this and make sure it contains a reference to the element that was the source of the event.

    //using jQuery  
    $('#btn1').click( function() {  
        alert( this.id ); // jQuery ensures 'this' will be the button  
    });  
 

How does jQuery override the value of this ? Keep reading.

Two more: apply() and call()

The more you leverage functions in JavaScript, the more you find yourself passing functions around and needing to invoke them in different contexts. Just like jQuery does in the event handler functions, you'll often need to override the value of this . Remember I told you functions are objects in JavaScript? Functions have predefined methods, two of them are apply() and call() . We can use them to do precisely that kind of overriding.


    var gasGuzzler = { year: 2008, model: 'Dodge Bailout' };  
    makeArray.apply( gasGuzzler, [ 'one', 'two' ] );  
    // => [ gasGuzzler, 'one' , 'two' ]  
    makeArray.call( gasGuzzler,  'one', 'two' );  
    // => [ gasGuzzler, 'one' , 'two' ]  
 

The two methods are similar. The first parameter will override this . They differ on the subsequent arguments. Function.apply() takes an array of values that will be passed as arguments to the function and Function.call() takes the same arguments separately. In practice I believe you'll find that apply() is more convenient in most cases.

JavaScript function invocation rule #3 If we want to override the value of this without copying the function to another object, we can use myFunction.apply( obj ) or myFunction.call( obj ) .

Constructors

I won't delve into the details of defining types in JavaScript but at minimum we should be aware that there aren't classes in JavaScript and that any custom type needs a constructor function. It's also a good idea to define the methods of your type using the prototype object, which is a property of the constructor function. Let's create a small type.

    //declaring the constructor  
    function ArrayMaker(arg1, arg2) {  
        this.someProperty = 'whatever';  
        this.theArray = [ this, arg1, arg2 ];  
    }  
    // declaring instance methods  
    ArrayMaker.prototype = {  
        someMethod: function () {  
            alert( 'someMethod called');  
        },  
        getArray: function () {  
            return this.theArray;  
        }  
    };  
      
    var am = new ArrayMaker( 'one', 'two' );  
    var other = new ArrayMaker( 'first', 'second' );  
      
    am.getArray();  
    // => [ am, 'one' , 'two' ]  
 

What's very important to note here is the presence of the new operator before the function call. Without that your function will just be called like a global function and those properties that we are creating would be created on the global object (window .) And you don't want to do that. Another issue is that, because you typically don't have an explicit return value in your constructor function, you'll end up assigning undefined to some variable if you forget to use new . For these reasons it's a good convention to name your constructor functions starting with an upper case character. This should serve as a reminder to put the new operator before the call.

With that taken care of, the code inside the constructor is very similar to any constructor you probably have written in other languages. The value of this will be the new object that you are trying to initialize.

JavaScript function invocation rule #4 When used as a constructor, like new MyFunction() , the value of this will be a brand new object provided by the JavaScript runtime. If we don't explictly return anything from that function, this will be considered its return value.

It's a wrap

I hope understanding the differences between the invocation styles help you keeping bugs out of your JavaScript code. Some of these bugs can be very tricky do identify and making sure you always know what the value of this will be is a good start to avoiding them in the first place.

 

 

分享到:
评论

相关推荐

    WebView JS方法调用

    而“WebView JS方法调用”是指在WebView加载的HTML页面中,通过JavaScript代码调用Android原生方法,实现Web与Native的交互。这种交互方式极大地扩展了WebView的功能,使得网页可以与应用程序深度整合。 首先,我们...

    android demo,webview_js(webview的js方法调用java方法)。

    本示例“android demo,webview_js”着重展示了如何通过Webview实现JavaScript调用Java方法的功能。这个功能对于创建混合式应用或者在原生应用中嵌入HTML5页面尤其有用。 首先,我们需要在Android布局文件中添加一...

    JS调用C#后台方法

    本文将深入探讨如何使用JavaScript调用C#编写的后台方法,并介绍相关技术与实践。 首先,JavaScript作为客户端脚本语言,运行在用户的浏览器上,而C#通常是服务器端的语言,运行在Web服务器上。要实现它们之间的...

    jsp 日期 日历js方法调用!简单,方便,好用!

    jsp 日期 日历js方法调用 简单 方便 好用 &lt;script language="javascript" type="text/javascript" src="My97DatePicker/WdatePicker.js"&gt; ()"&gt; 文件夹请放到WebRoot下! 单击文本框就可调用日期

    js调用C#方法

    JavaScript调用C#方法 JavaScript可以通过以下步骤来调用服务器端的C#方法: ##### 步骤一:定义服务器端C#方法 确保该方法被标记为`public`,以便JS能够访问。例如: ```csharp public string GetServerData()...

    vbscript和javascript互相调用方法

    -- JavaScript调用VBScript函数 --&gt; document.write(FormatValue(1234.56)) ``` 然而,这种直接在HTML中嵌入VBScript的做法在安全性方面存在隐患,并且在现代Web开发实践中不推荐使用。 ### 数组转换:VBScript...

    Android中调用js方法及js中调用本地方法

    本文将详细讲解如何在Android中调用JavaScript的方法,以及JavaScript如何反向调用Android本地方法。 首先,让我们从Android调用JavaScript的方法开始。Android中的WebView组件是实现这种交互的主要工具。当在...

    OC调用JS以及JS调用OC的demo调用JS以及JS调用OC的demo

    这个示例项目包含了`03-webView`、`04-oc调用js方法`、`05-js调用oc中的方法`等文件夹,它们分别展示了上述过程的实现细节。`myweb`可能是一个包含HTML和JavaScript的文件,用于测试这些交互功能。 总的来说,通过...

    Struts2动态方法调用

    1. **JS方法调用**: 在Struts2中,JavaScript可以用来发起Ajax请求,动态调用后台Action的方法。例如,我们可以使用jQuery的`$.ajax`或`$.post`方法,配合Struts2的ActionContext,将请求参数传递给服务器。在...

    C++与js相互调用

    JavaScript调用C++通常依赖于一些库或框架,如Emscripten,它是一个LLVM到JavaScript的编译器,可以将C/C++代码编译成WebAssembly,然后在浏览器中运行。另一个常见的方式是使用ChakraCore,Microsoft的JavaScript...

    Winform中使用CefSharp和js互相调用方法

    Winform中使用CefSharp和js互相调用方法,Winform中使用CefSharp和js互相调用方法,Winform中使用CefSharp和js互相调用方法,Winform中使用CefSharp和js互相调用方法 vs2019.debug目录下有cef所需要的文件,在其他...

    android webview中使用Java调用JavaScript方法并获取返回值

    如果需要在WebView中启用JavaScript调用Android代码的功能,还要在addJavascriptInterface()方法中声明一个Java类的实例,并为其指定一个可以在JavaScript中访问的接口名字。 在Java代码中定义一个内部类,用于接收...

    android和js相互调用

    ### JavaScript调用Android 要使JavaScript能够调用Android方法,你需要实现`WebViewClient`并重写`shouldOverrideUrlLoading()`方法。在这个方法中,你可以识别特定的URL模式并执行相应的Android代码。比如,定义...

    javascript调用delphi中的函数

    标题“javascript调用delphi中的函数”涉及到的技术领域是跨语言通信,具体是JavaScript与Delphi之间的交互。这种交互通常发生在Web应用程序与桌面应用程序的集成,或者在浏览器扩展和本地资源之间。以下是对这一...

    javascript 直接调用OC 方法demo

    总结,JavaScript调用Objective-C方法的实现依赖于JavaScriptCore框架,通过JSContext、JSExport协议以及桥接方法实现跨语言通信。这种方法在混合开发中非常有用,允许开发者利用Web技术构建用户界面,同时充分利用...

    link中调用js方法

    link中调用js方法 link中调用js方法link中调用js方法link中调用js方法

    c# winform webbrowser页面中js调用winform类方法

    除了直接调用方法外,还可以创建一个事件回调系统,使得WinForm可以监听JavaScript的某些事件。这通常通过在C#中定义一个事件,并在JavaScript中触发这个事件来实现。 5. **异步调用**: 如果C#方法需要执行耗时...

    C#与JAVASCRIPT函数的相互调用 C#调用JAVASCRIPT函数的调用 JAVASCRIPT调用C#函数的调用

    C#与JAVASCRIPT函数的相互调用 C#调用JAVASCRIPT函数的调用 JAVASCRIPT调用C#函数的调用

    cefsharp JavaScript调用C#方法并返回参数

    本文将深入探讨如何利用CEFSharp实现JavaScript调用C#方法,并获取返回的参数。 首先,理解CEFSharp的工作原理至关重要。CEFSharp是Chromium Embedded Framework(CEF)的.NET封装,而CEF是一个开源项目,用于在...

    JS调用后台带参数的方法

    根据给定的信息,本文将详细解释“JS调用后台带参数的方法”。这涉及到前端JavaScript与后端服务之间的交互,特别是如何在发送请求时携带参数。 ### JS调用后台带参数的基本概念 在Web开发中,前端(通常是...

Global site tag (gtag.js) - Google Analytics