gpt4 book ai didi

javascript - 我不了解Crockford的JavaScript:前进的道路

转载 作者:行者123 更新时间:2023-12-02 05:10:34 25 4
gpt4 key购买 nike

在一次名为“前进之路”的演讲中,道格拉斯·克罗克福德(Douglass Crockford)表示他不再在JavaScript中使用"new",而是逐渐摆脱了“这个”。他说JavaScript的好功能不是原型(prototype)继承,而是无类继承。他提供了以下代码片段,这是他定义对象的方式:

function constructor(init) {
var that = other_constructor(init),
member,
method = function () {
// init, member, method
};
that.method = method;
return that;
}
他解释说:

I've got a function which will take some value to initialize it. I recommend that to be an object, (that way you can have a JSON text you can use to create new instances). You can call another constructor if you want to inherit it's stuff; in any case, you're going to create an object and put it in a variable called "that". You will create all of your member variables (things that are going to become properties of the object, of your method variables, things that are going to act on the object...) those methods will be functions which will close over the initialization value over all the member variables and all the method variables.

It could also use "this" and "that", but I recommend not. The reason for not doing that is, if it doesn't use "this" or "that", then you can take any of the functions out of the object and call them independantly and they still do exactly the same thing. So that increases the reliability of the language. Also means you can pass any of those things, use it as a call back without having to bind anything (It just becomes more reliable). Then any methods that need to be public or privilaged you simply attach them to the object and return the object. This is a really flexible pattern-- you can get multiple inheritance, you can get aspects, you can get factories-- lots of things you can do with this basic pattern.



为什么此代码段执行以下任务?
that.method = method
方法有什么目的?如何初始化?以这种方式声明对象的目的是什么?
他的演讲非常笼统,他只花了一分钟时间就讲授这部分内容,而没有详述他的推理或引用资源。任何人都可以阐明这种编程风格的动机吗?
链接到视频:
https://www.youtube.com/watch?v=3WgVHE5Augc
从37分钟左右开始

最佳答案

Why does this snippet make the following assignment?

that.method = method

what purpose does method serve? How is it initialized?


它被初始化为一个变量,并在后面多行:
method = function () { ... }
然后,您引用的那一行将变量的值(对该函数的引用)分配给 that所引用的对象的属性,因此可以将其用作对象的“方法”。因此,您可以这样做:
var x = constructor(42);
x.method(); // <== Here's where we use the function assigned to the property as a method
更多(在我的博客上): Mythical methods

What is the purpose of declaring objects in this way?


Crockford不喜欢JavaScript的构造函数,因此不使用它们。因此,他改为这样做。关于JavaScript的真正伟大之处之一就是它的灵活性。您可以将其用作几乎纯粹的功能性语言,也可以将其用作原型(prototype)语言,甚至可以将其用作基于类的语言,即使它不是基于类的,也可以使用,因为它的原型(prototype)特性为您提供了为此所需的一切(从ES2015 +开始;在ES2015之前,几乎只是一切)。而且,只要您认为合适,就可以混合使用这些方法。就这么灵活。
与Crockford不同,我喜欢构造函数和 new关键字。但是我也很喜欢在它们不是正确的工具时就不必使用它们,而通常它们并不是正确的工具。

在下面重新发表您的评论:

Would you by any chance be able to provide an example of Crockford's constructor function snippet in actual use? Is that.method used to initialize that.member, or am I totally off here?


