面向对象编程中,函数、方法、类的构造函数是三种不同的概念。
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. 初识Groovy

    Groovy是一种基于JVM(Java虚拟机)的敏捷开发语言,它结合了Python.Ruby和Smalltalk的许多强大的特性,Groovy 代码能够与 Java 代码很好地结合,也能用于扩展现有代 ...

  2. Scala学习笔记(七):Application特质

    Scala提供了特质scala.Application 在单例对象名后面写上“extends Application”,把想要执行的代码直接放在单例对象的花括号之间 import ChecksumAc ...

  3. 几种Boost算法的比较(Discrete AdaBoost, Real AdaBoost, LogitBoost, Gentle Adaboost)

    关于boost算法 boost算法是基于PAC学习理论(probably approximately correct)而建立的一套集成学习算法(ensemble learning).其根本思想在于通过 ...

  4. 自己编写redis客户端[deerlet-redis-client],分享与招募。

    引言 最近工作上有需要使用redis,于是便心血来潮打算自己写一个Java客户端.经过两天的努力,目前该客户端已经基本成型.不过可惜的是,由于redis的命令众多,因此LZ还需要慢慢扩展它去支持更多的 ...

  5. iptables 的使用

    iptables 是Linux 防火墙规则配置命令 iptables -L -n 查看目前配置 iptables -F        清除预设表filter中的所有规则链的规则 iptables -A ...

  6. [wikioi 1034][CTSC 1999]家园(网络流)

    由于人类对自然的疯狂破坏,人们意识到在大约2300年之后,地球不能再居住了,于是在月球上建立了新的绿地,以便在需要时移民.令人意想不到的是,2177年冬由于未知的原因,地球环境发生了连锁崩溃,人类必须 ...

  7. DOM(六)事件类型

    对于用户事件类型而言,最常用的是鼠标.键盘.浏览器. 1.鼠标事件: 鼠标的事件都频繁使用,下面例子就测试各种鼠标事件 <script language="javascript&quo ...

  8. 今天学习到的关于mysql数据库的linux命令

    1. 登录mysql数据库: mysql -uroot -p 2.安装会提示的mysql的数据库软件:mycli sudo apt-get install mycli 3.安装依赖包: sudo ap ...

  9. LCA最近公共祖先 Tarjan离线算法

    学习博客:  http://noalgo.info/476.html 讲的很清楚! 对于一颗树,dfs遍历时,先向下遍历,并且用并查集维护当前节点和父节点的集合.这样如果关于当前节点(A)的关联节点( ...

  10. yii2URL美化

    yii2的url 域名/index.php?r=site%2Findex 实际为 域名/index.php?r=site/index 可以美化下 可以在main.php中配置 'components' ...