T4 Tutorial: Debugging Code Generation Files

src: http://www.olegsych.com/2008/09/t4-tutorial-debugging-code-generation-files/

Posted by Oleg SychSeptember 13, 2008

This post is a part of the series that introduces code generation with Text Templates (also known as T4Templates) in Visual Studio using C# and Visual Basic; explains how to create reusable templates and combine them in complex code generators. In order to follow examples in this article, you need to have Visual Studio 2008 Standard Edition or higher, SQL Server 2005 or later, T4 Toolbox and T4 Editorinstalled on your computer.

Overview

As you remember from the previous article in this series, Runtime Errors are caused by exceptions thrown by code in the GeneratedTextTransformation class, which is compiled and executed by the code generation Engine.

Compilation and Runtime Errors

Although the Engine reports detailed stack dump for every exception thrown, troubleshooting non-trivial runtime errors may require using a debugger to step through the template code as it executes. Because template code is running inside of Visual Studio process itself, a second instance of Visual Studio is required to serve as a debugger for the first instance, which is running the template code.

Current support for debugging of code generation templates in Visual Studio is somewhat limited. It requires you to either use a manual breakpoint in the template code to trigger the just-in-time debugger or starting a debugging instance of Visual Studio in advance and attaching it to the instance that’s running the template.

Setup

Use Visual Studio to open CrudStoredProcedures.tt created in the first article of this series (you can download the source code using links at the end of this article). As you remember, it’s a code generation file that produces a DELETE stored procedure using table schema information retrieved from SQL server using SMO.

  • Simulate a runtime error by assigning null or Nothing to the server variable. This should trigger a run-time exception in the call to Database constructor.
  • Save the template file or select Run Custom Tool item from context menu in Solution Explorer to trigger template transformation.

Troubleshooting Runtime Errors

C#

Introducing ArgumentNullException in C# code

Visual Basic

Introducing ArgumentNullException in Visual Basic code

Runtime Error, Error List

    Just-In-Time Debugging

The quickest way to start debugging is by placing a breakpoint in the code of the template and triggering the just-in-time debugger. Note, if you are using Windows Vista or 2008 Server, this technique can hang Visual Studio. Please read the Just In Time Debugging on Windows Vista and 2008 Server section below first.

  • Make sure that debug parameter of the template directive is set to True.
  • Modify the template to call Debugger.Break method in the beginning of the code block.
C#

Setting just-in-time breakpoint in C# code

Visual Basic

Setting just-in-time breakpoint in Visual Basic code

  • Save the template file or select Run Custom Tool item from context menu in Solution Explorer to trigger template transformation.

Just-in-time debugging prompt

Debugger.Break method attempts to launch the Just-In-Time Debugger configured on your system.You should see a Visual Studio Just-In-Time Debugger dialog (shown above).

  • In Visual Studio Just-In-Time Debugger dialog, select New instance of Visual Studio 2008 in the list and click Yes.
C#

Stepping from just-in-time breakpoint in C# code

Visual Basic

Stepping from just-in-time breakpoint in Visual Basic code

This will launch a new instance of Visual Studio and attach it as a debugger to the first instance which is running your template. You should see the source code of your template automatically loaded in debugger and a green line pointing where the execution point currently is.

While in debugger, you can use all standard features, like stepping through code, and windows, like Watch, Call Stack, Immediate, etc.

  • Select Exceptions item from Debug menu in Visual Studio; turn on the option to break when exception is thrown and click OK.

Turning on Break-On-Exception option

  • Select Continue item from Debug menu in Visual Studio.

Exception details dialog

The template will continue to run until it encounters the exception. At that point, the Visual Studio debugger will pause it and display the dialog shown above. You can inspect the exception object by clicking View Detail link.

  • Select Continue item from Debug menu.
  • Close the debugging instance of Visual Studio.
  • Back in the original instance of Visual Studio, remove the call to Debugger.Break method from the template code.

Just-In-Time Debugging on Windows Vista and 2008 Server

By default on Windows Vista, the just-in-time debugger is configured to display a user-friendly dialog shown below. Although you can click the Debug the program button and start the debugger successfully, your original Visual Studio instance will hang in the end of the debugging session.

User-defined breakpoint dialog on Windows Vista

In order to avoid having to constantly kill the Visual Studio process after debugging, you will want to change Just-In-Time debugger configuration to work the same way it does on Windows XP and Windows Server 2003. This configuration is stored in registry as DbgJITDebugLaunchSetting value in HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework key. It’s default value on Windows Vista is 0×10. Change it to 0×2, which is the default value on Windows XP. After making this change, you should no longer see the User-Defined Breakpoint dialog and will be able to continue using Visual Studio after debugging.

Attaching Debugger Manually

Just-in-time debugging, described above, is the fastest and most precise way to set a breakpoint in template code and hit it in the debugger. However, it may not be appropriate if the code generation file you want to debug is read-only (such as when it is stored in source control repository or received from a third-party). In this situation, you can attach the debugger manually, which takes longer but doesn’t require you to modify the template code.

  • Start a second instance of Visual Studio and open the code generation file you need to debug –CrudStoredProcedures.tt in this example.
  • Select Attach to Process from the Debug menu in Visual Studio.

Attach to Process dialog

  • In the list of Available Processes, select devenv.exe and click the Attach button. This will attach the current instance of Visual Studio as a debugger for the first instance of Visual Studio running the template. Let’s call the first instance as simply Visual Studio and the second instance as Debugger.
  • Back in text editor of the Debugger, where you have the CrudStoredProcedures.tt file open, click on the left side of line 8 to sent a breakpoint.
C#

Setting breakpoint in C# code using attached debugger

Visual Basic

Setting breakpoint in Visual Basic code using attached debugger

Normally, the red breakpoint icon would appear next to the line you clicked. However, due to limitations in the current support for template debugging, Visual Studio displays the breakpoint icon in line 2 instead.

  • In the original Visual Studio instance, trigger template transformation by either saving the template or selecting Run Custom Tool from the context menu in Solution Explorer. This will trigger the breakpoint and you will see something like this in the Debugger.
C#

Stepping through C# code in attached debugger

Visual Basic

Stepping through Visual Basic code in attached debugger

You can use all debugging features as you would expect in regular .NET code with the exception of breakpoints. I have not found a way to place breakpoints in the template code precisely using the debugger and have to resort to manual breakpoints using Debugger.Break as described above.

  • Select Continue item from Debug menu.
  • Close the debugging instance of Visual Studio.
  • Back in the original instance of Visual Studio, restore the original initialization code for server variable.

Conclusion

Debugging is the most powerful technique in troubleshooting runtime errors that occur during code generation. Although current support for debugging of template code in Visual Studio is somewhat limited, you can debug templates effectively by either triggering Just-In-Time debugger with Debugger.Break from template code or by attaching a separate instance of Visual Studio as a debugger in advance.

In the next article of this series, we will talk about creating reusable code generation templates.

T4 (Text Template Transformation Toolkit) Code Generation – Best Kept Visual Studio Secret

src:http://www.hanselman.com/blog/T4TextTemplateTransformationToolkitCodeGenerationBestKeptVisualStudioSecret.aspx

 

Rob beat me to it. Blogging about T4 (the Text Template Transformation Toolkit) had been on my list literally for a year. He and I were singing its praises last night. Hopefully I can add something small to the conversation.

What’s the story? Well, T4 is a code generator built right into Visual Studio. To be clear, you HAVE THIS NOW on your system…go play. Now’s the time to introduce code generation to your company. If you’re doing something twice or more, manually, in your company, generate it.

However, it’s not deep-deep built in, because there’s no item templates in File | New Item and there’s no intellisense or syntax highlighting.

You don’t need this, but if you want really get the most out of T4, first, head over to Clarius Consulting and get their “T4 Editor Community Edition.” That’ll get you some basic coloring. They have a pay version that gets you more if you want.

Now, go into Visual Studio and make a Console App (or any app) and add a Text File, but name it something with a .tt extension. You’ll get a warning since it’s a generator, that someone could generate evil. Click OK if you are cool with potential evil. ;)

Security Warning

imageNow, look in Solution Explorer at the .tt file. If you’re using C#, you’ll have a sub .cs file, or if you’re using VB, a sub .vb file. That’s the file that will hold the result of the generation. This is the same visual metaphor used to the express the template/generated file relationship with .designer files you’ve seen elsewhere in Visual Studio.

If you look in the Properties for the .tt file, you’ll see it’s using a CustomTool listed as the “TextTemplatingFileGenerator.” This custom tool extensibility point is how things like XSD and WSDL code generators hook in to generate their artifacts.

T4 can generate any kind of text file, not just code. Whatever you like. You can use it in your projects, as above, or you can call T4 from the command-line.

Aside from Kzu and the folks at ClariusRob notes that Oleg Sych has a great collection of T4 resources. He’s got some great Tutorials:

Here’s some of the links from Oleg’s blog.

Oleg also has a CodePlex project called T4 Toolbox that is a library of T4 templates that get added to File | New Item.

Also, check out Damien Guard’s T4 templates that are a wholesale replacement of code that LINQ to SQL generates. Here’s an example, where I use Damien’s T4 templates against the sample Chinook Database.

image

Notice that I’ve named the .tt file the same as the .dbml, so Damian’s code can find it. I also continue to let original LINQ to SQL generate it’s .designer.cs file, but make that file’s Build Action “None” so it’s not ever compiled. That effectively puts Damian’s code in charge.

Here’s a screenshot showing a bit of Damian’s T4 template using the syntax highlighting from the Clairus T4 Visual Studio free download. If I’d pay them, I’d get intellisense and syntax highlighting inside the code blocks also. It looks like a lot like ASP.NET Web Forms, or Velocity, or any templating language really. The code blocks are where your logic is and outside the codeblocks is the template for whatever you want to generate. Notice how Damien gets input and sets output. You have full control, you can read files off the file system, from with your project, etc. He sets the output extension also. I like to use .g.cs or .g.vb, myself. In this example his generated file is Chinook.generated.cs.

I particularly like Damien’s example because he’s swapping out parts of LINQ to SQL that he didn’t like (the generated code) while keeping the part he did (the general mode, the designer, the dbml file.) If you don’t like something, fix it.

Plus, it all works in Visual Studio without installing anything.

image

If you’re doing Code Gen, or thinking about it, check out T4 as it’s a great place to start. Also, search my blog for “Code Generation” as I was livign and breathing it with CodeSmith for the many years I worked atCorillian. Have fun!

C#调用C++Dll封装时遇到的一系列问题

最近帮底层开发的同时用C#重新封装一下dll,也就是用C#类来封装C++Dll里的方法,以供用户使用。

之前也用到过类似的应用,大多数问题都出在类型转换上,但是这次的应用层出不穷,所以在这里总结一下,以供自己以后查阅,也希望对大家能够有所帮助。

首先,重复一下一些基本使用方法。具体的那些方式在这里就不重复讲了,网上很多的。比如http://blog.csdn.net/sunboyljp/archive/2009/12/31/5110639.aspx

c++ 头文件中的定义:

NPD_API int   NP_Init();

C#中定义函数

[DllImport(“npd_api.dll”)]

public static extern int NP_Init();

 

基本类型转换见下表(我用到过的):

BSTR——StringBuilder

LPCTSTR ——StringBuilder

LPCWSTR ——IntPtr

handle ——IntPtr

hwnd ——IntPtr

char *  ——string

int * ——ref int

int & ——ref int

void * ——IntPtrs

unsigned char * ——ref byte

BOOL ——bool

DWORD ——uint或int(我用的是uint,没出过什么问题)

 

我的问题来了,长期的经验教训我知道了:

1、指针做参数时在C#中一定要使用ref 或out关键字,尤其是结构体指针,要不会报内存读取错误,即使不报错数据也是不太对的。呵呵

SIPCLIENT_API void WINAPI SCCleanup(SipClient * psip);

[DllImport(“sipclient.dll”)]
public static extern void SCCleanup(ref SipClient psip);

其中SipClient是一个结构体。

 

2、重写结构体的时候,之前有指明类型长度或数组长度的地方,也要进行相应的标注,要不也会导致内存错误。

复制代码
 typedef struct {

char sDVRIP[16]; /* DVR IP地址 */

char sDVRIPMask[16]; /* DVR IP地址掩码 */

DWORD dwNetInterface; /* 10M/100M自适应,索引 */

WORD wDVRPort; /* 端口号 */

BYTE byMACAddr[MACADDR_LEN]; /* 服务器的物理地址 */

}NET_POSA_ETHERNET;

public struct NET_POSA_ETHERNET
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
public string sDVRIP; //DVR IP地址
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
public string sDVRIPMask; // DVR IP地址掩码
public uint dwNetInterface; //网络接口 1-10MBase-T 2-10MBase-T全双工 3-100MBase-TX 4-100M全双工 5-10M/100M自适应
public uint wDVRPort; //端口号
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
public byte[] byMACAddr; //[MACADDR_LEN]; //PPPoE用户名//服务器的物理地址
}

复制代码

 

3、遇到这样一个问题,折腾了大半天时间——http://space.cnblogs.com/q/16616/

最后是在C++那边做了修改解决的,通过制定模块定义 (.def) 文件,统一制定导出函数对应的名称。返回值为结构体指针的函数用IntPtr也能使用了。

复制代码
SIPCLIENT_API SipClient* SCInit(const char * reaml,
   const char * from_ip, int from_port,
   const char * to_ip, int to_port, const char * server_id,
   const char * user_id, const char * user_name, void * user_obj_param);

[DllImport(“sipclient.dll”)]
public static extern IntPtr SCInit(string reaml, string from_ip, int from_port,
string to_ip, int to_port, string server_id,
string user_id, string user_name, IntPtr user_obj_param);

复制代码

 

4、后来还遇到个回调函数导致的崩溃问题,又耽误了大半天时间,下班了还耽搁了会终于找的解决发办法了。

刚开始同事分析出了崩溃的原因,都是回收方式惹的祸,可参见http://www.hudong.com/wiki/WINAPI,尝试使用__stdcall,但是还是没有解决问题

