简体   繁体   English

关于JavaScript如何工作的一些问题

[英]A few questions about how JavaScript works

I have been looking deeply into JavaScript lately to fully understand the language and have a few nagging questions that I can not seem to find answers to (Specifically dealing with Object Oriented programming). 我最近一直在深入研究JavaScript以完全理解语言,并且有一些唠叨的问题,我似乎无法找到答案(特别是处理面向对象的编程)。

Assuming the following code: 假设以下代码:

function TestObject()
{
    this.fA = function()
    {
        // do stuff
    }

    this.fB = testB;

    function testB()
    {
        // do stuff
    }
}

TestObject.prototype = {
    fC : function 
    {
        // do stuff
    }
}

What is the difference between functions fA and fB ? 函数fAfB什么区别? Do they behave exactly the same in scope and potential ability? 他们的范围和潜在能力是否完全相同? Is it just convention or is one way technically better or proper? 它只是惯例还是技术上更好或更合适的一种方式?

If there is only ever going to be one instance of an object at any given time, would adding a function to the prototype such as fC even be worthwhile? 如果在任何给定时间只有一个对象的实例,那么将原型中的函数添加到fC是否值得? Is there any benefit to doing so? 这样做有什么好处吗? Is the prototype only really useful when dealing with many instances of an object or inheritance? 原型只在处理对象或继承的许多实例时才真正有用吗?

And what is technically the "proper" way to add methods to the prototype the way I have above or calling TestObject.prototype.functionName = function(){} every time? 从技术上来说,每次都按照我上面的方式或者调用TestObject.prototype.functionName = function(){}方法向原型添加方法的“正确”方法是什么?

I am looking to keep my JavaScript code as clean and readable as possible but am also very interested in what the proper conventions for Objects are in the language. 我希望尽可能保持我的JavaScript代码干净和可读,但我也非常感兴趣的是对象的正确约定在语言中。 I come from a Java and PHP background and am trying to not make any assumptions about how JavaScript works since I know it is very different being prototype based. 我来自Java和PHP背景,我试图不对JavaScript如何工作做任何假设,因为我知道它是基于原型的非常不同。

What is the difference between functions fA and fB 函数fA和fB之间有什么区别