没有 that.member。您显示的代码中的 member不是对象的属性,而只是一个变量。在对 method的调用中创建的 constructor函数可以访问该变量,因为它是对 constructor的调用上下文的封闭,但是只有有权访问返回对象的对象才能看到 member。因此, member真正是 constructor中创建的函数的专用。另外两篇文章可能在这里有用:我博客中的 Closures are not complicated解释了什么是“关闭”,以及克罗克福德的 Private Members in JavaScript,它描述了将私有(private)信息与他引用的示例中使用的对象相关联的方式。 (我在回答的最后提到了一种不同的方式来获取有关对象的私有(private)信息。)
您引用的示例正在执行的操作演示了两个基本上不相关的事情:
  • 创建增强(非派生)对象的方法
  • 一种具有与那些对象关联的真正私有(private)信息的方法

  • 他显示的模式不是执行这些操作的唯一方法,而是它所显示的。
    再举一个具体的例子:
    假设我们要创建“事物”对象。它们到底是什么并不重要,但是它们具有一个称为“名称”的属性(不必是私有(private)的)。 (它们可能也有方法,但是它们并不重要,因此为了简洁和清楚起见,我们将其省略。)因此,我们将从以下内容开始:
    // Very simple Crockford-style constructor
    function createThing(name) {
    return {name: name}; // Again, there'd probably be more to it, this is simple on purpose
    }

    // Usage
    var t = createThing("foo");
    console.log(t.name); // "foo"
    到现在为止还挺好。现在,我们还希望能够创建可以添加计数器的事物,以及一种“使用”事物和使用计数的方法,以返回新的使用计数。 (是的,这个 是一个人为的示例。)一个简单的版本,再次使用类似于Crockford的方法,可能看起来像这样:
    // Naive approach
    function createThingWithCounter(name) {
    var that = createThing(name);
    that.useCounter = 0;
    that.use = function() {
    // ...do something with `that`...

    // Return the new number of times we've "used" the thing
    return ++that.useCounter;
    };
    return that;
    }

    // Usage
    var t = createThingWithCounter("foo");
    console.log(t.name); // "foo"
    console.log(t.use()); // 1
    console.log(t.use()); // 2
    再次,到目前为止一切顺利。但是问题是, useCounter是对象的公共(public)属性。因此,我们可以从 createThingWithCounter代码之外对其进行处理:
    var t = createThingWithCounter("foo");
    console.log(t.name); // "foo"
    console.log(t.use()); // 1
    t.useCounter = 0;
    console.log(t.use()); // 1 -- uh oh!
    我们不希望 useCounter公开。现在,有多种方法可以将其设为私有(private),包括根本不使其私有(private)化,而是使用命名约定(通常以下划线开头,例如 _useCounter),意思是“别管它了!”,但是这种模式通过查看,我们可以利用 useCounter方法是对 use的调用上下文的封闭,从而使 createThingWithCounter真正私有(private)。这样,再加上一些重新布置源代码以更好地适应引用的模式,可以为我们提供以下功能:
    function createThingWithCounter(name) {
    var that = createThing(name),
    useCounter = 0,
    use = function() {
    // ...do something with `that`...

    // Return the new number of times we've "used" the thing
    return ++useCounter;
    };
    that.use = use;
    return that;
    }
    现在, useCounter根本不是对象的属性。它是真正的私有(private), createThingWithCounter之外的任何人都看不到或更改它:
    var t = createThingWithCounter("foo");
    console.log(t.name); // "foo"
    console.log(t.use()); // 1
    t.useCounter = 0; // <== Has absolutely no effect on the real counter
    console.log(t.use()); // 2
    这就是我们的具体示例(如果有人为)。它是如何映射到引用的模式的:
  • constructor = createThingWithCounter
  • otherConstructor = createThing
  • member = useCounter
  • method = use

  • 现在,我想强调的是,以上没有什么可以代替使用 new的普通构造函数来完成的。它看起来甚至没有什么不同:
    // Doing the same thing with normal constructor functions and `new`
    function Thing(name) {
    this.name = name;
    }

    // Usage
    var t = new Thing("foo");
    console.log(t.name); // "foo"

    // Augmented things
    function ThingWithCounter(name) {
    var useCounter = 0;

    Thing.call(this, name);
    this.use = function() {
    // ...do something with `this`...

    // Return the new number of times we've "used" the thing
    return ++useCounter;
    };
    }

    // Usage of augmented things
    var t = new ThingWithCounter("foo");
    console.log(t.name); // "foo"
    console.log(t.use()); // 1
    t.useCounter = 0; // <== Has absolutely no effect on the real counter
    console.log(t.use()); // 2
    它们只是达成相似目标的不同方式。
    还有另一种方法:派生而不是扩增。与扩充一样,导出可以采用Crockford样式或通过标准的构造函数完成。这就是语言的出色灵活性。 :-)
    关于私有(private)信息的最后说明:在以上两种样式中, useCounter都是真正的私有(private),但它不是对象的属性。它根本不在对象上。获得隐私的方式有很多成本:首先,我们必须为每个实例创建一个 use函数。这些功能不会在实例之间共享,例如可以附加到原型(prototype)的功能(以及其他各种方式)可以共享。 2014年的成本相当低廉,现代引擎在优化成本方面非常聪明; 15年前,它的成本要高得多。
    另一个代价是 use函数无法在其他地方重用,这使其与JavaScript中的绝大多数函数不符。如果查看 the spec,则几乎在每个预定义的JavaScript方法上都会看到此语言:

    NOTE: The xyz function is intentionally generic; it does not require that its this value be a Whatsit object. Therefore it can be transferred to other kinds of objects for use as a method.


    因此,如果我有一些很像数组但不是数组的东西(例如JavaScript arguments对象),则可以将 Array.prototype中的方法放在上面,并且只要我的对象足够像数组,它们就可以正常工作:
    var arrayLikeObject = {
    length: 2,
    0: "one",
    1: "two",
    indexOf: Array.prototype.indexOf
    };
    console.log(arrayLikeObject.indexOf("two")); // 1
    我们的 use方法不能以这种方式重复使用。它被锁定在与之相关的“带有计数器的事物”实例上。如果我们确实尝试过以这种方式使用它,我们最终将在我们要放入的对象与我们原来使用的带有计数器的对象之间发生奇怪的串扰。这种奇怪的串扰是 很棒的很好的方式,可以在任何规模的项目中都有真正令人讨厌,费时,笨拙的错误。
    JavaScript标准的下一个版本ECMAScript6为我们提供了一种拥有私有(private)属性的方法。即,私有(private)对象的实际属性(或随着信息以现代语言/环境进入私有(private)状态)。因为属性实际上是对象的属性,所以我们不必依赖 use函数作为闭包,我们可以在原型(prototype)对象上定义它和/或在其他对象上重用它-也就是说,这两个成本都没有以上适用。
    甚至更好的是,他们现在用来添加该功能的非常巧妙的模式可以立即使用,以获得约90%的 yield 。因此,如果这是您感兴趣的主题,那么为您准备的最后一篇博客文章 Private properties in ES6 -- and ES3, and ES5

    关于javascript - 我不了解Crockford的JavaScript:前进的道路,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24248426/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com