你的位置:首页 > Java教程

[Java教程][Effective JavaScript 笔记]第18条:理解函数调用、方法调用及构造函数调用之间的不同

面向对象编程中,函数、方法、类的构造函数是三种不同的概念。
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变量的对象。
按照上面的文字,画了一张图:
1464147280602
由于方法其实就是通过特定对象调用的函数,不知为何一个普通的函数不能引用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"

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

1464148054539

如果直接调用 

hello();//"hello,undefined"

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

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

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

结果如图 

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

通过构造函数使用

就像方法和纯函数一样,构造函数也是由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运算符调用,并产生一个新的对象作为其接收者