后来实践证明,程序是很严谨的,半点差错都不能出才不会导致错误,思路还是__stdcall,只不过少改了东西,有两个地方需要改,才能保证不出错。

参考http://hi.baidu.com/tease/blog/item/1fe7213802780f22b9998f5a.html

关键就是这两句话

typedef void (_stdcall *CiCiCallBack) (bool started, void* client,char *message);
将导出函数修改为:
extern “C” _declspec(dllexport) bool _stdcall Test(char* fileName, CiCiCallBack callback)

一开始的时候就只修改了定义那,却忘记了导出时的修改,差点就放弃了这条解决思路了,不过还好,所谓坚持就是胜利!
5、后来封装好拿到用户那里用,却总是提示说找不到C++那些dll.

网上一查,初步定位是开发环境引起的,跟环境部署有关系。我们的开发环境是vs2008,而客户使用的vs2010,通过几次尝试,问题终于了。

首先考虑是缺少某些C++必备的运行库,存在相互依赖关系,所以导致找不到dll。用查看Dependency Walker查看才发现真的是客户机子上少了一些东西。

但是此路不通,将缺少的那些东西拷贝到可执行程序目录下,问题依旧没有解决。但是依旧坚持这条路~

尝试安装vcredist_x86.exe,以排除是否还是缺少了某些运行库的可能,问题依然存在。

后来我想起来之前搜索问题的时候,看到好像跟dll的Releas\Debug版本还有关系,所有又尝试提议让同事将他们的c++dll改为Release版的。

因为项目是多个人一起做了,编译Release版还花了不少时间,不过好歹问题终于解决了!

总结:直接安装vcredist_x86.exe,所有dll必须使用Release版的。如果使用Debug版的就必须保证可执行程序目录下的dll是完整的,缺一不可!

网上详细的讲解也很多,感觉这个总结的很好http://hi.baidu.com/fairysky/blog/item/e7a8366dbaa735f3431694c8.html

 

做程序就怕出现问题,出现问题就怕不知道原因,知道原因了就好找解决的办法啦!

ECMASCRIPT5新特性

Function 1: Object.create

这是一个很重要的改动,现在我们终于可以得到一个原型链干净的对象了。以前要创建一个类

 

Js代码
  1. function Cat(name) {
  2. this.name = name;
  3. this.paws = 4;
  4. this.hungry = false;
  5. this.eaten = [];
  6. }
  7. Cat.prototype = {
  8. constructor : Cat,
  9. play : function () { this.hungry = true; return ‘playing!’; },
  10. feed : function (food) { this.eaten.push(food); this.hungry = false; },
  11. speak : function () { return ‘Meow’; }
  12. };

必须要分两步走,但是现在可以不必了

 

Js代码
  1. var Dog = {
  2. name : ‘dog’,
  3. paws : 4,
  4. hungry : false,
  5. eaten : null,
  6. play : function () { this.hungry = true; return ‘playing!’; },
  7. speak : function () { return ‘Woof!’; }
  8. };
  9. var dog = Object.create(Dog);

Object.create他还有第2个参数,是一个properties descriptor object ,关于这方面的详细解释,请看第2点。

 

另外:如果浏览器不支持Object.create,可以用这种方法代替

Js代码
  1. if (typeof Object.create !== ‘function’) {
  2. Object.create = function (o) {
  3. function F() {}
  4. F.prototype = o;
  5. return new F();
  6. };
  7. }

Browser Support

 

○ Firefox 4

○ Internet Explorer 9

○ Safari 5

○ Chrome 5+

Function 2: Object.defineProperty

 

如果你想为一个对象定义属性,那么就必须my_dog.age = 2; 用这种方法。但是在ECMAScript5中,提供了更好的包装方法Object.defineProperty

Parameters:

1.对象引用

2.属性名

3.修饰对象

修饰对象中的定义如下:

 value: use this to set the value of a property. Defaults to undefined.

 writable: use this boolean to define whether this is a read-only variable. If it’s writable, it’s true. Defaults to false.

 configurable: use this boolean to define whether the type (value vs. method) of this property can be changed, or whether the property can be deleted. If it’s configurable, it’s true. Defaults to false.

 enumerable: use this boolean to define whether this property is included when the properties of the object are enumerated (a for-in loop or the keys method). Defaults to false.

 get: use this to define a custom getter method. Defaults to undefined.

 set: use this to define a custom setter method. Defaults to undefined.

Sample:

Js代码
  1. var Dog = {
  2. name : ‘dog’,
  3. paws : 4
  4. };
  5. var dog = Object.create(Dog);
  6. Object.defineProperty(dog, ‘age’, {
  7. set : function (age) { this.humanYears = age * 7; },
  8. get : function () { return this.humanYears / 7; },
  9. enumerable : true
  10. });
  11. dog.age = 2;
  12. dog.humanYears; // 14

