Javascript 何时使用原型 [英] Javascript when to use prototypes

查看:31
本文介绍了Javascript 何时使用原型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想了解什么时候在 js 中使用原型方法是合适的.是否应该始终使用它们?或者是否存在不推荐使用它们和/或导致性能损失的情况?

I'd like to understand when it is appropriate to use prototype methods in js. Should they always be used? Or are there cases where using them is not preferred and/or incurs a performance penalty?

在本网站上搜索 js 中命名空间的常用方法时,似乎大多数使用非基于原型的实现:简单地使用对象或函数对象来封装命名空间.

In searching around this site on common methods for namespacing in js, it seems that most use a non-prototype based implementation: simply using an object or a function object to encapsulate a namespace.

来自基于类的语言,很难不尝试得出相似之处并认为原型就像类",而我提到的命名空间实现就像静态方法.

Coming from a class-based language, it's hard not to try and draw parallels and think that prototypes are like "classes" and the namespace implementations I mentioned are like static methods.

推荐答案

原型是一种优化.

很好地使用它们的一个很好的例子是 jQuery 库.每次使用 $('.someClass') 获取 jQuery 对象时,该对象都有数十个方法".库可以通过返回一个对象来实现:

A great example of using them well is the jQuery library. Every time you obtain a jQuery object by using $('.someClass'), that object has dozens of "methods". The library could achieve that by returning an object:

return {
   show: function() { ... },
   hide: function() { ... },
   css: function() { ... },
   animate: function() { ... },
   // etc...
};

但这意味着内存中的每个 jQuery 对象都会有几十个包含相同方法的命名槽,一遍又一遍.

But that would mean that every jQuery object in memory would have dozens of named slots containing the same methods, over and over.

相反,这些方法是在原型上定义的,所有 jQuery 对象都继承"该原型,以便以很少的运行时成本获得所有这些方法.

Instead, those methods are defined on a prototype and all jQuery objects "inherit" that prototype so as to gain all those methods at very little runtime cost.

jQuery 正确使用它的一个非常重要的部分是它对程序员是隐藏的.它被视为纯粹的优化,而不是您在使用库时必须担心的事情.

One vitally important part of how jQuery gets it right is that this is hidden from the programmer. It's treated purely an optimisation, not as something that you have to worry about when using the library.

JavaScript 的问题是裸构造函数要求调用者记住在它们前面加上 new 前缀,否则它们通常不起作用.这没有充分的理由.jQuery 通过将这些废话隐藏在普通函数 $ 后面而做到了正确,因此您不必关心对象是如何实现的.

The problem with JavaScript is that naked constructor functions require the caller to remember to prefix them with new or otherwise they typically don't work. There is no good reason for this. jQuery gets it right by hiding that nonsense behind an ordinary function, $, so you don't have to care how the objects are implemented.

为了方便地创建具有指定原型的对象,ECMAScript 5 包含一个标准函数Object.create.一个大大简化的版本看起来像这样:

So that you can conveniently create an object with a specified prototype, ECMAScript 5 includes a standard function Object.create. A greatly simplified version of it would look like this:

Object.create = function(prototype) {
    var Type = function () {};
    Type.prototype = prototype;
    return new Type();
};

它只是解决了编写构造函数然后用new调用它的痛苦.

It just takes care of the pain of writing a constructor function and then calling it with new.

你什么时候会避免原型?

一个有用的比较是与流行的 OO 语言,如 Java 和 C#.这些支持两种继承:

A useful comparison is with popular OO languages such as Java and C#. These support two kinds of inheritance:

  • 接口继承,您在其中实现一个interface,以便该类为接口的每个成员提供自己独特的实现.
  • 实现继承,您在其中扩展一个class,它提供了一些方法的默认实现.
  • interface inheritance, where you implement an interface such that the class provides its own unique implementation for every member of the interface.
  • implementation inheritance, where you extend a class that provides default implementations of some methods.

在 JavaScript 中,原型继承是一种实现继承.因此,在那些情况下(在 C# 或 Java 中)您将从基类派生以获得默认行为,然后您通过覆盖对其进行小的修改,然后在 JavaScript 中,原型继承是有意义的.

In JavaScript, prototypical inheritance is a kind of implementation inheritance. So in those situations where (in C# or Java) you would have derived from a base class to gain default behaviour, which you then make small modifications to via overrides, then in JavaScript, prototypical inheritance makes sense.

但是,如果您在使用 C# 或 Java 中的接口的情况下,那么您不需要 JavaScript 中的任何特定语言功能.不需要显式声明表示接口的东西,也不需要将对象标记为实现"该接口:

However, if you're in a situation where you would have used interfaces in C# or Java, then you don't need any particular language feature in JavaScript. There is no need to explicitly declare something that represents the interface, and no need to mark objects as "implementing" that interface:

var duck = {
    quack: function() { ... }
};

duck.quack(); // we're satisfied it's a duck!

换句话说,如果每个类型"的对象都有自己的方法"定义,那么从原型继承就没有价值.之后,这取决于您为每种类型分配了多少实例.但在许多模块化设计中,给定类型只有一个实例.

In other words, if each "type" of object has its own definitions of the "methods", then there is no value in inheriting from a prototype. After that, it depends on how many instances you allocate of each type. But in many modular designs, there is only one instance of a given type.

事实上,很多人都建议人们认为实现继承是邪恶的.也就是说,如果某个类型有一些常见的操作,那么如果它们不放入基类/超类中,而只是作为某个模块中的普通函数公开,您将对象传递给该模块,则可能会更清楚您希望他们对其进行操作.

And in fact, it has been suggested by many people that implementation inheritance is evil. That is, if there are some common operations for a type, then maybe it's clearer if they are not put into a base/super class, but are instead just exposed as ordinary functions in some module, to which you pass the object(s) you want them to operate on.

这篇关于Javascript 何时使用原型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