[转载]Bing Maps Android SDK Released

mikel阅读(899)

[转载]Bing Maps Android SDK Released – Bēniaǒ成长笔记 – 博客园.

Bing Maps Android SDK是一套使用JAVA语言基于微软Bing Maps AJAX v7 Control之上开发的一套GIS开发API,并开源发布于Codeplex,以帮助Android开发人员创建基于微软Bing Maps AJAX V7 Control的地图应用程序。

项目地址http://bingmapsandroidsdk.codeplex.com/

功能列表

– Built on top of Bing Maps AJAX V7
– Touch controls added to support pinch to zoom, and double tap to zoom
– Majority of map functionalities are wrapped with Java code so that there is no need to write JavaScript code. This should make things easier for Android developers.
– Requires Bing Maps Key
– Supports Pushpins, Polylines, Polygons, EntityCollections, and TileLayers.
– Libraries for accessing Bing Maps REST service supports Geocoding (Address and query searches), Reverse Geocoding, Routing with support for all route options.
– Libraries for accessing Bing Spatial Data service supports FindByArea, FindByID, and FindByProperty.
– All service calls have an Asynchronous task which make requests to Bing Servers and parses the response on a background tread.
– Works in any orientation.
– Infobox support.
– Support for GeoRSS files.

未来计划

– Support for localization.
– Documentation of code, and articles on how to use the SDK to create an application.
– UI controls for rotating Birdseye view.
– Clustering.
– Best Map View support for data.
– Location Details view.

参考资料

[1]、http://rbrundritt.wordpress.com/2011/03/21/bing-maps-android-sdk-released/

[转载]ASP.NET MVC 3 RTM 更新(1)

mikel阅读(934)

[转载]ASP.NET MVC 3 RTM 更新(1) – Catcher In The Rye – 博客园.

一、路由(Routing)

路由功能最初整合在ASP.NET MVC(以下简称MVC)中,后来被独立出来形成了System.Web.Routing 3.5程序集。ASP.NET 4已经把Routing功能已经转移到了System.Web 4 程序集下作为基础服务的一部分。在使用Routing功能时,您已不再需要在web.config中注册Module,因为 UrlRoutingModule已经集成进ASP.NET 4中了,就像FormsAuthenticationModule等Module一样。而ASP.NET MVC 3(以下简称MVC3)是基于ASP.NET 4的。

在System.Web.Routing 3.5中,UrlRoutingModule通过处理PostResolveRequestCache和PostMapRequestHandler事件 来配合设置请求处理程序(IHttpHandler),而在System.Web.Routing 4中,只处理了PostResolveRequestCache事件(PostMapRequestHandler事件也处理了,但什么都不做,但已标明 过期)。

值得一提的是ASP.NET 4的HttpContext新增加了一个RequestContext属性,其类型正是System.Web.Routing.RequestContext。该类封装了当前请求上下文以及RouteData。

增加了PageRouteHandler类以支持WebForm的路由功能,该类实现IRouteHandler接口。而在ASP.NET 2.0中,得自己实现类似的IRouteHandler。
为了更方便的添加该类型的路由规则,RouteCollection类中还新增加了四个MapPageRoute的重载方法。

简单演示一下:
1、新建一个基于.Net 4的Web Application。
2、新建Global.asa并修改Global.asa.cs的Application_Start方法
void Application_Start(object sender, EventArgs e)
{
// 以下两种方式都可以添加路由规则,显然MapPageRoute更方便、清晰一些
//RouteTable.Routes.Add(“newRoute”,new Route(“TestRouting”,new PageRouteHandler(“~/TestRouting.aspx”)));
RouteTable.Routes.MapPageRoute(“newRoute”
, “RoutingTest”
, “~/RoutingTest.aspx”);

}
3、新建Web窗体,命名为RoutingTest.aspx。在里面随便输入一些内容。
4、启动调试(F5),输入类似的网址:http://localhost:3232/RoutingTest

一切正常的话应该显示出您输入的内容。

二、IDependencyResolver和DependencyResolver

Ioc/DI(Inversion of Control / the Dependency Injection,控制反转/依赖注入)是实现系统解耦的一大利器。.Net平台可用的DI容器有Castle Windsor、StructureMap、Autofac 、Unity等。在MVC2中我们就可以很容易的使用这些容器,MVC3在DI方面又为我们做了什么呢?

需要清楚一点,MVC3对DI的 支持并不是说它内置了类似于Autofac之类的DI容器。它只是内置了一种创建(获取)对象的默认“方式” (DefaultDependencyResolver),这种“方式”内部其中一个途径是通过 Activator.CreateInstance(Type serviceType)来创建对象。更重要的是,它提供了一种API让我们可以改变这种方式。这使得我们可以使用Autofac之类的DI方式来替换。

下面我们从源码角度分析一下MVC3是如何实现这种机制的。

首先看看IDependencyResolver接口,该接口正是上面所说的创建(获取)对象的“方式”。接口有两个方法,GetService根据Type获取一个简单对象,GetServices根据Type获取一个集合对象。
public interface IDependencyResolver
{
object GetService(Type serviceType);
IEnumerable<object> GetServices(Type serviceType);
}
DependencyResolver并不是IDependencyResolver接口的实现。
它有两个私有内联类DefaultDependencyResolver和DelegateBasedDependencyResolver,都是现实的IDependencyResolver接口;
一个DependencyResover型的私有变量_instance;
一个IDependencyResolver型的私有变量_current;
一个静态构造方法,方法内部创建一个DependencyResolver赋给_instance变量;
一个默认构造方法,方法内部创建一个DefaultDependencyResolver赋给_current变量;
两个只读的类型为IDependencyResolver的属性Current和InnerCurrent,这两个属性的get方法最终返回的是_instance变量——典型的单例模式;
三 个InnerSetResolver重载方法和三个SetResolver重载方法。每个SetResolver只是简单的调用对应的 InnerSetResolver方法。这些方法用于设置当前的IDependencyResolver对象,并将对象赋给_current变量。

当我们需要根据某种类型比如SomeClass创建相应的对象时,我们这样调用:DependencyResolver.Current.GetService(typeof(SomeType))。
当然,返回结合对象就这样调用DependencyResolver.Current.GetServices(typeof(SomeType))。
默 认情况下我们使用的是DefaultDependencyResolver对象,在该对象的GetService方法内部,通过调用 Activator.CreateInstance(typeof(SomeType))来创建对象,而GetServices方法返回的是 numerable.Empty<object>()生成的对象。

IDependencyResolver接口是创建(获取)对象的“方式”,而SetResolver方法等则是改变这种方式的API。下面简单分析一下这几个方法。
1、InnerSetResolver(IDependencyResolver resolver)
该方法接受一个IDependencyResolver型参数,方法内部直接将值赋给_current变量。
2、InnerSetResolver(Func<Type, object> getService, Func<Type, IEnumerable<object>> getServices)
该方法接受两个委托,第一个接受一个Type型参数返回object型对象,而第二个返回IEnumerable<object>型集合对象。
方法内部创建一个DelegateBasedDependencyResolver对象。调用DelegateBasedDependencyResolver.GetService(Type type)返回的
是getService(type)的执行结果。相应的,调用GetServices(Type type)返回的是getServices(type)的执行结果。
3、InnerSetResolver(object commonServiceLocator)
该方法接受一个object型参数,方法内部会通过反射的方式尝试获取方法名为”GetInstance”和”GetAllInstances”,参数为Type型的两个方法;
接着检查方法的返回值是否分别是object型和IEnumeralbe<object>型,如果是创建一个DelegateBasedDependencyResolver对象,两个方法作为构造方法
参数传入,并将对象赋给_current变量。返回值的不匹配则抛出异常。