以上代码让age和humanYears保存了同步,如果你不想对外界暴露humanYears,可以这样使用闭包:

Js代码
  1. Object.defineProperty(dog, ‘age’, (function () {
  2. var humanYears;
  3. return {
  4. set : function (age) { humanYears = age * 7; },
  5. get : function () { return humanYears / 7; },
  6. enumerable : true
  7. };
  8. }()));

当然,也可以用在Object.create方法上面

Js代码
  1. var yourDog = Object.create(Dog, {
  2. age : {
  3. get : function () { /* . . . */ },
  4. set : function () { /* . . . */ },
  5. enumerable: true
  6. },
  7. gender : {
  8. value : ‘female’
  9. }
  10. });

Browser Support

 

○ Firefox 4

○ Internet Explorer 9

○ Safari 5

○ Chrome 5+

Function 3: Object.defineProperties

当然,如果你想像Object.create方法那样一口气给对象加入很多属性的话,你可以用Object.defineProperties方法

 

Js代码
  1. Object.defineProperties(dog, {
  2. age : {
  3. get : function () { /* . . . */ },
  4. set : function () { /* . . . */ },
  5. enumerable: true
  6. },
  7. gender : {
  8. value : ‘female’
  9. }
  10. });

注意区别 Object.create和Object.defineProperties第一个参数的不同,Object.create是prototype,而Object.defineProperties是对象

 

Browser Support

○ Firefox 4

○ Internet Explorer 9

○ Safari 5

○ Chrome 5+

Function 4: Object.getOwnPropertyDescriptor

 

用途:得到一个属性的定义

 

 

Js代码
  1. var person = { name : ‘Joe’ };
  2. Object.getOwnPropertyDescriptor(person, ‘name’); // { configurable : true,enumerable : true, value : ‘Joe&’, writable : true }

但是这个函数只能适用于函数自身的对象,并不能取得原型链上的属性

Browser Support

○ Firefox 4

○ Internet Explorer 9

○ Safari 5

○ Chrome 5+

 

Function 5: Object.keys

用途:取得所有的属性名

 

 

Js代码
  1. var horse = { name : ‘Ed’, age : 4, job : ‘jumping’, owner : ‘Jim’ };
  2. var horseKeys = Object.keys(horse); // [‘name’, ‘age’, ‘job’, ‘owner’];

 

 

Browser Support

○ Firefox 4

○ Internet Explorer 9

○ Safari 5

○ Chrome 5+

 

 

Function 6: Object.getOwnPropertyNames

此函数功能基本和第5点相同,但是她可以取得所有的属性名,即使那个属性是不可枚取的(属性的enumerable =false,详细请参照第2点)

Browser Support

○ Firefox 4

○ Internet Explorer 9

○ Safari 5

○ Chrome 5+

 

Function 7: Object.preventExtensions / Object.isExtensible

这个函数能把一个对象的属性锁住,让他不能扩展。

 

 

Js代码
  1. var product = { name : ‘Foobar’, rating : 3.5 };
  2. Object.isExtensible(product); // true
  3. Object.preventExtentions(product);
  4. Object.isExtensible(product); // false
  5. product.price = ‘$10.00’; // doesn’t work
  6. product.price; // undefined

但是仅仅只是不能增加属性,他的值仍然是可以改的,而且这个属性也能够被delete

Browser Support

○ Firefox 4

○ Internet Explorer 9

○ Chrome 6+

 

Function 8: Object.seal / Object.isSealed

 

Seal一个对象意味着你无法增加删除属性,也无法把已经定义好的属性值指向一个accessor (a method or

function),反过来也是一样

 

 

Js代码
  1. var pet = { name : ‘Browser’, type : ‘dog’ };
  2. Object.seal(pet);
  3. pet.name = ‘Oreo’;
  4. pet.age = 2; // doesn’t work
  5. pet.type = function () { /**/ }; // doesn’t work
  6. delete pet.name; // doesn’t work

Browser Support

○ Firefox 4

○ Internet Explorer 9

○ Chrome 6+

 

Function 9: Object.freeze / Object.isFrozen

freeze一个对象,意味着你不能通过任何手段修改对象内容,他变成了完全只读的

 

Js代码
  1. var obj = { greeting : ‘Hi!’ };
  2. Object.freeze(obj);
  3. Object.isFrozen(obj); // true

 

 

Browser Support

○ Firefox 4

○ Internet Explorer 9

○ Chrome 6+

 

Function 10: Array.isArray

很显然,这是一个判断是否是数组的函数

 

Js代码
  1. var names = [‘Collis’, ‘Cyan’];
  2. Array.isArray(names); // true

Browser Support

○ Firefox 4

○ Internet Explorer 9

○ Safari 5

○ Chrome 5+

○ Opera 10.5+