In practice, nothing. 在实践中,没有。 The primary difference between a function expression (fA) and a function declaration (fB) is when the function is created (declared functions are available before any code is executed, whereas a function expression isn't available until the expression is actually executed). 函数表达式(fA)和函数声明(fB)之间的主要区别在于创建函数时(声明的函数在执行任何代码之前可用,而函数表达式在表达式实际执行之前不可用)。 There are also various quirks associated with function expressions that you may stumble across. 您可能会偶然发现与函数表达式相关的各种怪癖。

In the example, I'd use a function expression, simply because declaring a function expression, then assigning the result seems a bit abstracted. 在这个例子中,我使用函数表达式,只是因为声明一个函数表达式,然后分配结果似乎有点抽象。 But there is nothing "right" or "wrong" about either approach. 但这两种方法都没有“正确”或“错误”。

If there is only ever going to be one instance of an object at any given time, would adding a function to the prototype such as fC even be worthwhile? 如果在任何给定时间只有一个对象的实例,那么将原型中的函数添加到fC中是否值得?

No. Just about everyone who goes does inheritance finds that plain objects are often simpler and therefore "better". 没有。几乎所有进行继承的人都发现普通对象通常更简单,因此“更好”。 Prototype inheritance is very handy for patching built–in objects though (eg adding Array.prototype.each where absent). 原型继承对于修补内置对象非常方便(例如,在缺少的情况下添加Array.prototype.each)。

And what is technically the "proper" way to add methods to the prototype… 从技术上讲,在原型中添加方法的“正确”方法是什么......

There isn't one. 没有一个。 Replacing the default prototype with some other object seems like a bit of a waste, but assigning an object created by a literal is perhaps tidier and easier to read that sequential assignments. 用一些其他对象替换默认原型似乎有点浪费,但是分配由文字创建的对象可能更整洁,更容易阅读顺序分配。 For one or two assignments, I'd use: 对于一个或两个作业,我会使用:

 Constructor.prototype.method = function(){…}

but for lots of methods I'd use an object literal. 但是对于很多方法我会使用对象文字。 Some even use a classic extend function and do: 有些甚至使用经典的扩展​​功能,并做:

myLib.extend(Constructor.prototype, {
    method: function(){…}
});

Which is good for adding methods if some have already been defined. 如果已经定义了一些方法,那么添加方法是有益的。

Have a look at some libraries and decide what you like, some mix and match. 看看一些图书馆并决定你喜欢什么,一些混合搭配。 Do whatever suits a particular circumstance, often it's simply a matter of getting enough code to all look the same, then it will look neat whatever pattern you've chosen. 做任何适合特定情况的事情,通常只需要获得足够的代码就可以看到相同的内容,然后无论您选择何种模式,它都会看起来很整洁。

fA and fB are effectively the same and it is just a matter of convention. fAfB实际上是相同的,这只是一个惯例问题。

If there is only one instance of a object I wouldn't even use a constructor function, but rather just a object literal, such as: 如果只有一个对象的实例,我甚至不会使用构造函数,而只是一个对象文字,例如:

var o = {
   fA: function () { ... },
   fB: function () { ... },
   fC: function () { ... }
};

As for adding it to an instance or a prototype, the instance is slightly more efficient than adding it to the prototype if you only have one instance but, as I said, use a literal instead. 至于将它添加到实例或原型中,如果你只有一个实例,那么实例比将它添加到原型更有效,但正如我所说,使用文字代替。

I avoid declaring functions in the constructor because each invocation of the constructor will create new object representing each function. 我避免在构造函数中声明函数,因为构造函数的每次调用都将创建表示每个函数的新对象。 These objects are not very large they tend to add up if many objects are created. 这些对象不是很大,如果创建了很多对象,它们往往会相加。 If the functions can be moved to the prototype, it is much more efficient to do so. 如果可以将函数移动到原型,那么这样做会更有效。

As for adding to the prototype, I favor the 至于添加到原型,我赞成

TestObject.prototype.functionName = function () { };

style but it is a matter of preference. 风格,但这是一个偏好的问题。 I like the above because it looks the same whether you are extending the prototype or creating the intial prototype. 我喜欢上述内容,因为无论是扩展原型还是创建初始原型,它看起来都是一样的。

I answer for first part: there is no differences, when you declare function not as variable then declaration of it rises in the block, so 我回答第一部分:没有区别,当你声明函数不是变量时,它的声明在块中上升,所以

...
func();
...    
function func () { ... }

is equal to 等于

var func = function () { ... };
...
func();
...

So your code 所以你的代码

function TestObject () {
  this.fA = function() { // do stuff };   
  this.fB = testB;    
  function testB() { // do stuff }
}

is equal to 等于

function TestObject () {
    var testB = function () { // do stuff };    
    this.fA = function () { // do stuff };
    this.fB = testB;
}

Also are there any definitive JavaScript style guides or documentation about how JavaScript operates at a low level? 还有关于JavaScript如何在低级别运行的任何明确的JavaScript样式指南或文档吗?

Damn no javascript programmer should ever miss "Professional JavaScript for Web Developers" . 该死的javascript程序员应该错过“面向Web开发人员的专业JavaScript” This is a fantastic book, that goes into the deep. 这本书很精彩,深入探讨。 It explains objects, class emulation, functions, scopes and much much more. 它解释了对象,类仿真,函数,范围等等。 It is also a JS reference. 它也是一个JS参考。

And what is technically the "proper" way to add methods to the prototype the way I have above or calling TestObject.prototype.functionName = function(){} every time? 从技术上来说,每次都按照我上面的方式或者调用TestObject.prototype.functionName = function(){}的方式向原型添加方法的“正确”方法是什么?

As for the way to define classes, I would recommend to have a look at various JS MVC frameworks (like Spine.js, which is lightweight ). 至于定义类的方法,我建议看看各种JS MVC框架(如Spine.js,它是轻量级的)。 You do not need the whole of them, just their class emulation libraries . 您不需要整个它们,只需要它们的类仿真库 The main reason for this, is that JS does not have the concept of classes, rather it is purely consisted of objects and prototypes. 这样做的主要原因是JS没有类的概念,而是纯粹由对象和原型组成。 On the other hand classes can be perfectly emulated (please do not take the word emulated as it is something missing). 另一方面,可以完美地模拟类(请不要模仿,因为它是缺少的东西)。 As this needs some discipline from the programmer, it is better to have a class emulation library to do the job and make you code cleaner. 由于这需要程序员的一些规则,最好有一个类仿真库来完成这项工作并使代码更清晰。

The standard methods that a programmer should expect of a class emulation library are: 程序员应该期望类仿真库的标准方法是:

// define a new Class
var AClass = Class.create({
   // Object members (aka prototype), 
   // usually an initialize() method is called if it is defined 
   // as the "constructor" function when a class object is created
}, {
   // Static members
}); 

// create a child class that inherits methods and attributes from parent
var ChildClass = AClass.extend({
   // Child object members
},{
   // Child static members
}); 

AClass.include({
   // Object amendments (aka mixin), methods and attributes 
   //   to be injected to the class object
},{
  // Statics amendments, methods and attributes to be 
  //  injected as class static members
});


// check object type
var aObj = new AClass();
aObj instanceof AClass; //  true
aObj instanceof ChildClass; //  false


var cObj = new ChildClass();
cObj instanceof AClass; //  true
cObj instanceof ChildClass; //  true

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM