面向对象编程中,函数、方法、类的构造函数是三种不同的概念。
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. 第二章 OO大原则

    昨天忙了一天,晚上加班到了12点,虽然工作有时候比较累,但是整体来讲还是比较轻松的,国企加上我是今年才毕业的应届生,导致了现在这种情况.工资也真的不算高...但我觉得最开始还是要踏踏实实一点比较好.学 ...

  2. [bzoj 1064][NOI2008]假面舞会(dfs判断环)

    题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1064 分析: 如果a看到b,则a->b 那么: 1.如果图中有环,则说明这个环的 ...

  3. java网络编程基础

    前言 通过网络进行数据传输时,一般使用TCP/UDP进行数据传输.但是两个的区别就是TCP可靠,UDP不可靠.两个的共同之处就是都需要建立socket套接字,将IP地址和端口port进行绑定.但是服务 ...

  4. angular例子笔记

    学习angular的插件写法和制作; <!DOCTYPE html> <html ng-app="APP"> <head> <meta c ...

  5. iOS--雪花掉落特效

    - (void)createAnimaton { // 实例化发射器 CAEmitterLayer *snowLayer = [CAEmitterLayer layer]; // 设置大小 snowL ...

  6. java ee 中文乱码的问题

    java ee 中文乱码的问题 发生中文乱码的三种情况 (一) 表单form Post 方法 直接在服务器中设置 request.setCharacterEncoding("utf-8&qu ...

  7. hdu1542矩阵的并 线段树+扫描线

    求矩阵的并,也就是要求所有的面积.那可以吧总的图形按照矩阵来切割.使其为一块一块. 输入的时候用坐标表示,这里扫描线从下到上扫描.初始时让下面的边为1,上面的为-1: 用一条先从下面开始想上扫描.遇到 ...

  8. Java-LinkedHashSet

    如下: package 集合类.Set类; import java.util.Arrays; import java.util.HashSet; import java.util.LinkedHash ...

  9. 【bzoj1037】 ZJOI2008—生日聚会Party

    http://www.lydsy.com/JudgeOnline/problem.php?id=1037 (题目链接) 题意 有n个boy和m个girl排成一排,求使得任意一段的boy个数girl个数 ...

  10. UOJ150 运输计划

    运输计划(transport.cpp/c/pas)[问题描述]公元 2044 年,人类进入了宇宙纪元.L 国有 n 个星球,还有 n-1 条 双向 航道,每条航道建立在两个星球之间,这 n-1 条航道 ...