Function 11: Date.prototype.toJSON

 

提供了从Date类型转成json的方法。

 

Js代码
  1. new Date().toJSON(); // “2010-12-06T16:25:40.040Z”

Function 12: Function.prototype.bind

你会发现这个函数的功能和下面的很相似

 

Js代码
  1. var arr1 = [‘1’, ‘2’, ‘3’],
  2. arr2 = [‘4’, ‘5’, ‘6’];
  3. // 等同于arr1.push(arr2);
  4. Array.prototype.push.apply(arr1, arr2);
  5. alert(arr1);

bind和上面的不同之处在于apply是直接执行的,而bind只是绑定函数内部的this,并且将函数返回

 

Js代码
  1. var tooltip = { text: ‘Click here to . . . ‘ },
  2. overlay = { text: ‘Please enter the number of attendees’ };
  3. function showText () {
  4. // really, do something more useful here
  5. alert(this.text);
  6. }
  7. tooltip.show = showText.bind(tooltip);
  8. tooltip.show();
  9. overlay.show = showText.bind(overlay);
  10. overlay.show();

Browser Support

○ Firefox 4

○ Internet Explorer 9

○ Chrome 7+

 

Function 13: Date.now()

大致这个函数就是等同于new Date().getTime() or +new Date,不是什么大的改动

 

Function 14: Object.getPrototypeOf

 

这个函数提供了从通过Object.create得到的对象中提取原型的方法,当然,如果这个对象是通过老的new

function的方法创造出来的,那也可以通过这个方法得到原型

 

 

Js代码
  1. var Dog = {
  2. name : ‘dog’,
  3. paws : 4,
  4. hungry : false,
  5. speak : function () { return ‘Woof!’; }
  6. };
  7. var dog = Object.create(Dog);
  8. // true
  9. alert(Object.getPrototypeOf(dog) === Dog);
  10. // 老方法判断
  11. function Cat() {}
  12. // true
  13. alert(Object.getPrototypeOf(new Cat()) === Cat.prototype);

 

Function 15: String.prototype.trim

 

用来去除字符串两边的空格

 

Js代码
  1. var origin = ” foo “;
  2. document.write(origin.trim());

 

Function 16: Array.prototype.indexOf

 

这个函数用来返回查找的对象在数组中第一次出现的index

他有两个参数,第一个参数是要查找的对象,第二个参数是查找的起始位置

 

Js代码
  1. var array = [2, 5, 9];
  2. var index = array.indexOf(2);
  3. // index is 0
  4. index = array.indexOf(7);
  5. // index is -1
  6. var element = 5;
  7. var indices = [];
  8. var idx = array.indexOf(element);
  9. while (idx != -1) {
  10. indices.push(idx);
  11. idx = array.indexOf(element, idx + 1);
  12. }

当然如果浏览器没有支持indexOf,你可以用以下方法实现

 

Js代码
  1. if (!Array.prototype.indexOf) {
  2. Array.prototype.indexOf = function(searchElement /*, fromIndex */) {
  3. “use strict”;
  4. if (this === void 0 || this === null)
  5. throw new TypeError();
  6. var t = Object(this);
  7. var len = t.length >>> 0;
  8. if (len === 0)
  9. return -1;
  10. var n = 0;
  11. if (arguments.length > 0) {
  12. n = Number(arguments[1]);
  13. if (n !== n)
  14. n = 0;
  15. else if (n !== 0 && n !== (1 / 0) && n !== -(1 / 0))
  16. n = (n > 0 || -1) * Math.floor(Math.abs(n));
  17. }
  18. if (n >= len)
  19. return -1;
  20. var k = n >= 0
  21. ? n : Math.max(len – Math.abs(n), 0);
  22. for (; k < len; k++) {
  23. if (k in t && t[k] === searchElement)
  24. return k;
  25. }
  26. return -1;
  27. };
  28. }

Function 17: Array.prototype.lastIndexOf

用法和16相似,取得最后一次出现的index

如果浏览器没有实现此方法,你可以通过这种方式实现

