Crockford的书中提到的"method":Javascript: The Good Parts

24
道格拉斯·克罗克福德在他的书中写道(第4页):
整本书都使用一个名为method的方法来定义新方法,这是它的定义:
Function.prototype.method = function (name, func) {
    this.prototype[name] = func;
    return this;
};

然后他开始使用这种方法在Number、String、Function、Object、Array、RegExp中添加方法,以下是完整列表:

P33:

Number.method('integer', function () {...});
String.method('trim', function () {...});

P40(不确定第41页是否有印刷错误:the end()):
String.method('deentityify', function () {...}());

P43和P44:

Function.method('curry', function () {...});

P47(我在这里有些困惑,不知道为什么Crockford定义了new方法,而他似乎从未在书中使用new方法):
Function.method('new', function () {...});

P48:
第48页:
Function.method('inherits', function (Parent) {...});

P54:

Object.method('superior', function (name) {...});

P62:

Array.method('reduce', function (f, value) {...});

P79:

Array.method('pop', function () {...});
Array.method('push', function () {...});
Array.method('shift', function () {...});

P82:

Array.method('splice', function (start, deleteCount) {...});

P84:

Function.method('bind', function (that) {...});

P88:

RegExp.method('test', function (string) {...});
String.method('charAt', function (pos) {...});

P90(不确定第91页中是否有打印错误:the end()):
String.method('entityify', function () {...}());

“方法”这个定义是基于“函数”的,为什么它可以在除了“函数”之外的数据类型中使用,例如“数字、字符串、对象、数组、正则表达式”?并且这个“方法”能用于其他数据类型吗?

另一个小问题:在第63页和64页中,Array.dim, Array.matrix, Array.identity的定义没有使用上述的“方法”,为什么?

5个回答

23
所有 JavaScript 中的原生函数都继承自 Function.prototypeNumberStringObjectArrayRegExp 都是函数,因此它们继承自 Function.prototypemethod 旨在调用构造函数上。它的作用是将您提供的函数转化为每个由该构造函数创建的对象上都存在的方法。您会注意到,在 Crockford 传递给 method 的函数中,他使用了 this,它是指调用方法的对象的引用。Array.dim, Array.matrixArray.identity 不使用 this,因为它们独立于任何特定的数组操作,因此不需要成为单个数组对象的方法。它们被分配为 Array 函数的属性,以方便使用:它们同样可以作为全局范围中的函数而存在。

1
@约翰:我向你保证,它们都是函数。如果你不相信我,可以尝试alert(typeof Number)等方法,或者查看规范(第15.1.4节):http://www.ecma-international.org/publications/standards/Ecma-262.htm。如果你的意思是它们也是全局对象的属性,那么也是这样的。 - Tim Down
1
@John:我明白了,你看了Mozilla的文档 https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects。它说得没错,`Number`、`String`、`Object`等不仅是函数,也是对象,因为所有函数都是对象;同时,作为全局对象的属性,它们在全局范围内可用,因此可以被描述为“全局对象”。然而,考虑到正式定义的术语“全局对象”的存在,我认为Mozilla使用术语“全局对象”并不太有帮助。 - Tim Down
1
谢谢!你甚至知道我提出这个问题的原因。我不能很好地理解Mozilla的术语“全局对象”,也许这是我在SO上的下一个问题。 - John
那么为什么我不能在Node 5.2.0中运行它们?我得到了一个“String.method不是函数”的错误。 - Manuel Hernandez
当我在Chrome浏览器控制台中将Crockford的函数分配给Function.prototype.method时,它按预期工作。 Number.method被定义。但是当我在NodeJS中尝试时,Number.methodundefined。这就是我在阅读Crockford的书时尝试后引发这个问题的原因。 - dmmfll
显示剩余2条评论

4
作为一个旁白,关于P40:
end()意味着“使用此函数返回的函数”,而不是返回它的外部函数。
如果他省略了最后的(),对deentityify的调用将返回一个函数,而不是一个字符串。
用Douglas Crockford自己的话来说:
我们立即使用()运算符调用刚刚创建的函数。该调用创建并返回成为deentityify方法的函数。

3
@Tim Down 给出的解决方案是准确的,但不是完全清晰的。
首先,在 JavaScript 中,函数也是一个对象。我指的不是通过 new() 构造创建的对象,而是函数本身。为避免混淆,我将这样的对象称为函数对象,对于使用函数的 new() 构造创建的对象,则称之为函数实例对象
其次,JavaScript 中的任何函数对象都有两个属性:_proto_prototype。此外,任何函数实例对象(使用构造函数创建)都具有一个属性_proto__proto_ 定义了继承关系。关于这方面的一些好资源可以在以下网址找到:

http://zeekat.nl/articles/constructors-considered-mildly-confusing.html

继承是如何定义的?

如果对象objA和objC通过任意数量的_proto_连接,则对象objA继承另一个对象objC。因此,如果objA的_proto_等于objB,而objB的_proto_等于objC,则objA继承objB和objC,而objB继承objC。

什么是继承?

这意味着任何继承对象都可以使用继承对象的任何属性。

什么是Function.prototype?

它是每个函数对象_proto_所指向的对象。这意味着每个函数对象都可以访问Function.prototype的属性,因为每个函数对象都继承了Function.prototype对象。这也意味着,如果在Function.prototype对象中添加方法属性,它将对javascript中所有可能的函数对象可用,包括字符串、数字等。

这里的 this.prototype[name] = func; 中的 this 指向 Function 对象,当从 Number、String 等 Function 对象 调用 'method' 时,意味着我们现在在 Function 对象 中有一个名为 "name" 的新属性,它是一个函数 'func'。 Function 对象prototype 是由使用该函数的 new 构造创建的 Function 实例对象_proto_ 所引用。
如果执行以下代码:

Number.method('integer', function () {...});

则 Number.prototype 中就定义了该 integer 方法。这意味着每个 Number function instance object(例如 new Number(2.4))都会从 Number.prototype 继承此新属性 'integer',因为该 Number function instance object_proto_ 将设置为 Number.prototype。

0

例如:如果有人卡住了,可以将柯里化重写如下。请参见jsFiddle演示

 Function.prototype.curry = function ( ) {
 var slice = Array.prototype.slice;
 var args = slice.apply(arguments);
 var that = this; 
 return function () {  
    return that.apply(null,args.concat (slice.apply(arguments)));
 }
};
var add = function(a, b)
{
    return a + b;
}
var add1 = add.curry(1);
document.writeln(add1(6)); // 7

0

尝试使用这个原型方法:

String.prototype.deentityify = function () { ... }

然后:

document.writeln('<">'.deentityify( ));

我们可以看到: <">


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接