Effective JavaScript Item 18 理解Function, Method, Constructor调用之间的区别

本系列作为Effective JavaScript的读书笔记。

Function绝对是JavaScript中的重中之重。在JavaScript中,Function承担了procedures,
methods, constructors甚至是classes以及modules的功能。

在面向对象程序设计中,functions,methods以及class
constructor往往是三件不同的事情,由不同的语法来实现。但是在JavaScript中,这三个概念都由function来实现,通过三种不同的模式。

最简单的使用模式就是functioncall:

function hello(username) {
	return "hello, " + username;
}
hello("Keyser Söze"); // "hello, Keyser Söze"

而methods这一概念在JavaScript中的表现就是,一个对象的属性是一个function:

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

以上代码中,比较关键的部分是:使用了this关键字,这里的this指向的是obj对象。你也许会认为正因为hello方法定义在了obj对象上,所以this指向的是obj。但是下面这段代码:

var obj2 = {
hello: obj.hello,
	username: "Boo Radley"
};
obj2.hello(); // "hello, Boo Radley"

真正的行为是,调用本身才会决定this会绑定到哪个对象,即:

obj1.hello()会将this绑定到obj1,obj2.hello()则会将this绑定到obj2。

正因为this绑定的这种规则,在下面的用法也是可行的:

function hello() {
	return "hello, " + this.username;
}

var obj1 = {
	hello: hello,
	username: "Gordon Gekko"
};
obj1.hello(); // "hello, Gordon Gekko"

var obj2 = {
	hello: hello,
	username: "Biff Tannen"
};_
obj2.hello(); // "hello, Biff Tannen"

但是,在一个普通的函数中,如上面的hello函数,使用this关键字是不太好的方式,当它被直接调用的时候,this的指向就成了问题。在这种情况下,this往往被指向全局对象(GlobalObject),在浏览器上一般就是window对象。

而这种行为是不确定和没有意义的。

所以在ES5标准中,如果使用了strict
mode,那么this会被设置为undefined:

function hello() {
	"use strict";
	return "hello, " + this.username;
}
hello(); // error: cannot read property "username" of undefined

以上这种做法是为了让潜在的错误更快的暴露出来,避免了误操作和难以找到的bug。

function的第三种使用模式就是讲它作为constructor:

function User(name, passwordHash) {
	this.name = name;
	this.passwordHash = passwordHash;
}
var u = new User("sfalken",
	"0ef33ae791068ec64b502d6cb0191387");
u.name; // "sfalken"

使用new关键将function作为constructor进行调用。和function以及method调用不一样的是,constructor会传入一个新的对象并将它绑定到this,然后返回该对象作为constructor的返回值。而constructor
function本身的作用就是为了初始化该对象。

总结:

  1. Method调用本身会决定this绑定到哪个对象
  2. Function调用中,this会指向全局对象,在浏览器中,通常是window对象
  3. Constructor调用通过new关键字完成,会将this绑定到一个新的对象上

时间: 2024-12-15 08:32:43

Effective JavaScript Item 18 理解Function, Method, Constructor调用之间的区别的相关文章

Effective JavaScript Item 30 理解prototype, getPrototypeOf和__proto__的不同

本系列作为Effective JavaScript的读书笔记. prototype,getPropertyOf和__proto__是三个用来访问prototype的方法.它们的命名方式很类似因此很容易带来困惑. 它们的使用方式如下: prototype: 一般用来为一个类型建立它的原型继承对象.比如C.prototype = xxx,这样就会让使用new C()得到的对象的原型对象为xxx.当然使用obj.prototype也能够得到obj的原型对象. getPropertyOf: Object

Effective JavaScript Item 12 理解Variable Hoisting