Java代码
  1. if (!Array.prototype.indexOf) {
  2. Array.prototype.indexOf = function(searchElement /*, fromIndex */) {
  3. “use strict”;
  4. if (this === void 0 || this === null)
  5. throw new TypeError();
  6. var t = Object(this);
  7. var len = t.length >>> 0;
  8. if (len === 0)
  9. return -1;
  10. var n = 0;
  11. if (arguments.length > 0) {
  12. n = Number(arguments[1]);
  13. if (n !== n)
  14. n = 0;
  15. else if (n !== 0 && n !== (1 / 0) && n !== -(1 / 0))
  16. n = (n > 0 || -1) * Math.floor(Math.abs(n));
  17. }
  18. if (n >= len)
  19. return -1;
  20. var k = n >= 0
  21. ? n : Math.max(len – Math.abs(n), 0);
  22. for (; k < len; k++) {
  23. if (k in t && t[k] === searchElement)
  24. return k;
  25. }
  26. return -1;
  27. };
  28. }
  29. Function 17: Array.prototype.lastIndexOf
  30. 用法和16相似,取得最后一次出现参数的index
  31. 如果浏览器没有实现此方法,你可以通过这种方式实现
  32. if (!Array.prototype.lastIndexOf) {
  33. Array.prototype.lastIndexOf = function(searchElement /*, fromIndex*/) {
  34. “use strict”;
  35. if (this === void 0 || this === null)
  36. throw new TypeError();
  37. var t = Object(this);
  38. var len = t.length >>> 0;
  39. if (len === 0)
  40. return -1;
  41. var n = len;
  42. if (arguments.length > 0) {
  43. n = Number(arguments[1]);
  44. if (n !== n)
  45. n = 0;
  46. else if (n !== 0 && n !== (1 / 0) && n !== -(1 / 0))
  47. n = (n > 0 || -1) * Math.floor(Math.abs(n));
  48. }
  49. var k = n >= 0
  50. ? Math.min(n, len – 1)
  51. : len – Math.abs(n);
  52. while (k >= 0) {
  53. if (k in t && t[k] === searchElement)
  54. return k;
  55. }
  56. return -1;
  57. };
  58. }

 

Function 18: Array.prototype.every

 

对于数组中的每一项都执行某个callback function,这个function的参数为当前数组元素,当前元素index,整个数组。当function中返回为false的时候,停止循环数组。仅当返回为true的时候继续循环

Js代码
  1. function isBigEnough(element, index, array) {
  2. return (element >= 10);
  3. }
  4. var passed = [12, 5, 8, 130, 44].every(isBigEnough);
  5. // passed is false
  6. passed = [12, 54, 18, 130, 44].every(isBigEnough);
  7. // passed is true

 

当浏览器没有实现此方法时,可以用以下方式代替

Js代码
  1. if (!Array.prototype.every) {
  2. Array.prototype.every = function(fun /*, thisp */) {
  3. “use strict”;
  4. if (this === void 0 || this === null)
  5. throw new TypeError();
  6. var t = Object(this);
  7. var len = t.length >>> 0;
  8. if (typeof fun !== “function”)
  9. throw new TypeError();
  10. var thisp = arguments[1];
  11. for (var i = 0; i < len; i++) {
  12. if (i in t && !fun.call(thisp, t[i], i, t))
  13. return false;
  14. }
  15. return true;
  16. };
  17. }

 

Function 19: Array.prototype.some

大致意思和every有些相似,当数组中有一个元素符合要求,就会返回true。所以callback中,一旦返回true,就不再循环,返回false则继续循环。

Js代码
  1. function isBigEnough(element, index, array) {
  2. return (element >= 10);
  3. }
  4. var passed = [2, 5, 8, 1, 4].some(isBigEnough);
  5. // passed is false
  6. passed = [12, 5, 8, 1, 4].some(isBigEnough);
  7. // passed is true

 

当浏览器不支持的时候,你可以用以下代码代替

Java代码
  1. if (!Array.prototype.some) {
  2. Array.prototype.some = function(fun /*, thisp */) {
  3. “use strict”;
  4. if (this === void 0 || this === null)
  5. throw new TypeError();
  6. var t = Object(this);
  7. var len = t.length >>> 0;
  8. if (typeof fun !== “function”)
  9. throw new TypeError();
  10. var thisp = arguments[1];
  11. for (var i = 0; i < len; i++) {
  12. if (i in t && fun.call(thisp, t[i], i, t))
  13. return true;
  14. }
  15. return false;
  16. };
  17. }

 

Function 20: Array.prototype.forEach

 

此函数对数组的所有元素循环执行一个callback function

Js代码
  1. function printElt(element, index, array) {
  2. print(“[” + index + “] is ” + element); // assumes print is already defined
  3. }
  4. [2, 5, 9].forEach(printElt);
  5. // Prints:
  6. // [0] is 2
  7. // [1] is 5
  8. // [2] is 9

 

当浏览器没有实现的时候,你可以通过如下方法代替

 

Js代码
  1. if (!Array.prototype.forEach) {
  2. Array.prototype.forEach = function(fun /*, thisp */) {
  3. “use strict”;
  4. if (this === void 0 || this === null)
  5. throw new TypeError();
  6. var t = Object(this);
  7. var len = t.length >>> 0;
  8. if (typeof fun !== “function”)
  9. throw new TypeError();
  10. var thisp = arguments[1];
  11. for (var i = 0; i < len; i++) {
  12. if (i in t)
  13. fun.call(thisp, t[i], i, t);
  14. }
  15. };
  16. }

 

Function 21: Array.prototype.map