您可能需要CommonServiceLocator的资料:http://commonservicelocator.codeplex.com

另外,DependencyResolverExtensions类是IDependencyResolver接口的扩展方法,分别是相应方法的泛型实现。
public static class DependencyResolverExtensions
{
public static TService GetService<TService>(this IDependencyResolver resolver)
{
return (TService) resolver.GetService(typeof(TService));
}

public static IEnumerable<TService> GetServices<TService>(this IDependencyResolver resolver)
{
return resolver.GetServices(typeof(TService)).Cast<TService>();
}
}

IDependencyResolver接口的实现类中,通常采用外观模式。内部包含一个DI容器,当调用GetService或GetServices方法时,调用DI容器相应的方法。

[转载]编程基本算法(三)

mikel阅读(1128)

[转载]编程基本算法(三) – 清风飘过 – 博客园.

编程基本算法(一)

编程基本算法(二)

编程基本算法(三)

选择排序

使用条件:可对比大小的集合。

算法思想:每一趟从待排序的数据元素中选出最小(或最大)的一个元素,顺序放在已排好序的数列的最后,直到全部待排序的数据元素排完。

举例编程:int b[10]={77,1,65,13,81,93,10,5,23,17}

//简单选择排序 void SimpleSelect(int b[10]) { int temp; int i; for(i=0;i<9;i++) { for(int j=i+1;j<9;j++) { if(b[i]>b[j]) { temp=b[i]; b[i]=b[j]; b[j]=temp; } } } cout<<"the sort is:"; for(int i=0;i<10;i++) { cout<<b[i]<<" "; } cout<<endl; }

性能分析:时间复杂度为On^2

堆排序

使用条件:可对比大小的集合。

算法思想:其实堆排序是简单选择排序的一种进化,它最主要是减少比较的次数。什么是堆?若将序列对应看成一个完全二叉树,完全二叉树中所有非终端节点的值均不大于(或者不小于)其左右孩子节点的值,可以称作为堆。由堆的性质可以知道堆顶是一个最大关键字(或者最小关键字)。在输出堆顶后,使剩下的元素又建成一个堆,然后在输出对顶。如此反复执行,便能得到一个有序序列,这个过程成便是堆排序。

堆排序主要分为两个步骤:

1)从无序序列建堆。(2)输出对顶元素,在调成一个新堆。

举例编程:int b[10]={77,1,65,13,81,93,10,5,23,17}

//堆排序 void HeapSort(int b[10]) { void HeapAdjuest(int b[10],int min,int max); void Sawp(int *a,int *b); int i; //因为是完成二叉树,所以从最后一个非叶子节点开始堆转换 for(i=9/2;i>=0;i--) { HeapAdjuest(b,i,9); } //拿出堆顶数据在从新堆排序 for(i=9;i>0;i--) { Sawp(&b[i],&b[0]); HeapAdjuest(b,0,i-1); } } //堆调整(大顶堆) //min 数据需要调整在数组中的开始位置 //max 数据需要调整在数据中的结束位置 void HeapAdjuest(int b[10],int min,int max) { if(max<=min)return ; int temp; temp=b[min]; int j; //延它的孩子节点循环 for(j=2*min;j<=max;j*=2) { //选择它的大孩子 if(j<max&&b[j]<b[j+1]) { j++; } //堆顶小于它的孩子不做处理 if(temp>b[j]) { break; } //将大的数替换成小的数 b[min]=b[j]; min=j; } b[min]=temp; } //交换函数 void Sawp(int *a,int *b) { int temp; temp=*a; *a=*b; *b=temp; }

性能分析:时间复杂度时间复杂度O(nlogn)

归并算法

又称2路归并算法

使用条件:可对比大小的集合。

算法思想:假设初始序列含有n个记录,则可看成n个有序的子序列,每个子序列长度为1,然后两两归并,得到[n/2]个长度为2或者为1(这里长度为1可能这里序列长度是奇数,那么最后一个序列就落单了,所以长度为1);在两两归并,如此重复,直至得到一个长度为n的有序序列为止。

举例编程:int b[10]={77,1,65,13,81,93,10,5,23,17}

//归并排序 void MergeSort(int b[10],int d[10],int min,int max) { //用与存放中间分区域得到的序列 int c[10]; void Merge(int c[10],int d[10],int min,int mid,int max); if(min==max)d[min]=b[min]; else { //平分成两个区域 int mid=(min+max)/2; //将这个区域进行归并排序 MergeSort(b,c,min,mid); //将这个区域进行归并排序 MergeSort(b,c,mid+1,max); //两个区域归并 Merge(c,d,min,mid,max); } } //将有序序列d[min-mid]与d[mid+1-max]归并成有序序列c[min-max] void Merge(int c[10],int d[10],int min,int mid,int max) { int i,j,k; for(i=j=min,k=mid+1;j<=mid&&k<=max;i++) { if(c[j]>c[k]) { d[i]=c[k]; k++; } else { d[i]=c[j]; j++; } } if(j<=mid) { for(;j<=mid;j++,i++) { d[i]=c[j]; } } if(k<=max) { for(;k<=max;k++,i++) { d[i]=c[k]; } } }

性能分析:时间复杂度O(nlogn)

总结

那么这么多排序算法,到底什么时候用什么样的算法呢?

因为不同的排序方法适应不同的应用换进和要求,选择合适的排序方法考虑以下因素:

  • 待排序的记录数n
  • 对其稳定性要求
  • 存储结构
  • 时间和辅助空间复杂度

(1)如果n比较小(例如n<=50),可采用直接插入排序或者简单选择排序。

(2)如果序列初始状态基本有序,则可选用直接插入排序,冒泡排序。

(3)如果n比价大,则可采用时间复杂度为O(nlogn)的算法:快速排序,堆排序,归并排序。

快速排序被认为目前基于比较的内部排序中最好的方法。当带排序的关键字随机分布时,快速排序平均时间最短。 不稳定

堆排序所需要的辅助空间小于快速排序,并且不会出现快速排序可能出现的最坏情况。 但还是比较不稳定

归并排序,比较稳定,但是归并排序一般不提倡使用,实用性很差,占用的辅助空间肯能个比较大。

[转载]C#高效编程话题集2(每期10话题)

mikel阅读(1028)

[转载]C#高效编程话题集2(每期10话题) – 不如来编码-luminji’s web – 博客园.

第一期话题在:C#高效编程话题集1(每期10话题)

C#快速成长团队第二期话题来到。欢迎进入C#快速成长团队进行讨论。

1:确保集合的线程安全

如果使用.net4.0,有新的线程安全集合类
新的 System.Collections.Concurrent 命名空间引入了多个新的线程安全集合类,可在需要时随时提供对项的无锁访问,并在锁适用时提供细粒度锁定。 在多线程方案中使用这些类应获得优于集合类型(例如, ArrayList 和 List <(Of <(T >)>))的性能。

除了System.Collections.Concurrent空间下集合外,非泛型集合使用
lock(非泛型集合对象.SyncRoot)进行锁定达到集合线程安全目的
泛型集合使用
static object sycObj = new object(); //是否static看具体应用
lock (sycObj)
{
//操作集合。
}

2:循环中先求长度还是使用list.Count,哪个效率高

第一类:

int len = list.Count;

for(int i; i<len; i++)

{

迭代

}

第二类:

for(int i; i<list.Count; i++)

{

迭代

}

答案是一样高。

第一种方法完全没有必要,很多人可能以为那样会为代码带来效率,而实际上是不会给效率带来任何提升。
因为事实上,索引器内部,为了安全期间,还是会去求整个list的count的。将两者代码贴出来可能会更好的理解这一点:
public T this[int index]
{
get
{
if (index >= this._size)
{
ThrowHelper.ThrowArgumentOutOfRangeException();
}
return this._items[index];
}
set
{
if (index >= this._size)
{
ThrowHelper.ThrowArgumentOutOfRangeException();
}
this._items[index] = value;
this._version++;
}
}
public int Count
{
get
{
return this._size;
}
}