本系列作为Effective JavaScript的读书笔记. JavaScript中并没有Block Scoping,只有Function Scoping. 因此如果在一个Block中定义了一个变量,那么这个变量相当于是被定义到了这个Block属于的Function中,比如: function isWinner(player, others) { var highest = 0; for (var i = 0, n = others.length; i < n; i++) { <span s

Effective JavaScript Item 38 在子类构造函数中调用父类构造函数

本系列作为Effective JavaScript的读书笔记. 在一个游戏或者图形模拟的应用中,都会有场景(Scene)这一概念.在一个场景中会包含一个对象集合,这些对象被称为角色(Actor).而每个角色根据其类型会有一个图像用来表示,同时场景也需要保存一个底层图形展示对象的引用,被称为上下文(Context): function Scene(context, width, height, images) { this.context = context; this.width = width

深入理解 &#39;0&#39; &quot;0&quot; &#39;\0&#39; 0 之间的区别

看来基础还是很重要的,基础不扎实就难以学好c语言,就别说写出高质量的c语言代码了.今天,我就被这个问题折磨的不行了,哈哈,不过现在终于明白了‘\0’ ,‘0’, “0” 之间的区别了.困惑和快乐与你分享! 首先比较一下‘\0’和‘0’的区别.有一个共同点就是它们都是字符,在c语言中,字符是按其所对应的ASCII码来存储的,一个字符占一个字节.请翻开 你的ASCII字符集表吧,一般在你的C语言教材的附录上,没有的话网上查查哦.请看第一个ASCII码,对是0,对应的字符是(Null),其实就是 ‘\

Effective JavaScript Item 19 使用高阶函数 (High-Order Function)

本系列作为Effective JavaScript的读书笔记. 不要被高阶函数这个名字给唬住了.实际上,高阶函数只是代表了两类函数: 接受其他函数作为参数的函数 返回值为函数的函数 有了这个定义,你也许就发现你已经使用过它们了,典型的就是对于一些事件的处理时传入的回调函数. 另外的一个典型使用场景就是Array类型的sort函数,它可以接受一个function作为排序时比较的判断依据: [3, 1, 4, 1, 5, 9].sort(function(x, y) { if (x < y) { r

Effective JavaScript Item 25 使用bind方法来得到一个固定了this指向的方法

本系列作为Effective JavaScript的读书笔记. 当需要将方法抽取出来作为回调函数使用的时候,常常会因为this的指向不明而发生错误,比如: var buffer = { entries: [], add: function(s) { this.entries.push(s); }, concat: function() { return this.entries.join(""); } }; 如果想利用其中的add作为回调函数对一组数据进行添加: var source

Effective JavaScript Item 23 永远不要修改arguments对象

本系列作为Effective JavaScript的读书笔记. arguments对象只是一个类似数组的对象,但是它并没有数组对象提供的方法,比如shift,push等.因此调用诸如:arguments.shift(),arguments.push()是错误的. 在Item 20和Item 21中,知道了函数对象上存在call和apply方法,那么是不是可以利用它们来让arguments也能够利用数组的方法呢: function callMethod(obj, method) { var shi

Effective JavaScript Item 20 使用call方法来绑定this变量

本系列作为Effective JavaScript的读书笔记. 通常而言,一个函数中this的指向和该函数的调用类型相关,比如当函数直接作为函数被调用时,this一般指向的是全局对象(StrictMode时指向undefined):当函数作为方法被调用时(即x.method()这种形式),this指向的是x:当函数作为构造方法被调用时,this指向的是一个新创建的对象. 但是在一些场合,需要指定this的指向,比如下面的代码需要将this指向一个对象obj,一个简单的办法如下: obj.temp

Effective JavaScript Item 37 认识this的隐式指向

本系列作为Effective JavaScript的读书笔记. CSV数据通常都会被某种分隔符进行分隔,所以在实现CSV Reader时,需要支持不同的分隔符.那么,很自然的一种实现就是将分隔符作为构造函数的参数. function CSVReader(separators) { this.separators = separators || [","]; this.regexp = new RegExp(this.separators.map(function(sep) { retu