循环数组每个元素,用于执行callback,之后返回循环结果作为一个新数组,而原数组不变.

Sample1:

Js代码
  1. function makePseudoPlural(single) {
  2. return single.replace(/o/g, “e”);
  3. }
  4. var singles = [“foot”, “goose”, “moose”];
  5. var plurals = singles.map(makePseudoPlural);
  6. // plurals is [“feet”, “geese”, “meese”]
  7. // singles is unchanged<span style=”white-space: normal;”> </span>

 

Sample2

 

 

Js代码
  1. var numbers = [1, 4, 9];
  2. var roots = numbers.map(Math.sqrt);
  3. // roots is now [1, 2, 3]
  4. // numbers is still [1, 4, 9]

如果浏览器没有实现,则可以用如下方法代替

Java代码
  1. if (!Array.prototype.map) {
  2. Array.prototype.map = function(fun /*, thisp */) {
  3. “use strict”;
  4. if (this === void 0 || this === null)
  5. throw new TypeError();
  6. var t = Object(this);
  7. var len = t.length >>> 0;
  8. if (typeof fun !== “function”)
  9. throw new TypeError();
  10. var res = new Array(len);
  11. var thisp = arguments[1];
  12. for (var i = 0; i < len; i++) {
  13. if (i in t)
  14. res[i] = fun.call(thisp, t[i], i, t);
  15. }
  16. return res;
  17. };

 

Function 22: Array.prototype.filter

 

从数组中筛选出符合callback条件的元素,如果callback中返回true,则此元素会被加入到新数组中

Js代码
  1. function isBigEnough(element, index, array) {
  2. return (element >= 10);
  3. }
  4. // 12, 130, 44
  5. var filtered = [12, 5, 8, 130, 44].filter(isBigEnough);

 

如果浏览器没有实现,则可以用如下方式代替:

Js代码
  1. if (!Array.prototype.filter) {
  2. Array.prototype.filter = function(fun /*, thisp */) {
  3. “use strict”;
  4. if (this === void 0 || this === null)
  5. throw new TypeError();
  6. var t = Object(this);
  7. var len = t.length >>> 0;
  8. if (typeof fun !== “function”)
  9. throw new TypeError();
  10. var res = [];
  11. var thisp = arguments[1];
  12. for (var i = 0; i < len; i++) {
  13. if (i in t) {
  14. var val = t[i]; // in case fun mutates this
  15. if (fun.call(thisp, val, i, t))
  16. res.push(val);
  17. }
  18. }
  19. return res;
  20. };
  21. }

 

Function 23: Array.prototype.reduce

 

这个函数有两个参数,第一个为callback function,第二个为初始值。

Callback function的格式为:

.reduce(function(previousValue, currentValue, index, array){ // …})

Js代码
  1. var total = [0, 1, 2, 3].reduce(function(a, b){ return a + b; });
  2. // total == 6
  3. var flattened = [[0, 1], [2, 3], [4, 5]].reduce(function(a, b) {
  4. return a.concat(b);
  5. });
  6. // flattened is [0, 1, 2, 3, 4, 5]

 

 

如果浏览器没有实现,则可用以下代码代替

 

 

 

 

Js代码
  1. if (!Array.prototype.reduce) {
  2. Array.prototype.reduce = function(fun /*, initialValue */) {
  3. “use strict”;
  4. if (this === void 0 || this === null)
  5. throw new TypeError();
  6. var t = Object(this);
  7. var len = t.length >>> 0;
  8. if (typeof fun !== “function”)
  9. throw new TypeError();
  10. // no value to return if no initial value and an empty array
  11. if (len == 0 && arguments.length == 1)
  12. throw new TypeError();
  13. var k = 0;
  14. var accumulator;
  15. if (arguments.length >= 2) {
  16. accumulator = arguments[1];
  17. } else {
  18. do {
  19. if (k in t) {
  20. accumulator = t[k++];
  21. break;
  22. }
  23. // if array contains no values, no initial value to return
  24. if (++k >= len)
  25. throw new TypeError();
  26. } while (true);
  27. }
  28. while (k < len) {
  29. if (k in t)
  30. accumulator = fun.call(undefined, accumulator, t[k], k, t);
  31. k++;
  32. }
  33. return accumulator;
  34. };
  35. }

 

 

Function 24: Array.prototype.reduceRight

 

这个函数有两个参数,第一个为callback function,第二个为初始值。

Callback function的格式为:

 

 

 

 

Js代码
  1. var total = [0, 1, 2, 3].reduceRight(function(a, b) { return a + b; });
  2. //total == 6
  3. var flattened = [[0, 1], [2, 3], [4, 5]].reduceRight(function(a, b) {
  4. return a.concat(b);
  5. }, []);
  6. // flattened is [4, 5, 2, 3, 0, 1]