3:善用延迟求值

以List<int> list = new List<int>() { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9};为例,说明linq查询中的延迟求值和主动求值。

List<int> list = new List<int>() { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
var temp1 = from c in list where c > 5 select c;
var temp2 = (from c in list where c > 5 select c).ToList<int>();
list[0] = 11;
Console.Write(“temp1: “);
foreach (var item in temp1)
{
Console.Write(item.ToString() + ” “);
}
Console.Write(“\ntemp2: “);
foreach (var item in temp2)
{
Console.Write(item.ToString() + ” “);
}

4:谨慎泛型类型中的静态成员

static void Main(string[] args)
{
MyList<int> list1 = new MyList<int>();
MyList<int> list2 = new MyList<int>();
MyList<string> list3 = new MyList<string>();
Console.WriteLine(MyList<int>.Count);
Console.WriteLine(MyList<string>.Count);
}
class MyList<T>
{
public static int Count { get; set; }
public MyList()
{
Count++;
}

}

代码输出是莫子?

只要知道 MyList<int> 和 MyList<string> 是两个不同的类型,这题就不难理解了。.NET 中类型参数不同的封闭泛型类型是不同的类型。

5:小心闭包中的陷阱

for (int i = 0; i < 10; i++)
{
Action t = () =>
{
Console.WriteLine(“t1:” + i.ToString());
};
t.BeginInvoke(null, null);
}

以上代码的输出为?

当闭包中引用了外部的局部变量或者方法参数的时候,C#会把该变量编译成一个类的实例字段,顶楼的代码编译后实际上等效于:
TempClass tp = new TempClass();
for (tp.i = 0; tp.i < 10; tp.i++)
{
Action t = tp.TempMethod;
t.BeginInvoke(null, null);
}
TempClass是C#编译器自动生成的类,其定义大概是这样:
class TempClass
{
public int i;
public void TempMethod()
{
Console.Writeline(“t1:” + i.ToString());
}
}
因为只循环10次,几乎一瞬间就完了,因此第一个异步委托还没开始执行 tp.i 就等于10了

6:event关键字的作用

既然使用委托也能实现回调,为什么又需要event关键字。答曰:event 最大的作用就是防止在类的外部触发类的事件。

7:区分IEnumerable<T>和IQueryable<T>

本地数据源用IEnumerable<T>,远程数据源用IQueryable<T>。
针对LinqLINQ TO to OBJECTS,使用Enumerable中的扩展方法对本地集合进行排序、查询等操作,查询参数接受的是Func< >。Func< >叫做谓语表达式,相当于一个委托。针对LinqLINQ TO to SQL则使用Querable中的扩展方法,它接受的参数是Expression< >。Expression< >用于包装Func< >。LinqLINQ TO to SQL引擎最终会将表达式树转化成为相应的SQL语句,然后在数据库中执行。

8:选择正确的集合

查看此文吧:http://www.cnblogs.com/luminji/archive/2011/03/24/1993393.html

9:泛型参数的约束是不是应该叫约定更好

在泛型的使用过程中,常常使用到的一个功能就是为泛型参数设定约束。约束听上去像是限制了泛型参数的使用范围,而实际上,约束本身确实拓展了泛型参数的使用。

一个没有约束的泛型参数,只能具有object的行为和属性,而一个指定约束为Student的泛型参数,却可以使用类型Student的所有公开属性和方法。

所以,俺觉得约束这个词翻译的实在不好,叫约定多好。

10:减少使用自定义委托

FCL中的3个(或者说3系列)委托已经满足了大部分自定义委托的需求,所以基本上不再需要自定义委托了。

它们是:

Action表示接受0个或多个输入参数,执行一段代码,但是没有任何返回值;

Func表示接受0个或多个输入参数,执行一段代码,同时有返回值;

Predicate表示定义一组条件并判断参数是否符合条件;

更多话题,期待下一期。

[转载]使用SQL Server Management Studio 2008 将数据库里的数据导成脚本

mikel阅读(833)

[转载]使用SQL Server Management Studio 2008 将数据库里的数据导成脚本 – 自由、创新、研究、探索 – 博客园.

之前很羡慕MySQL 有这样的工具可以把数据库里的数据导成脚本,SQL Server 2005 的时候大牛Pinal Dave写了个Database Publishing Wizard,具体用法参考他写的文章SQL SERVER – 2005 – Generate Script with Data from Database – Database Publishing Wizard。SQL Server Management Studio 2008现在已经自带了这样的功能,下面我就来演示下如何使用:

1、打开SQL Server Management Studio 2008 ,连接到你的数据库服务器,展开对象资源管理器到数据库节点

2、选择需要将数据导出到脚本的数据库,我这里选择的是AdventureWorks ,将包含所有的存储过程,表,视图,表里的数据等等。

image

3、右击选中的数据,按照以下路径选择生成脚本向导 :AdventureWorks -〉任务 -〉生成脚本

image

4、当点击生成脚本,弹出一个向导–生成数据库对象脚本:

image

5、下一步到达设置脚本编写选项,进入高级设置对话框,关键是要编写脚本的数据类型这里,默认是仅限架构,选择架构和数据或者是数据都可以吧数据导成脚本:

image

执行完就可以看到如下的结果了

image

[转载]使用SQL Server Management Studio 2008 将数据库里的数据导成脚本

mikel阅读(840)

[转载]使用SQL Server Management Studio 2008 将数据库里的数据导成脚本 – 自由、创新、研究、探索 – 博客园.

之前很羡慕MySQL 有这样的工具可以把数据库里的数据导成脚本,SQL Server 2005 的时候大牛Pinal Dave写了个Database Publishing Wizard,具体用法参考他写的文章SQL SERVER – 2005 – Generate Script with Data from Database – Database Publishing Wizard。SQL Server Management Studio 2008现在已经自带了这样的功能,下面我就来演示下如何使用:

1、打开SQL Server Management Studio 2008 ,连接到你的数据库服务器,展开对象资源管理器到数据库节点

2、选择需要将数据导出到脚本的数据库,我这里选择的是AdventureWorks ,将包含所有的存储过程,表,视图,表里的数据等等。

image

3、右击选中的数据,按照以下路径选择生成脚本向导 :AdventureWorks -〉任务 -〉生成脚本

image

4、当点击生成脚本,弹出一个向导–生成数据库对象脚本:

image

5、下一步到达设置脚本编写选项,进入高级设置对话框,关键是要编写脚本的数据类型这里,默认是仅限架构,选择架构和数据或者是数据都可以吧数据导成脚本:

image

执行完就可以看到如下的结果了

image

[转载][翻译]JavaScript秘密花园 - Type Casting,undefined,eval,setTimeout,Auto Semicolon Insertion - 全部完成PDF打包下载

mikel阅读(835)

[转载][翻译]JavaScript秘密花园 – Type Casting,undefined,eval,setTimeout,Auto Semicolon Insertion – 全部完成PDF打包下载 – 三生石上 – 博客园.

PDF打包下载

类型转换

JavaScript弱类型语言,所以会在任何可能的情况下应用强制类型转换

// 下面的比较结果是:true
new Number(10) == 10; // Number.toString() 返回的字符串被再次转换为数字

10 == '10';           // 字符串被转换为数字
10 == '+10 ';         // 同上
10 == '010';          // 同上 
isNaN(null) == false; // null 被转换为数字 0
                      // 0 当然不是一个 NaN(译者注:否定之否定)

// 下面的比较结果是:false
10 == 010;
10 == '-10';

ES5 提示:0 开头的数字字面值会被作为八进制数字解析。 而在 ECMAScript 5 严格模式下,这个特性被移除了。

为了避免上面复杂的强制类型转换,强烈推荐使用严格的等于操作符。 虽然这可以避免大部分的问题,但 JavaScript 的弱类型系统仍然会导致一些其它问题。

内置类型的构造函数(Constructors of built-in types)

内置类型(比如 NumberString)的构造函数在被调用时,使用或者不使用 new 的结果完全不同。

new Number(10) === 10;     // False, 对象与数字的比较
Number(10) === 10;         // True, 数字与数字的比较
new Number(10) + 0 === 10; // True, 由于隐式的类型转换

使用内置类型 Number 作为构造函数将会创建一个新的 Number 对象, 而在不使用 new 关键字的 Number 函数更像是一个数字转换器。

另外,在比较中引入对象的字面值将会导致更加复杂的强制类型转换。

最好的选择是把要比较的值显式的转换为三种可能的类型之一。

转换为字符串(Casting to a string)

'' + 10 === '10'; // true

将一个值加上空字符串可以轻松转换为字符串类型。

转换为数字(Casting to a number)

+'10' === 10; // true

使用一元的加号操作符,可以把字符串转换为数字。

译者注:字符串转换为数字的常用方法:

+'010' === 10
Number('010') === 10
parseInt('010', 10) === 10  // 用来转换为整数

+'010.2' === 10.2
Number('010.2') === 10.2
parseInt('010.2', 10) === 10

转换为布尔型(Casting to a boolean)

通过使用 操作符两次,可以把一个值转换为布尔型。

!!'foo';   // true
!!'';      // false
!!'0';     // true
!!'1';     // true
!!'-1'     // true
!!{};      // true
!!true;    // true

undefinednull

JavaScript 有两个表示 的值,其中比较有用的是 undefined

`undefined`的值(The value `undefined`)

undefined 是一个值为 undefined 的类型。

这个语言也定义了一个全局变量,它的值是 undefined,这个变量也被称为 undefined。 但是这个变量不是一个常量,也不是一个关键字。这意味着它的可以轻易被覆盖。

ES5 提示: 在 ECMAScript 5 的严格模式下,undefined 不再是 可写的了。 但是它的名称仍然可以被隐藏,比如定义一个函数名为 undefined

下面的情况会返回 undefined 值:

  • 访问未修改的全局变量 undefined
  • 由于没有定义 return 表达式的函数隐式返回。
  • return 表达式没有显式的返回任何内容。
  • 访问不存在的属性。
  • 函数参数没有被显式的传递值。
  • 任何被设置为 undefined 值的变量。

处理 `undefined` 值的改变(Handling changes to the value of `undefined`)

由于全局变量 undefined 只是保存了 undefined 类型实际的副本, 因此对它赋新值不会改变类型 undefined 的值。

然而,为了方便其它变量和 undefined 做比较,我们需要事先获取类型 undefined 的值。

为了避免可能对 undefined 值的改变,一个常用的技巧是使用一个传递到匿名包装器的额外参数。 在调用时,这个参数不会获取任何值。

var undefined = 123;
(function(something, foo, undefined) {
    // 局部作用域里的 undefined 变量重新获得了 `undefined` 值

})('Hello World', 42);

另外一种达到相同目的方法是在函数内使用变量声明。

var undefined = 123;
(function(something, foo) {
    var undefined;
    ...

})('Hello World', 42);

这里唯一的区别是,在压缩后并且函数内没有其它需要使用 var 声明变量的情况下,这个版本的代码会多出 4 个字节的代码。

译者注:这里有点绕口,其实很简单。 如果此函数内没有其它需要声明的变量,那么 var 总共 4 个字符(包含一个空白字符)就是专门为 undefined 变量准备的,相比上个例子多出了 4 个字节。

使用 `null`(Uses of `null`)

JavaScript 中的 undefined 的使用场景类似于其它语言中的 null,实际上 JavaScript 中的 null 是另外一种数据类型。

它在 JavaScript 内部有一些使用场景(比如声明原型链的终结 Foo.prototype = null),但是大多数情况下都可以使用 undefined 来代替。

为什么不要使用 `eval`

eval 函数会在当前作用域中执行一段 JavaScript 代码字符串。

var foo = 1;
function test() {
    var foo = 2;
    eval('foo = 3');
    return foo;
}
test(); // 3
foo; // 1

但是 eval 只在被直接调用并且调用函数就是 eval 本身时,才在当前作用域中执行。

var foo = 1;
function test() {
    var foo = 2;
    var bar = eval;
    bar('foo = 3');
    return foo;
}
test(); // 2
foo; // 3

译者注:上面的代码等价于在全局作用域中调用 eval,和下面两种写法效果一样:

// 写法一:直接调用全局作用域下的 foo 变量
var foo = 1;
function test() {
    var foo = 2;
    window.foo = 3;
    return foo;
}
test(); // 2
foo; // 3

// 写法二:使用 call 函数修改 `eval` 执行的上下文为全局作用域
var foo = 1;
function test() {
    var foo = 2;
    eval.call(window, 'foo = 3');
    return foo;
}
test(); // 2
foo; // 3

任何情况下我们都应该避免使用 eval 函数。99.9% 使用 eval 的场景都有不使用 eval 的解决方案。

伪装的 `eval`(`eval` in disguise)

定时函数 setTimeoutsetInterval 都可以接受字符串作为它们的第一个参数。 这个字符串总是在全局作用域中执行,因此 eval 在这种情况下没有被直接调用。

安全问题(Security issues)

eval 也存在安全问题,因为它会执行任意传给它的代码, 在代码字符串未知或者是来自一个不信任的源时,绝对不要使用 eval 函数。

结论(In conclusion)

绝对不要使用 eval,任何使用它的代码都会在它的工作方式,性能和安全性方面受到质疑。 如果一些情况必须使用到 eval 才能正常工作,首先它的设计会受到质疑,这不应该是首选的解决方案, 一个更好的不使用 eval 的解决方案应该得到充分考虑并优先采用。

`setTimeout` 和 `setInterval`

由于 JavaScript 是异步的,可以使用 setTimeoutsetInterval 来计划执行函数。

注意: 定时处理不是 ECMAScript 的标准,它们在 DOM 被实现。

function foo() {}
var id = setTimeout(foo, 1000); // 返回一个大于零的数字

setTimeout 被调用时,它会返回一个 ID 标识并且计划在将来大约 1000 毫秒后调用 foo 函数。 foo 函数只会被执行一次

基于 JavaScript 引擎的计时策略,以及本质上的单线程运行方式,所以其它代码的运行可能会阻塞此线程。 因此没法确保函数会在 setTimeout 指定的时刻被调用。

作为第一个参数的函数将会在全局作用域中执行,因此函数内的 `this` 将会指向这个全局对象。

function Foo() {
    this.value = 42;
    this.method = function() {
        // this 指向全局对象
        console.log(this.value); // 输出:undefined
    };
    setTimeout(this.method, 500);
}
new Foo();

注意: setTimeout 的第一个参数是函数对象,一个常犯的错误是这样的 setTimeout(foo(), 1000), 这里回调函数是 foo返回值,而不是foo本身。 大部分情况下,这是一个潜在的错误,因为如果函数返回 undefinedsetTimeout不会报错。

`setInterval` 的堆调用(Stacking calls with `setInterval`)

setTimeout 只会执行回调函数一次,不过 setInterval – 正如名字建议的 – 会每隔 X 毫秒执行函数一次。 但是却不鼓励使用这个函数。

当回调函数的执行被阻塞时,setInterval 仍然会发布更多的毁掉指令。在很小的定时间隔情况下,这会导致回调函数被堆积起来。

function foo(){
    // 阻塞执行 1 秒
}
setInterval(foo, 100);

上面代码中,foo 会执行一次随后被阻塞了一分钟。

foo 被阻塞的时候,setInterval 仍然在组织将来对回调函数的调用。 因此,当第一次 foo 函数调用结束时,已经有 10 次函数调用在等待执行。

处理可能的阻塞调用(Dealing with possible blocking code)

最简单也是最容易控制的方案,是在回调函数内部使用 setTimeout 函数。

function foo(){
    // 阻塞执行 1 秒
    setTimeout(foo, 100);
}
foo();

这样不仅封装了 setTimeout 回调函数,而且阻止了调用指令的堆积,可以有更多的控制。 foo 函数现在可以控制是否继续执行还是终止执行。

手工清空定时器(Manually clearing timeouts)

可以通过将定时时产生的 ID 标识传递给 clearTimeout 或者 clearInterval 函数来清除定时, 至于使用哪个函数取决于调用的时候使用的是 setTimeout 还是 setInterval

var id = setTimeout(foo, 1000);
clearTimeout(id);

清除所有定时器(Clearing all timeouts)

由于没有内置的清除所有定时器的方法,可以采用一种暴力的方式来达到这一目的。

// 清空"所有"的定时器
for(var i = 1; i < 1000; i++) {
    clearTimeout(i);
}

可能还有些定时器不会在上面代码中被清除(译者注:如果定时器调用时返回的 ID 值大于 1000), 因此我们可以事先保存所有的定时器 ID,然后一把清除。

隐藏使用 `eval`(Hidden use of `eval`)

setTimeoutsetInterval 也接受第一个参数为字符串的情况。 这个特性绝对不要使用,因为它在内部使用了 eval

注意: 由于定时器函数不是 ECMAScript 的标准,如何解析字符串参数在不同的 JavaScript 引擎实现中可能不同。 事实上,微软的 JScript 会使用 Function 构造函数来代替 eval 的使用。

function foo() {
    // 将会被调用
}

function bar() {
    function foo() {
        // 不会被调用
    }
    setTimeout('foo()', 1000);
}
bar();

由于 eval 在这种情况下不是被直接调用,因此传递到 setTimeout 的字符串会自全局作用域中执行; 因此,上面的回调函数使用的不是定义在 bar 作用域中的局部变量 foo

建议不要在调用定时器函数时,为了向回调函数传递参数而使用字符串的形式。

function foo(a, b, c) {}

// 不要这样做
setTimeout('foo(1,2, 3)', 1000)

// 可以使用匿名函数完成相同功能
setTimeout(function() {
    foo(a, b, c);
}, 1000)

注意: 虽然也可以使用这样的语法 setTimeout(foo, 1000, a, b, c), 但是不推荐这么做,因为在使用对象的属性方法时可能会出错。 (译者注:这里说的是属性方法内,this 的指向错误)

结论(In conclusion)

绝对不要使用字符串作为 setTimeout 或者 setInterval 的第一个参数, 这么写的代码明显质量很差。当需要向回调函数传递参数时,可以创建一个匿名函数,在函数内执行真实的回调函数。

另外,应该避免使用 setInterval,因为它的定时执行不会被 JavaScript 阻塞。

自动分号插入

尽管 JavaScript 有 C 的代码风格,但是它强制要求在代码中使用分号,实际上可以省略它们。

JavaScript 不是一个没有分号的语言,恰恰相反上它需要分号来就解析源代码。 因此 JavaScript 解析器在遇到由于缺少分号导致的解析错误时,会自动在源代码中插入分号。

var foo = function() {
} // 解析错误,分号丢失
test()

自动插入分号,解析器重新解析。

var foo = function() {
}; // 没有错误,解析继续
test()

自动的分号插入被认为是 JavaScript 语言最大的设计缺陷之一,因为它改变代码的行为。

工作原理(How it works)

下面的代码没有分号,因此解析器需要自己判断需要在哪些地方插入分号。

(function(window, undefined) {
    function test(options) {
        log('testing!')

        (options.list || []).forEach(function(i) {

        })

        options.value.test(
            'long string to pass here',
            'and another long string to pass'
        )

        return
        {
            foo: function() {}
        }
    }
    window.test = test

})(window)

(function(window) {
    window.someLibrary = {}

})(window)

下面是解析器”猜测”的结果。

(function(window, undefined) {
    function test(options) {

        // Not inserted, lines got merged
        log('testing!')(options.list || []).forEach(function(i) {

        }); // <- 插入分号

        options.value.test(
            'long string to pass here',
            'and another long string to pass'
        ); // <- 插入分号

        return; // <- 插入分号, 改变了 return 表达式的行为
        { // 作为一个代码段处理

            // a label and a single expression statement
            foo: function() {} 
        }; // <- 插入分号
    }
    window.test = test; // <- 插入分号

// The lines got merged again
})(window)(function(window) {
    window.someLibrary = {}; // <- 插入分号

})(window); //<- 插入分号

注意: JavaScript 不能正确的处理 return 表达式紧跟换行符的情况, 虽然这不能算是自动分号插入的错误,但这确实是一种不希望的副作用。

解析器显著改变了上面代码的行为,在另外一些情况下也会做出错误的处理

前置括号(Leading parenthesis)

在前置括号的情况下,解析器不会自动插入分号。

log('testing!')
(options.list || []).forEach(function(i) {})

上面代码被解析器转换为一行。

log('testing!')(options.list || []).forEach(function(i) {})

log 函数的执行结果极大可能不是函数;这种情况下就会出现 TypeError 的错误,详细错误信息可能是 undefined is not a function

结论(In conclusion)

建议绝对不要省略分号,同时也提倡将花括号和相应的表达式放在一行, 对于只有一行代码的 if 或者 else 表达式,也不应该省略花括号。

这些良好的编程习惯不仅可以提到代码的一致性,而且可以防止解析器改变代码行为的错误处理。

[转载]css与js实现Tab标签切换

mikel阅读(1005)

[转载]css与js实现Tab标签切换 – qandq – 博客园.

如下图所示的tab菜单切换,目前很流行这种效果。

代码如下:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>tab标签切换</title>
<style>
*{
font-size:10.5pt;
margin:0px;
padding:0px;
}
.codeDemoUL {
list-style: none;
clear:right;
overflow:hidden;
cursor:pointer;
z-index:3;
position:relative;
margin-bottom:-1px;
}
.codeDemoUL li {
float:left;
padding:5px 10px;
display:inline;
border-bottom:none;
margin: 0 5px 0 0;
overflow: visible;
line-height:1.5em;
}
.codeDemomouseOnMenu {
border:1px solid #bdc5c8;
border-bottom:1px solid #fff;
background-color:#fff;
font-weight:bold;
}
.codeDemomouseOutMenu
{
border:1px solid #bdc5c8;
background-color:#d7e0e3;
}
.codeDemoDiv {
clear:both;
border:1px solid #bdc5c8;
overflow:hidden;
margin-bottom:10px;
}
</style>

<SCRIPT LANGUAGE="JavaScript">
<!--
var $ = function(o) {return document.getElementById(o);}
function showDiv(parm)
{
$('divDemo').style.display='none';
$('divCode').style.display='none';
$(parm).style.display = '';
for(var i in $('ulMenu').getElementsByTagName('LI')){
$('ulMenu').getElementsByTagName('LI')&#91;i&#93;.className = 'codeDemomouseOutMenu';
}
}
//-->
</SCRIPT>
</head>
<body>
<ul class="codeDemoUL" id="ulMenu">
<li class="codeDemomouseOnMenu" onclick="showDiv('divDemo');this.className='codeDemomouseOnMenu'">演 示</li>
<li class="codeDemomouseOutMenu" onclick="showDiv('divCode');this.className='codeDemomouseOnMenu'">代 码</li>
</ul>
<div class="codeDemoDiv" id="divDemo">
<br />
&nbsp;&nbsp;&nbsp;演示
</div>
<div class="codeDemoDiv" id="divCode" style="display:none">
<br />&nbsp;&nbsp;&nbsp;代码
</div>

</body>
</html>


[转载]程序员人生之路(强烈推荐,分析的透彻!)

mikel阅读(927)

[转载]程序员人生之路(强烈推荐,分析的透彻!) – shenopkss.net – 博客园.

程序员人生之路(强烈推荐,分析的透彻!),某程序达人的人生感悟,估计没有半个甲子的时间,是绝对不可能感悟出来的。
转载自CSDN论坛:http://topic.csdn.net/u/20110323/16/16ebe2ac-bca5-49da-a050-45cf522a0828.html
原文在网上找了下:http://blog.csdn.net/b136364111/archive/2007/12/10/1927073.aspx
本文所指的开发工程师,仅指程序开发人员和以数字电路开发为主的电子工程师。
当你选择计算机或者电子、自控等专业进入大学时,你本来还是有机会从事其它行业的,可你毕业时执迷不悟,仍然选择了开发做为你的职业,真是自做孽不可活。不过,欢迎你和我一样加入这个被其它人认为是风光无限的“白领”吧。
如果你不是特别的与人世隔绝,我想你一定看过金老先生的名著《笑傲江湖》吧,里面有一门十分奇特的武功叫做”辟邪剑法”,你看这个小说第一次看到这种功 夫的练法时,我想你当时一定笑歪了牙“呵呵,真好玩!”,可是现在我很痛心的告诉你:你选择的开发工作就是你人生路上的”辟邪剑法”,而你现在已经练了, 并且无法再回头。

相对同时刚出校门同学从事其它行业而言优厚的薪水,以及不断学习更新的专业知识不仅仅让你感到生活的充实,更满足了你那不让外人知的虚荣心。在刚出校门 的几年中,你经常回头看看被你落在后面的同学们,在内心怜悯他们的同时,你也会对自已天天加班的努力工作感到心里平衡:“有付出才会有回报”这句话在那几 年中你说的最多,不管是对自已的朋友们还是自已的爱人。第二句最常说的话是对公司的领导:“不行我就走人!”,实际上你也真的走过几回。对了,在这几年 中,因为你的经济条件不错,你开始买房、开始谈恋爱、结婚、开始有了自已的小孩。有时候你会对自已说再过两年就去买车。当然其中可能有许多大件是需要分期 付款的,但你对前途充满了信心,你确信认为这种日子会永远的持续下去,即使不是变得更好的话。
日子总是在这种平淡中一天天的过去,就在那么不 经意间,你突然发现自已已经快30岁了,或者已经30了,莫名的,你心里会漫延着一种说不清楚的不安情绪,你好像觉得前途并非像前几年那样变得越来越好, 你也忽然发现你以前所瞧不起的同学里好像已经有不少开着车的了,也有几个人住着比你还大的房子,好像房款还是一次付清的,你突然明白你现在的生活比起你的 同学来最多是中游偏上了。工作中最让你感到心里不舒服的是,你越来越不敢对你的领导说不了,即使比你来的晚的同事升职或提薪,你也只是在私下与朋友们一起 喝酒时才敢发发牢骚,在头的面前你的声间越来越小、笑脸是越来越温柔。
你终于开始迷茫“再过几年我会是在干什么呢?”,这句话常常出现在你的心里。
计算机开发工作,是一种以年轻为资本的工作,说句通俗点的话是“吃青春饭的”,嗯,这句话好像在一种特别的行业也听到过。

其 标志就是一:工作的时间性非常强,一个开发项目被定的时限通常是很紧张的,更有甚者,有些号称开发管理的书里面还非常卑鄙的号召将一个项目切成多个小片, 每个小片都定一个叫“里程碑”的东东来严格跟踪开发进度,加班加点在其它行业是需要加班工资的,而在开发行业,加班工资好像还没见到几个公司发过,是啊, 反正有时间限制着,你干不完我再找你算账.所以开发工作通常有着其它工作所没有的精神上的压力。

一旦一个人步入而立之年,因为家庭和孩子 的负担,加上精力上面的衰退,加班工作时间变得越来越少,这点让很多老板们感到:这些人已经老了,不好用了。指示人事部门:“以后招开发人员限制在30岁 以下!”,相对而言硬件开发会年龄方面限制会稍好一点点,但也是五十步笑百步。还有一个很重要的一点就是:计算机这个烂东东实在是进步的太快了,前两年买 的顶级配置电脑,现在怎么看怎么像废品,这还是小事,更可气的是好像每天都需要学习新的知识,刚毕业时只会书本上的PASCAL,学会了用腐蚀的办法来做 电路板,一上班就开始学习TURBOC和TANGER2.0,刚刚学会,还没来得及高兴,马上开始学Borland C++和Protel3.0,好不容易学会了,却发现需要学习VC和Protel98了。单片机也是啊:Z80的指令背的很熟,工作中没来得及用就要学 8031,好好学吧,本来想着这辈子就吃它了,又发现又出来什么PIC、DSP、CPLD、FPGA、ARM等等….这还不包括中间要学一大堆74系 列、4000系列、XX系列…IC卡居然里面还有CPU卡..如果学习的知识里每个字都能变成一分钱,我想所有的开发工程师都是腰缠万贯的富翁。
一眼看去,这种日子好像见不到头,年轻时乐此不彼,但现在你一定对自已能坚持到什么时候感到怀疑了。我们都玩过像仙剑奇侠传这样的RPG游戏,刚开始时 你只是一个一名不文的少年,随着你去打怪物、捡宝贝、学秘芨,最后终于有一天你会变成一个大英雄!那么你在实际生活中过得比那些小侠们还辛苦,为什么成不 了一个生活中的大侠呢?呵呵,原因在这里:因为开发工作是邪门功夫,它虽然可以让你速成的变成小资,但它最大的特点是经验不积累!日新月异的知识更新,让 你总是感到自已在退步,你就像在RPG中的主人公,开始时就给了你一把好剑和好盔甲,而且让你的级别很高,但让你的经验不累积,虽然刚开始打小怪物时你觉 得自已很爽,但越到后来,你会发现你会死的很惨!比较一下你与其它非开发行业的同学你就可以知道了,例如和你学医的同学比起来。套用岳不群他老人家说华山 剑宗和气宗的区别那段话:前十年你比你那些学医的同学收入和地位要好的多,但十年以后你和他基本上各方面都会持平,而二十年以后你的各方面远远不能与你学 医的同学相提并论!嗯,你已经开始不笑辟邪剑法了吧。
“敢问路在何方?路在脚下…”,不过猴兄和八戒兄这么认为是可以的,你呢?
总结了许多开发朋友在30岁以后的生活之路,让我们一起看看开发人员“路在何方?”那么开发人员在30岁以后都干些什么呢?
其路一:继续做你这个很有“前途”的职业吧!
偶掰着脚指头仔细数了数,发现还真的有很多朋友在30岁以后还在从事开发工作,我这里说的从事,是指你还需要天天在电脑边上编程序和画电路板,与你手下 是否有几个小兵无关,也与你是否头上顶着什么项目经理、主任工程师的帽子无关,只要你还需要亲自开发,你就属于这一类。其中有个年龄最大的朋友是63年 的,从事医疗仪器的开发工作,35岁左右还在从事软硬件开发工作的仍有一大堆,分析这些仍然从事开发的朋友,基本上都有以下特点:
1 痴迷工作或者痴迷电脑,晚上八点到十二点的这段时间,基本上是在电脑桌或工作台前渡过的。
2 不喜欢与人交住,朋友很少,常联系的人不超过五个。
3 与朋友交往时谈工作多,但一般不主动谈钱。
4 体型偏胖或偏廋,不在正常区间。
5 无未来计划,对五年后自已生活怎么样、从事什么工作说不清楚。
6 俭省,从不乱花钱。
即使你是还不到30岁的开发人员,你也可以看看自己对以上几条是否符合,是否会在30岁后还从事开发职业,四条疑似,五条以上基本确诊你也是这类型的人。
这些朋友们通常报着过一天是一天的态度生活,到了这个年龄,也不敢再轻易的换工作了,年轻时的锐气慢慢的也消退了。唯一不变的希望是有一天从天上掉下来一 大堆钱把自己砸伤。说实在话因为他们的性格所限,基本上可以确定他们以后不可能在职场上获得更好的发展,当个小头头,带几个人开发已经是他们发展的顶点。 至于以后的人生之路,不仅他们自己迷茫,可能上帝也正在头痛。
不过像这类朋友,偶很奇怪的发现:他们的小孩都是儿子!不知是偶然还是有什么其它说法。
简单建议:要改变命运,先改变性格:坚持半年晚上不从事工作、游戏及电视,用此时间与人交往,你的人生会有改变。

其 路二:转行从事技术支持、行政或生产等工作还有一些朋友,从事了几年的开发工作,因为自已并非特别的爱好,或者领导上面的强制工作安排,他们转到了技术支 持、服务或行政等工作,至少当时从表面上看起来,他们的薪水较开发要少一些,但真正的统计这些人,发现他们之中有半数的人获得了更好的发展,升职为服务部 经理或行政经理等职,最历害的一个朋友已升职为总经理助理,进入高层。
这类朋友当时转行通常并非自已志愿,属被逼无奈或者其它原因,但显然,拥有专业知识技术的他们显然在非技术部门中鹤立鸡群,遇到什么事情他们均可从专业的角度提出建言,久而久之,他们获得更多的升职和加薪机会也就不足为奇。
因为不从事开发,所以经验开始积累,这类的职业通常会给你一个很安定的感觉,你到30多岁后会发现这类职业反而比开发工作更容易获得新的工作机会。

简单建议:你如果确定在开发部无法获得很好的发展机会,不妨转到其它几个部门试试,换个活法,钱少点就少点吧,机会多。
其路三:开发管理
如果你现在已经是总工或开发部经理,或者你眼看就有机会被提升为这类职务,那么恭喜你,你走的是从“弼马温”到“斗战胜佛”这条金光大路,你不仅拥有很 高的专业技能,而且很显然,你也有着很强的人际交往能力,你这类人根本不需要对未来有着任何的担心,你在即使一无所有的时候也很容易白手起家。
你这种人算是练辟邪剑法练成了仙,嗯,我无话可说。
你是不是这类人也很容易区别,就像围棋二十岁不称国手终身无望一样,你应该在工作三、四年以后,也就是说二十七岁左右就会发现自已工作中指手划脚的时间 比亲自开发的时间要多了,而且大多数这类人在这个年龄手下应该有“兵”了,相反的,如果你快30岁了还天天埋头于电脑前编程序和画板子,或者30多岁了你 还没升到部门经理(虽然你总是觉得自已很有希望),基本上可以确定你不是这类人。好了,如果你确定你是这类人,那么你唯一的想法就是尽快爬上中层和高层, 因为有时候人生偶然性太大,不占住坑的萝卜很有可能被人拔出来!

简单建议:天天去你的老板家里面拖地和擦桌子!

其路四:出国或考研
有两个搞开发后出国的朋友,其中一个甚至打工打到了一个小公司总工的位置,数据库和软件方面水平巨牛,但仍感觉心里不踏实,于是将自己工作多年的钱忍痛 掏出来,出国费加上机票大概将自已辛苦所攒的银子花完,然后又借了一些钱,在02年身上揣着一万美元跑去了加拿大,在加拿大不停的重复找工作,换工作,然 后再找工作的循环,找的工作基本上与计算机无关,不过工资总是在1500加元左右,呵呵,折成人民币与他在国内打工拿的基本上差不多,不过租个地下室就花 了300加元,然后吃吃喝喝,再买个电脑上上网这类的,基本每月平均还要倒贴一点。前段时间给我的邮件里说,现在身上花的差不多只有5、6000美元了, 准备开个小公司,看看能不能往国内倒腾点东东,做最后一搏。另外一个朋友去澳州,时间稍早一些,先是大概摘了一年多的葡萄,后来总算找了个技术工作,每天 的工作是画机械图纸,收入还算不错

将近3000澳元,买了个旧车,也算是过上了资本主义生活。不过前年回来一趟,唯一的感叹就是:在国外拿2000美元的生活,绝对不如在国内拿5000人民币的生活舒服。
也有两个考研的朋友,不过其中一个严格的说不是做开发的出身,偏重于市场方面的工作性质,不过我的朋友里面考研的不多,只好凑两个人说说,一个考研后在 北京找了个工作,每个月5、6000元钱,但还是做开发,生活仍然与没考研之前没有任何的改变,前途仍然没见到什么大亮的光,还是搞不清楚以后再干些什 么,标准的过一天算一天了。另外一个考研后在大学里面找了个工作,工资虽然比他原来打工少了不少,但毕竟终身有靠,稳定了下来,也算修成了正果,这位哥们 心情一放松下来,也开始有时间琢磨着业余时间自已做点什么,好像现在慢慢的也开始有了点眉目。
简单建议:这两条路,对开发人员来说都不算是很好,出国十年前是好事,现在难说,考研能成功转行的概率恐怕也不是很大,多半仍然去搞开发,只不过研究生可以多干几年罢了。

其路五:转行到市场
绞尽脑汁的想想,我所知道的人之中只有两个开发人员去了市场,这两个人都不能说是朋友,认识而已。他们都是主动要求去了市场,结果是这两个人均在市场都 是干到一年左右,然后都自已开公司了。呵呵,很奇怪,极高的转行成功率!不过仔细想想,我对这两个人的思路佩服的五体投地。能下决心仍掉每月5、6000 元的开发职位,从事一个自已并不熟悉的岗位,每月拿个2000多元+提成,但提成那是说不清楚的事情,这个决定,只能让人感觉到他们对自已前途清晰的把握 和老谋深算的心机。而且他们不去服务不去生产,挖空心思说服领导去市场(市场部门与开发部门通常是一个公司的核心部门,进入其实并不容易),可以说是有着 长远的考虑的。有技术了,再与客户交成朋友,马上就会产生很大的机遇应该是正常的事情。
有实力,有心机,也有着很强的决心力,这种人恐怕早在 大学毕业时或更早的时候就已经决定了自已的人生之路,他们的每一步路在若干年前早就计划周全,现在看起来:学会技术->进入市场->寻找商机->开公司, 一条多么清楚的人生之路。但就像我们上小学中学时,所有人都知道上大学是我们最清楚的人生路一样,最后只有少数人才能真正达到目标(当然,现在扩招的历害 是另外一回事,我是说我们那个时候,也就是:“很久很久以前,当我像你那么大的时候”)。

简单建议:你若是这类人,我的建议是:…嗯?….那个你.你,你别走啊,我还有个事想请你赞助一下啊…..

其路六:开公司自已干

呵呵,看到这一条,发现你的眼睛已经圆了,你肯定千百次的想过这个事情吧,咳咳,其实我从事开发的时候也是天天梦想着这种事情。总想着过两年找个机会就 自已干,这个梦想一年又一年的折磨着你也给着你希望。看看吧,开发后来开公司的还真的不少,里面有成功的也有很多失败的,通常开公司都是几个人合伙开始 的,有做技术的,有做市场的,几个人一拍即合、狼狈为奸,共同策划了这一个大活动。一般说来能让这几个人下决心走出这一步,产品肯定是先进的,甚至是国内 独一无二的,市场也是很大的,负责市场的那个哥们通常会拍着胸保证可以卖出去,并悄悄地告诉你他在某主管领导是他小舅子的同学的二叔,肯定没问题。于是你 们几个人找地点、注册执照、买了几个破桌子,再攒了两台电脑,每个人又凑了几万银子,公司开张了!
产品很快出来了,市场的哥们也不负重望,有几个客户表示要试用了,一切看起来都是如此的正常,“…….你坐在老板桌前,不停的有人来汇报工作或者找你签字…人进人出中…你又想起公司再穷也不能只有一把椅子的故事…..”你在梦中笑出声来。
是 如此的顺利,你们很快就有单子了,很快的单子让你们凑的那点钱不够了,你们很高兴的每个人又增加了投入,拿出钱时你眼泪汪汪的数着钱说:“这就是我那生蛋 的母鸡啊”。你们的产品确实不错,市场也经营的很好,客户慢慢的多了起来,单子来的时候一笔接着一笔,你每天都处于兴奋之中,唯一美中不足的是好像客户回 款总是会拖一些日子,不过客户给你保证说:过几天,过几天就付给你们,因为回款总是在计划外,所以你们为了资金的流畅运行又凑了一些钱,这个时候你有一些 心事了,因为你的存款折上面的数字已经快趋向于零了。“没事,过两个月等回款了一切都OK了,谁干事业不吃点苦呢?”你这么安慰着自已又投入到工作中去, 资金总是在回款和生产经营费用之间走着一个窄窄的小木桥,你的账上总是没有太多的钱,扩大了的公司规模和许多意外情况,使你又一次、二次、三次的与合作者 们再次投入了自已的资金,当然,后来的钱你可能已经是借的了…..
终于有一天,你的会计再一次告诉你,老板啊,账上又没现金了,吃过多次 苦头的你终于下决心开始重视资金的运行了,你裁掉了一些不必要的人手,减少了开发的投入,要求市场人员签单的时候必须予付XX%的款,回扣也必须等收过款 后再付,同时也开始对产品的生产成本开始进行控制。
时间一天一天的过去,因为竟争对手的产品也对你的产品进行了仿造,你的产品慢慢变得不再先进,市场人员开始埋怨公司的合同资金方面规定太严格,不好签单,生产成本的下降通常也导至产品毛病的增多,客户也开始埋怨你的服务人员不能及时进行服务。
终于有一天,你重新走进了人才交流中心,以前你是来招人的,现在你拿着自已的简历开始寻找一个工作
……
公司的成功与否,与产品有关,与市场有关,但更重要的是与资金有关,产品与市场都可以通过资金来弥补,而却没有任何东西可以代替

资 金,凡是倒下的公司,99%与资金链的断裂有关。在你决定要开公司以前,先估计一下你公司支持一年所需要的资金数额,包括人工费,生产,场地,广告宣传、 市场费用、甚至电、水费等等等等,把你所想到的一切加在一起,得出的值就是..慢..如果你没有实际的开过公司的经验,你需要将此数字乘3,然后就是你开 公司一年最少需要的费用,呵呵,公司的实际运营所需要的钱是你想像的3倍以上,你要是不信我也没办法。

简单建议:开公司前最重要的是先确立你后续的资金来源!也就是说钱不够了怎么办?---因为你投入的钱肯定会不够的。

其路七:第二职业
这 类的朋友有不少,他们没有脱离开发工作,但是在业余时间又不停的接项目或者在卖产品,在单位里面他们显得并不出众,比起其它人来说他们属于最不愿意加班的 一类.为此他们白天通常工作很勤奋.这类人也许不一定可以挣很多钱,但平均下来他们一年之中通常都可以比同事们多挣个几万元.有时候比上班拿得还多.但令 人疑惑的是,这类人在生活中更加注重稳定,基本上没见到他们跳过蹧,即使私下里面已经开了个小公司,他们通常也不会辞职.
你的旁边有没有这类人呢?分辨他们很容易:
— 电话很多,而且更愿意来电话时离开办公室找个没人的旮旯通话.神秘兮兮给人一种”这家伙是不是有二奶啊?”的感觉的人,通常是这类人。这类人是女性最佳的 选择对象:很顾家,不象那些富人容易花心,而比起一般人来说,他们收入相对要高得多。但总结了一下几位这类的开发朋友:也得出了一个令人沮丧的结论:这种 人通常个子不高,体形类似桶状…..

简单建议:这好像是开发人员最佳的出路了,但比较丰厚的收入通常让这类人不愿意去冒风险….到现在为止我所认识的这类人还没有一个真正算是成功的。
好了,虽然偶的经历远远说不上丰富,也没有什么成功之处可以自满的,但或许因为比其它朋友痴长了几岁,见过的人可能会稍多一些,所

以斗胆写出了以上的一些文字,让您掉牙了。
下面是偶走过开发这条路上总结出来的一点心得,你可以不看,但看了就千万别把嘴咧的太大:
一、 不管是给别人打工还是自已干,都要全心全意的工作,因为你所做的任何一点工作都会让自已的人生多一点筹码,这一点最最重要!这样的例子我至少可以举出两 起,优秀的开发人员被其它新公司挖走,并给一定的股份,成为新公司的股东的例子。当时与这样的开发人员一个部门同时工作或更早工作的有许多人,他们平时经 常偷点懒,能少干点工作就少干点,有时候还笑话那个平时努力工作的人傻,几年过去了,究竟谁比谁傻?
二、多与市场人员交朋友,你接触他们时可能总会觉得他们知识比你少,甚至素质比你低,可能比你还有点黄。但实际上他们比你更懂这个社会!参加到他们这个圈子中去,和他们一起赌赌钱、一起聊聊天、一起洗洗桑拿、一起…..你会通过他们接触到另外一个世界。
三、 机会远比钱重要,挣不挣钱在年轻时并不是特别重要!不论是在实际生活中还是在网上或其它地方,如果有机会参与到除本职工作外的一些项目或产品的开发中(包 括你的朋友拉你去做点小生意之类的非开发性质的工作),那怕是帮忙的性质,也要积极介入,至少你会交到很多的朋友,这样你的人生会多出很多的机会。

[转载]为VS2008默认模板添加版权信息

mikel阅读(950)

[转载]为VS2008默认模板添加版权信息 – SpongeNet – 博客园.

在公司做项目的时候常常会被要求在代码的最上面加入版权信息,如果手工粘贴复制岂不累死?于是乎偷懒秘籍如下,仅供分享!

1. 打开路径 D:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\ItemTemplates\CSharp(D盘为我的VS安装盘符)。

这个路径下为C#的添加项项模板。

如果你要修改类与接口的模板那么Code文件夹中就是你所需要的。进入Code文件夹中,在进入2052文件夹,会看到很多模板

其中Class.zip压缩包是类模板,InterFace.zip是接口模板,下面我们以接口模板为例修改模板

双击打开压缩包,不要解压。然后双击InterFace.cs, IDE会自动启动打开文件

现在在IDE中修改文件加入我们的版权信息,然后保存

这时WinRAR会提示你是否更新压缩包中的文件,选择是.

如果这时你有打开的IDE请关闭它们,然后在VS2008的Visual Studio 2008 命令提示中运行devenv.exe /InstallVSTemplates 命令

然后等待进程devenv.exe结束就完成了,祝你成功O(∩_∩)O哈哈~