Using JavaScript’s Prototype with MVC

本文从MVC视角出发,详细介绍了如何利用JavaScript操纵DOM,包括构造JavaScript对象、其属性和方法,以及如何将这些对象实例化以对应视图行为。文章通过实例展示了如何将视图视为对象,而非页面,以及如何在样式和脚本中实现这种概念。重点讨论了如何在JavaScript中遵循金科玉律来开发基于视图的代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

In this article, we will review the process of using JavaScript, from an MVC-based perspective, to manipulate the DOM. More specifically, we’ll engineer our JavaScript objects, their properties and methods, and their instantiations parallel to the intended behavior of our Views (what the user sees).


Consider Your Views As Objects, Not As Pages

At any point in the development of a web page, we are using a language that naturally promotes either class-based development or object-based development. In strongly-typed languages like Java and C#, we are usually writing our views in classes – giving them state, scope, and context. When we are working with languages like PHP or newer view engines, like Razor for ASP.NET, our views may simply be markup (HTML/CSS) mixed with templating. However, this does not mean we have to change our perception on how the view behaves as its own stateful entity.

Within Views, we are primarily working with HTML, which consists of nested elements; these elements have attributes which describe what their semantic purpose is or how they appear when rendered. These elements then have children or parent elements that inherit/provide cascading (through CSS) and block/inline behaviors. These elements can naturally be viewed from an OOP (Object-Oriented Programming) perspective. Consider, for example, the following markup:

1
2
3
4
5
6
div.container {
   border: 1px solid #333;
   padding: 5px;
   color: red;
}
1
2
3
4
<div class="container">
   <h2>About Our Company</h2>
</div>

Result :

Our header inherited a red border through CSS cascading

As you can see above, the header inherited its font color property from its parent container though the CSS behavior of cascading. This behavior is quite similar to the concept of inheritance in OOP. We can also see that the header is a child of the container, inheriting certain properties, based on the behavior of the element. When we see our elements from this perspective, we have a better definition of what we intend to do with our view elements and can encapsulate styles and functionality better.

Inside a view, we will have markup. However, this markup may have nested partial views like sidebars, a header, a footer, a right (or left) rail, and one or more content sections. All of these partial views should be viewed as their own entity, capable of having their own state, context, and scope.

“When you conceive your views and partial views as objects, it makes writing your client-side code much easier.”


Translating This Concept Into Your Styles and Scripts

Many developers tend to write JavaScript from a procedural or functional point of view, and often neglect to consider the natural tendencies offered in view-based development approaches and parallel instantiation (creating a new instance of the view as we create a new instance of a JavaScript object corresponding to that view) when working in MVC Frameworks. It’s often the case that I run into JavaScript files that are just one method after another. Though this behavior works, and is common, it is not very efficient for code maintenance, debugging, or extension of current or future code when you are working extensively with views.

To get away from this habit and begin writing better behavioral code, when you begin to lay out your View’s scripting and styles, follow these general rules:

Golden Rules of View-based JavaScript Development

  • Every view that is rendered from an action on a controller should have its own JavaScript object.
  • Every Partial View that is loaded inside a View should have its own JavaScript object.
  • Name your objects the same as your views (or partial views). This will make more sense for you and everyone else that touches your code.
  • Use Pascal case for all objects (i.e. About, Sidebar, etc.). Your views should already, so why not do the same for your JavaScript objects?
  • All constants of these objects should be stored in the constructor. This means if your view has properties that will be used in multiple methods, these methods can all access these properties.
  • All methods that will be called on a view (or partial view) should be bound to the prototype of the object that corresponds to that view.
  • All event bindings for the view (or partial view) should be contained within their own event binding’s method, which is placed on the prototype.

Consider the following diagram:

Our MVC Layout viewed with styles and scripts

I generally create view-specific scripts and styles and then grab what I need from the main stylesheets and script libraries I’ve created that would be used on many views. This also reduces the amount of code that is used.


Creating View-based Objects

In this article, we will be laying out the structure for the About Us page on an MVC-based site. To start, we will create the structure as shown above in the previous diagram. From there, we will create an About object, and begin adding methods to the prototype. First, consider the following visual layout:

Sample About Us Page Layout

This is a very logical and commonly used layout for a webpage. We can segment our page into seperate visual objects. For each of these views, we can create a logical object that will correspond to it. I generally omit the repetitive information in the filename or classname that is used by MVC to determine the URI from the route and instead stick with something that is easy to keep consistent.

For page views, I generally call my JavaScript objects by the name of the view. Here is an example of my AboutView Object:

1
2
3
4
5
6
7
8
// View Filename: AboutView.cs (.NET MVC 1.0), About.cshtml (.NET MVC 3.0), or AboutView.php (PHP)
 
var About = function(pageTitle) {
   this.pageTitle = pageTitle;
   // binding events as soon as the object is instantiated
   this.bindEvents();
};

In the above example, we created a JavaScript object in the function format, giving it the capacity to serve as an Object constructor for all methods called for the about view. By choosing this format, we can instantiate a new instance of this, just as we do with our view Server-Side (by saying new AboutView();). From here, we can assign properties and methods to this object. In order to assign methods to this object, we will need access to the object’s prototype.


JavaScript’s Prototype is your Friend

Developers are often thwarted by the elusiveness (and ambiguity) of JavaScript’s Object Prototype.

Developers are often thwarted by the elusiveness (and ambiguity) of JavaScript’s Object Prototype. For many, it can be confusing to use and understand and adds another dimension to coding. As JavaScript becomes more event-driven with HTML5, AJAX, and web 2.0 concepts, JavaScript tends to lean naturally to procedural development that is easy to develop but hard to maintain, scale, and replicate.

Think of the word Prototype as a misnomer for now. When I think Prototype, I think of a “rough draft” or a base for inheritance, but this isn’t exactly the case.

” In reality, the better perspective for Prototype would be the Object’s Pointer in memory.”

When we create an object, we then instantiate a new instance of it. When we do that, we create a place in memory that the object can be referenced (remember, Objects in JavaScript are reference types, not primitive types; creating another variable equal to that object and then changing its values will actually change the original object in the pointer). When we create an object, instantiate a new instance of it, and then modify its “Pointer,” or Prototype, we add fields and methods to that object in memory directly (obviously we want to add all of these things before instantiation).


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值