javascript join()方法

join()方法将数组中的所有元素转换成字符串,然后连接起来,这刚好和String的split()方法是一个相反的操作。

join()默认是使用“,”作为分隔符,当然你也可以在方法中指定分隔符。

    var strHtml = [];
    strHtml.push('
'); strHtml.push('
    '); strHtml.push('
  • 请选择邮箱后缀
  • '); strHtml.push('
  • '); strHtml.push('
  • '); strHtml.push('
  • '); strHtml.push('
  • '); strHtml.push('
  • '); strHtml.push('
'); strHtml.push('
');

使用strHtml.join()输出结果为:

"
,
    ,
  • 请选择邮箱后缀
  • ,
  • ,
  • ,
  • ,
  • ,
  • ,
,
"

使用strHtml.join(”),即分隔符为空,则输出结果为:

"
  • 请选择邮箱后缀
"

javascript replace() 方法

replace() 方法用于在字符串中用一些字符替换另一些字符,或替换一个与正则表达式匹配的子串。

语法:stringObject.replace(regexp/substr,replacement)

参数和描述:
regexp/substr 必需。规定子字符串或要替换的模式的 RegExp 对象。请注意,如果该值是一个字符串,则将它作为要检索的直接量文本模式,而不是首先被转换为 RegExp 对象。
replacement 必需。一个字符串值。规定了替换文本或生成替换文本的函数。ECMAScript v3 规定,是函数这种情况下,每个匹配都调用该函数,它返回的字符串将作为替换文本使用。

返回值:一个新的字符串,是用 replacement 替换了 regexp 的第一次匹配或所有匹配之后得到的。

js中的repalce替换默认只替换一次(个),多次替换后面加g,i是大小写匹配。是特殊字符用到前面加/。

例一:
var str = ‘Mary had a little lamb.’;
str = str.replace(‘lamb’,’dog’);

Results:
str = ‘Mary had a little dog.’;

例二:
var str = ‘Good dog, good dog.’;
str = str.replace(‘Good’,’Bad’);

Results:
str = ‘Bad dog, good dog.’;

例三(不区分大小写):
var str = ‘ALL CAPS.’;
str = str.replace(/caps/i,’lower-case’);

Results:
str = ‘ALL lower-case.’;

例四(全局替换):
var str = ‘Good dog. Good dog.’;
str = str.replace(/Good/g,’Bad’);

Results:
str = ‘Bad dog. Bad dog.’;

例五 (全局替换,不区分大小写)
var str = ‘GOOD dog. GOOD dog.’;
str = str.replace(/good/gi,’Bad’);

Results:
str = ‘Bad dog. Bad dog.’;

javascript根据传递值改变页面背景

需求:根据传递的gametype值,切换显示不同游戏的背景。不存在的值,显示默认游戏。gametype值为ab-dd/ab-cd-dd/ab-dddd/ad-cd-dddd等。
分析特点:游戏类型最后是以“-”加游戏简写组成,简写对应相应的class。
思路:得到游戏简写去游戏名称中查找,若存在则修改body的class,不存在设为默认的class。

实现过程又温习了一遍js关于字符串的操作。以下是用到的javascript方法:

indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置。如果要检索的字符串值没有出现,则该方法返回 -1。
lastIndexOf()方法可返回一个指定的字符串值最后出现的位置,在一个字符串中的指定位置从后向前搜索。如果要检索的字符串值没有出现,则该方法返回 -1。
substring() 方法用于提取字符串中介于两个指定下标之间的字符。
toLowerCase() 方法用于把字符串转换为小写。

代码如下:

// 根据gameType修改相关页面值
function loadBackground(gametype){
  var game_list = "aa,bb,cc,dd,ee,ff,gg,jj,hh,jj,hh,ii,jj,kk,ll,mm,nn";
  var body_class = (gametype.substring(gametype.lastIndexOf("-") + 1,gametype.length)).toLowerCase();
  var is_class = game_list.indexOf(body_class);
	if(gametype=='' || is_class == -1){
		document.getElementsByTagName('body')[0].className = 'aa';//默认
		return;
	}else{
    document.getElementsByTagName('body')[0].className = body_class;
  }
}

使用正则表达式来得到游戏简写代码如下:

// 根据gameType修改相关页面值
function loadBackground(gametype){
  var game_list = "aa,bb,cc,dd,ee,ff,gg,jj,hh,jj,hh,ii,jj,kk,ll,mm,nn";
  var regex=/(.*)+-/;
  var body_class = (gametype.replace(regex,"")).toLowerCase();
  var is_class = game_list.indexOf(body_class);
	if(gametype=='' || is_class == -1){
		document.getElementsByTagName('body')[0].className = 'aa';//默认
		return;
	}else{
    document.getElementsByTagName('body')[0].className = body_class;
  }
}

为什么要使用“闭包”?

闭包是 JavaScript 一个非常重要的特性,意味着当前作用域总是能够访问外部作用域中的变量。

我已经讨论过这个概念,在“ this 是什么?”这篇文章中。在那篇文章中,我解释范围和上下文。

今天,我想介绍一下基于事件的编程中闭包的一些实际用途。以及比较其他的方法,如面向对象的事件调用之间保持状态。

什么是闭包?

引用维基百科的话:

在计算机科学中,闭包(Closure)是词法闭包(Lexical Closure)的简称,是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。

或者我的方式直观地理解它:

闭包是一个在内部作用域中定义的函数(内部函数),它能够访问其外部作用域中的所有变量。

使用闭包隐藏状态

看下面这段代码:

function greet(message) {
  console.log(message);
}

function greeter(name, age) {
  return name + ", who is " + age + " years old, says hi!";
}

// Generate the message
var message = greeter("Bob", 47);

// Pass it explicitly to greet
greet(message);

输出:
Bob, who is 47 years old, says hi!

这很简单,如果不需要其他功能。还有什么需要一些其他的数据传递功能,你会改变一切,传递更多的变量。显然,必须有一个更好的办法。

使用闭包后的代码:

function greeter(name, age) {
  var message = name + ", who is " + age + " years old, says hi!";
  return function greet() {
    console.log(message);
  };
}

// Generate the closure
var bobGreeter = greeter("Bob", 47);

// Use the closure
bobGreeter();

输出:
Bob, who is 47 years old, says hi!

提示:greet 在 greeter 中,形成一个闭包,意味着它只在这个函数内有效,可以访问到外部作用域中的变量姓名和年龄。

使用闭包而不是对象

很多写JavaScript的人是有经验的程序员,来自其他语言类和实例的共同的方式来处理这种封装。
JavaScript也有类似的构造函数和函数原型的形式。

经典的面向对象javascript

// Define the constructor
function Person(name, age) {

  // Store the message in internal state
  this.message = name + ", who is " + age + " years old, says hi!";

};

// Define a sync method
Person.prototype.greet = function greet() {
  console.log(this.message);
};

// Define a method with async internals
Person.prototype.slowGreet = function slowGreet() {
  var self = this; // Use a closure to preserve `this`
  setTimeout(function () {
    console.log(self.message);
  }, 1000);
};

// Export this file as a module
module.exports = Person;

这样来使用它

var Person = require('./personclass');
var bob = new Person("Bob", 47);
bob.greet();

这是一个很好的模式,很多成功的项目都使用了它。

使用闭包的对象工厂

// Define the factory
function newPerson(name, age) {

  // Store the message in a closure
  var message = name + ", who is " + age + " years old, says hi!";

  return {

    // Define a sync function
    greet: function greet() {
      console.log(message);
    },

    // Define a function with async internals
    slowGreet: function slowGreet() {
      setTimeout(function () {
        console.log(message);
      }, 1000);
    }

  };
}

// Export this file as a module
module.exports = newPerson;

这样来使用它:

var newPerson = require('./personfactory');
var tim = newPerson("Tim", 28);
tim.greet();

我很喜欢!需要注意:虽然这种方法很容易使用,当你创建大量实例时,它运行的不好。
因为,每一个实例将在自己的版本中创建一个函数对象。

闭包的事件和回调

function handle() {
  console.log(message);
}

function setAlarm(message, timeout) {
  setTimeout(handle, timeout);
}

setAlarm("Wake UP!", 100);

这样是有错误的,因为信息是不确定的,它是一个本地变量,在setAlarm的功能外,不存在。
所以,我们需要定义的处理函数内的setAlarm功能。

function setAlarm(message, timeout) {

  // Define handle in the closure
  function handle() {
    console.log(message);
  }

  setTimeout(handle, timeout);
}

setAlarm("Wake UP!", 100);

这样才是对的。

正如在“this是什么?”的文章,尤其是在处理回调的时候是令人不快的。
这是因为指定的对象的方法作为回调函数,会造成本身的功能是回调,而不是与它相关联的对象。

var Person = require('./personclass'),
    newPerson = require('./personfactory');

var bob = new Person("Bob", 47);
var jake = new Person("Jake", 17);
var tim = newPerson("Tim", 28);

setTimeout(bob.greet, 100);
// Outputs: undefined

setTimeout(tim.greet, 100);
// Outputs: Tim, who is 28 years old, says hi!

// With `this` based objects you have to manually bind the function
// This works
setTimeout(function () {
  jake.greet();
}, 100);
// Outputs: Jake, who is 17 years old, says hi!

有趣的事是,函数是JavaScript第一类值。这个上下文可以帮助设计经典的面向对象的API,但你要记住,这只是分配函数调用,它不是一件关乎本身的功能。变量的闭包,就是函数本身的一部分,无论如何它叫什么。

原文地址:http://howtonode.org/why-use-closure
感谢:@李松峰 @张鑫旭
参考:http://zh.wikipedia.org/wiki/%E9%97%AD%E5%8C%85_%28%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6%29

生成script,判定加载,解决统计问题

需求是添加一个统计代码,用于统计用户注册量。而用户注册是能过ajax方法实现的,实现思路是在判断用户注册成功后,访问一下统计地址。

最初实现过程中,在head区生成一个script标签,这样产生一次访问。但是后来发现统计不上,原因是用户注册成功后,就跳转了。可能跳转的时候,标签还没有生成完毕。

在解决的过程中,欲改用jQuery的$.ajax方法,来产生一次请求。代码如下:

$.ajax({
    url: 'http://www.k68.org/t?p=1&q=1',
    success:function(data){
        //后续操作
    }
});

但是遇到ie下jquery跨域错误提示。又改退回第一种实现方式,在判断生成的script加载(load)后,再执行后续代码,最终解决了问题。

代码如下:

//在注册成功时调用
X.loadScript('http://www.k68.org/t?p=1&q=1', function() {
	//后续操作
}

//调用生成script标签
X.loadScript:function (url,callback){
    var head = document.getElementsByTagName('head')[0];
    var script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = url;
    script.onload = script.onreadystatechange = function(){
        if((!this.readyState || this.readyState === "loaded" || this.readyState === "complete")){
            callback && callback();
            // Handle memory leak in IE
            script.onload = script.onreadystatechange = null;
            if ( head && script.parentNode ) {
                //head.removeChild( script );
            }
        }
    };
    // Use insertBefore instead of appendChild  to circumvent an IE6 bug.
    head.insertBefore( script, head.firstChild );
}

在同事和对方技术的配合下解决了问题,记录于此,深表谢意。

参考:
http://www.7hihi.com/?p=275
http://www.hujuntao.com/archives/javascript-dynamic-loading-the-script-function.html
http://wxianfeng.com/2009/12/10/jquery-ie-no-permission

理解基于原型的javascript语言

一句话:我们只需要知道”用对象去创建对象”,就可以在原型的世界里大行其道了!

对象创建:

1. 使用”原型对象”作为”模板”生成新对象

2. 初始化内部属性

使用:Object.create创建新对象。ECMAScript5中已经新增了此特性,如果不存在可以使用如下方式来创建。

/** 
 * 以原型对象为模板创建出新对象 
**/

if(!Object.create){
    Object.create = function(o){
        function F(){};
        F.prototype = o;
        return new F();
    }
}

基于原型的语言是以原型对象为模板创建对象newObject = create(oldObject)。对象会通过原型链动态地查找属性,对象的所拥有的属性并不是静态的。

Object.create 函数 (JavaScript)

创建一个具有指定原型且可选择性地包含指定属性的对象。

Object.create(prototype, descriptors)

参数:

prototype 必需。要用作原型的对象。 可为 null。
descriptors  可选。包含一个或多个属性描述符的 JavaScript 对象。

返回值:

一个具有指定的内部原型且包含指定的属性(如果有)的新对象

注:
1、instanceof为判断一个对象是否为某一数据类型,或一个变量是否为一个对象的实例;返回boolean类型
2、javaScript中isPrototypeOf函数方法是返回一个布尔值,指出对象是否存在于另一个对象的原型链中。

参考:
http://www.iteye.com/topic/1126635
http://technet.microsoft.com/zh-cn/query/ff925952

javascript表单末项回车调用验证函数

一般的快速注册表单都绑定了回车提交事件,一般用户在填写到表单最后一项时,会敲回车进行表单提交。

遇到一个问题就是末项的验证是鼠标离开事件时发生,这个时候当末项的输入不能通过验证,敲回来时,验证提示出不来。表单也没有提交出去,体验很差。

一个简单一点的解决方法,就是侦听末项的回车事件,调用blur事件的验证,去进行后续验证,提交表单操作。

代码如下:

	
        //注册确认密码验证
	$("#reg_repassword").bind("keyup",function(event){
		 if(event.keyCode==13){
    		$("#reg_repassword").blur();
    	}
	});

	$("#reg_repassword").bind("blur",function(){
		var cn = $("#reg_cn").val();
		var pwd = $("#reg_password").val();
		var pwd2 = $("#reg_repassword").val();
		var pwd2_tip = $("#reg .tips").eq(2);
		var pwd2_tipContent = $("#reg .tips").eq(2).find("span");
		var result = Verify.validatePwd(cn,pwd2,type[2]);
		var flag = (pwd == pwd2);
		if(result[0]){
			$(pwd2_tip).addClass('hidden');
		}else{
			$(pwd2_tip).removeClass('hidden');
			pwd2_tipContent.text(result[1]);
		}

		//判断是否存在后,如果值不相等,提示
		if (pwd && pwd2){
			var flag = (pwd != pwd2)
		}
		if(flag){
			$(pwd2_tip).removeClass('hidden');
			pwd2_tipContent.text(errTip.Msg['pwd_different']);
		}
	})

解决由ie6事件引起的页面无响应问题

处理一个文本框验证,验证逻辑为:文本框获得焦点时,保存按钮点亮;文本框失去焦点时,验证格式,格式不对时,显示错误信息,保存按钮置灰,格式正确进行保存验证。

问题描述:

在ie6下,当鼠标离开文本框,验证错误时,点击保存按钮,页面无响应,其他浏览器正常。

解决流程:

初步判定为ie6事件问题,当发生blur事件时,保存按钮应为不可点。但是有了保存事件,此时又验证到blur事件,又变回了不可点的状态,导致事件混乱,出现问题。
确定问题后,进行解决。
1、增加标识符判断,在离开文本框时添加状态符。在表单提交验证时,根据状态符进行后续操作,若为false时,不执行保存事件。
2、在验证不通过发生时,使用setTimeout进行延时处理,解决ie6执行顺序问题。

延时代码:

viewErr : function(subBut, dl, msg){
    setTimeout(function(){
        if(subBut) subBut.attr('disabled',"disabled").addClass('disabled');
        dl.find('p.t').hide();
        dl.find('p.e').html(''+msg).show();
    }, 500);
},

设置标识符:

input.blur(function(){
    suc = false;
    var in_text = input.val();
    var sum = NJS.textL(in_text);
    if (sum > 0 && iName != 'signature' && !NJS.isText(in_text)){
        that.profileUtil.viewErr(subBut, dl, errorTips[iName][1]);
    }else if(minL && sum >= 0 && sum < minL){
        //姓名过短的错误提示
        that.profileUtil.viewErr(subBut, dl, errorTips[iName][2]);
    }else if(sum > maxL){
        //姓名过长的错误提示
        that.profileUtil.viewErr(subBut, dl, errorTips[iName][0]);
    }else{
        suc = true;
    }
});

//表单提交的校验
form.submit(function(){
    if(!suc){
        return false;
    }
}

chorme生成的select和firefox/ie的顺序相反

问题:做年份的的下拉列表(倒序)时遇到在chorme生成的select和firefox/ie的顺序相反。

测试发现,chorme对for in的执行顺序和firefox不同

var o = {'2011':'2011年','2010':'2010年'};
var b = [];
for(var i in o){
    alert(i);
    b.push('' + o[i] + '');
}

firefox输出2011/2010
chorme输出2010/2011

原因:
ECMAScript第三版中描述,for-in 语句的属性遍历的顺序是由对象定义时属性的书写顺序决定的。
ECMAScript第五版规范中,对 for-in 语句的遍历机制又做了调整,属性遍历的顺序是没有被规定的。
Chrome Opera 的 JavaScript 解析引擎遵循的是新版 ECMA-262 第五版规范,而 IE6 IE7 IE8 Firefox Safari 的 JavaScript 解析引擎遵循的是较老的 ECMA-262 第三版规范,对属性的遍历顺序存在不一致的问题。

解决方案:
for-in语句无法保证遍历顺序,应尽量避免编写依赖对象属性顺序的代码。如果想顺序遍历一组数据,请使用数组并使用for语句遍历。

//存储时保存为对象的同时,建立一个数组存储
function array2Obj(s, e, str){
	var o = {};
	var a = [];
	str = str || '';
	var j = 0;
	for(var i = s; i <= e; i++){
		a[j] = i;
		o[i] = i + str;
		a[j++];			
	} 
	return [o,a];
}


//a 用于对显示顺序有要求的情况,a为key数组
function options(o, d, a){
	var b = [];
	var i;
	if(a){
		for(i = 0; i < a.length; i++) bp(a[i], o[a[i]]);  //100   a[i]=2011 o[a[i]]=2011年  a[0]=2011  o[a[0]]=2011年 
	}else{
		for(i in o) bp(i, o[i]); //2011 2011年..  2010 2010年 
	}
	function bp(k, v){
		b.push('');
	}
	return b.join('');
}

参考:
http://www.w3help.org/zh-cn/causes/SJ9011
http://mbn.iteye.com/blog/999204

Javascript设置下拉框默认选中项

以下函数的功能是,根据传入index设置下拉框默认选中项。

var region = $('#sel_prov').get(0);
setSelectIndex(region,currentRegion);
	function setSelectIndex(selectItem,index){
		for(i=0; i < selectItem.length;i++){
			if(selectItem.options[i].value == index){
				selectItem.options[i].selected = true;
			}
		}
	}

//options是个数组,里面可以存放多个<option value=”值”>文本</option>这样的标签

options[ ]数组的属性:

length属性:长度属性
selectedIndex 属性:可设置或返回下拉列表中被选选项的索引号。索引号从0开始,注意不是value的值。(若允许多重选择,则仅会返回第一个被选选项的索引号)

单个option的属性:

selected属性:返回/指定该对象是否被选中.通过指定 true 或者 false,可以动态的改变选中项。
text属性:返回/指定文本
value属性:返回/指定值,与一致。
index属性:返回下标。