面向对象编程中,函数、方法、类的构造函数是三种不同的概念。
JS中,它们只是单个构造对象的三种不同的使用模式。

三种不同的使用模式

函数调用

function hello(username){
return 'hello,'+username;
}
hello('world');//"hello,world"

函数的表现与行为一致,调用hello函数并将给定的实参绑定到username形参。

方法调用

js中的方法,是指对象的属性恰好是函数而已。

var obj={
hello:function(){
return 'hello,'+this.username;
},
username:'world'
};
obj.hello();//"hello,world"

这里方法hello是通过this变量来访问obj对象的属性的。

this的指向是如何完成的呢?从上面的这个例子中,可能倾向于this变量被绑定到obj对象了,由于hello方法定义在obj对象中。
下面看一个例子

var obj2={
hello:obj.hello,
username:'han mei mei.'
}
obj2.hello();//"hello,han mei mei."

事实是,在方法调用的时候才由表达式来确定this变量的绑定情况。

绑定到this变量的对象被称为调用接收者(receiver)。
表达式obj.hello()在obj对象中查找名为hello的属性,并将obj对象作为接收者,然后调用该属性。
表达式obj2.hello()在obj2对象中查找名为hello的属性,恰巧是obj.hello函数,但是接收者是obj2对象。
通常,通过某个对象调用方法将查找该方法并将对象作为该方法的接收者,也即this变量的对象。
按照上面的文字,画了一张图:

由于方法其实就是通过特定对象调用的函数,不知为何一个普通的函数不能引用this变量。

function hello(){
return 'hello,'+this.username;
} var obj1={
hello:hello,
username:'obj1'
}
var obj2={
hello:hello,
username:'obj2'
}
obj1.hello();//"hello,obj1"
obj2.hello();//"hello,obj2"

上面这段代码的结构图应该是这样的。

如果直接调用 

hello();//"hello,undefined"

一个非方法(nonmethod)的函数调用会将全局对象作为接收者,这时全局对象没有名为username的属性所以产生了undefined。

如果方法中需要使用this变量,则将方法作为函数调用则毫无用处,因为没有理由希望全局对象匹配调用对象中的方法。事实上,将this变量绑定到全局对象是有问题的,ES5严格模式将this变量的默认绑定值改为undefined

function hello(){
'use strict';
return 'hello,'+this.username;
}
hello();

结果如图


这样做可以有助于更快地捕获偶然地将方法错误地作为纯函数使用的情况。

通过构造函数使用

就像方法和纯函数一样,构造函数也是由function运算符定义的。
function User(name,pwd){
this.name=name;
this.pwd=pwd;
}
var u=new User('li lei','asdfxov2-3409');
u.name;//"li lei"

与函数调用和方法调用不同的是,构造函数调用将一个全新的对象作为this变量的值,并隐式返回这个新对象作为调用结果。构造函数的主要职责是初始化该新对象。

提示

  • 方法调用将被查找方法属性的对象作为调用接收者(this绑定)

  • 函数调用将全局对象(处于严格模式下则为undefined)作为其接收者。很少使用函数调用语法来调用方法。

  • 构造函数需要通过new运算符调用,并产生一个新的对象作为其接收者

[Effective JavaScript 笔记]第18条:理解函数调用、方法调用及构造函数调用之间的不同的更多相关文章

  1. [Effective JavaScript 笔记]第50条:迭代方法优于循环

    "懒"程序员才是好程序员.复制和粘贴样板代码,一但代码有错误,或代码功能修改,那么程序在修改的时候,程序员需要找到所有相同功能的代码一处处进行修改.这会使人重复发明轮子,而且在别人 ...

  2. [Effective JavaScript 笔记] 第13条:使用立即调用的函数表达式创建局部作用域

    function wrapElements(a){ var res=[],i,n; for(i=0,n=a.length;i<n;i++){ res[i]=function(){return a ...

  3. [Effective JavaScript 笔记] 第5条:避免对混合类型使用==运算符

    “1.0e0”=={valueOf:function(){return true;}} 是值是多少? 这两个完全不同的值使用==运算符是相等的.为什么呢?请看<[Effective JavaSc ...

  4. [Effective JavaScript 笔记]第27条:使用闭包而不是字符串来封装代码

    函数是一种将代码作为数据结构存储的便利方式,代码之后可以被执行.这使得富有表现力的高阶函数抽象如map和forEach成为可能.它也是js异步I/O方法的核心.与此同时,也可以将代码表示为字符串的形式 ...

  5. [Effective JavaScript 笔记] 第4条:原始类型优于封闭对象

    js有5种原始值类型:布尔值.数字.字符串.null和undefined. 用typeof检测一下: typeof true; //"boolean" typeof 2; //&q ...

  6. [Effective JavaScript 笔记]第28条:不要信赖函数对象的toString方法

    js函数有一个非凡的特性,即将其源代码重现为字符串的能力. (function(x){ return x+1 }).toString();//"function (x){ return x+ ...

  7. [Effective JavaScript 笔记]第20条:使用call方法自定义接收者来调用方法

    不好的实践 函数或方法的接收者(即绑定到特殊关键字this的值)是由调用者的语法决定的.方法调用语法将方法被查找的对象绑定到this变量,(可参阅之前文章<理解函数调用.方法调用及构造函数调用之 ...

  8. [Effective JavaScript 笔记]第55条:接收关键字参数的选项对象

    53节建议保持参数顺序的一致约定对于帮助程序员记住每个参数在函数调用中的意义很重要.参数较少这个主意不错,但如果参数过多后,就出现麻烦了,记忆和理解起来都不太容易. 参数蔓延 如下面这些代码: var ...

  9. [Effective JavaScript 笔记]第33条:使构造函数与new操作符无关

    当使用函数作为一个构造函数时,程序依赖于调用者是否记得使用new操作符来调用该构造函数.注意:该函数假设接收者是一个全新的对象. 一个例子 function User(name,pwd){ this. ...

随机推荐

  1. ajax请求模拟登录

    前台 @if (Session["username"] != null) { <div class="login"> <span style= ...

  2. Bootstrap3.0学习第八轮(工具Class)

    详情请查看http://aehyok.com/Blog/Detail/14.html 个人网站地址:aehyok.com QQ 技术群号:206058845,验证码为:aehyok 本文文章链接:ht ...

  3. JavaScript基础系列目录(2014.06.01~2014.06.08)

    下列文章,转载请亲注明链接出处,谢谢! 链接地址: http://www.cnblogs.com/ttcc/tag/JavaScript%20%E5%9F%BA%E7%A1%80%E7%9F%A5%E ...

  4. 第四十六课:MVC和MVVM的开发区别

    实现MVC的目的就是为了让M和V相分离.前端的MVC无法做到View和Model的相分离,而MVVM可以. 我们先来看一个用MVC模式开发的经典例子:(一定要深入了解这种开发的思想,而不是看懂代码) ...

  5. javax.servlet.ServletException: com.microsoft.jdbc.base.BaseDatabaseMetaData.supportsGetGeneratedKeys()Z

    javax.servlet.ServletException: com.microsoft.jdbc.base.BaseDatabaseMetaData.supportsGetGeneratedKey ...

  6. maven_创建quickstart模板时异常

    错误信息: Could not resolve archetype org.apache.maven.archetypes:maven-archetype-quickstart:1.1 from an ...

  7. Ajax 的缺点

    1.ajax干掉了back按钮,即对浏览器后退机制的破坏.后退按钮是一个标准的web站点的重要功能,但是它没法和js进行很好的合作.这是ajax所带来的一个比较严重的问题,因为用户往往是希望能够通过后 ...

  8. Hibernate-入门教程

    首先了解hibernate的目录结构 . +lib antlr.jar cglib-full.jar asm.jar asm-attrs.jars commons-collections.jar co ...

  9. 前端筑基篇(一)->ajax跨域原理以及解决方案

    说明 跨域主要是由于浏览器的“同源策略”引起,分为多种类型,本文主要探讨Ajax请求跨域问题 前言 参考来源 什么是跨域 ajax跨域的表现 跨域的原理 如何解决跨域问题 JSONP方式解决跨域问题 ...

  10. codeforces 719A:Vitya in the Countryside

    Description Every summer Vitya comes to visit his grandmother in the countryside. This summer, he go ...