博客

闭包

1) 返回值。在JS引擎中,所有的语法,操作都有返回值,而且通常返回值是它本身或undefined。通常我们可以用”()”操作符,来获取当前句子的返回值(部分操作符不能用,如var)。例如:a=3;其实这行的返回值就是3,所以在a=b=3时,JS引擎就可以正确的执行下去,首先3赋值给b,然后当前的返回值3再赋值给a(而不是大家所认为的,先将3赋值给b,然后再将b赋值给a)。又例如函数var fun=function(){},当JS引擎执行到这行时,会先执行右边,返回值是一个函数的字面量,然后将这个函数字面量赋值给fun。
Jquery也是利用了这个特性(函数return this),所以才有链式调用。我们看个例子:”fontFamily”.replace( /([A-Z])/g, “-$1″ ).toLowerCase(),没错这里也是利用了返回值,所以这行的结果是:font-family。
2) 闭包。子函数调用父函数的变量(非传参),就是闭包。在JS中,子函数能访问父函数的变量,这时被引用的变量不会释放,而且子函数中能一直持有这个变量的引用。
结合以上两大特点,可以生成一个力量强大的怪胎:
[code lang=”js”](function(){})();[/code]
不知道专业的名称,我叫它为:立即执行匿名函数。
首先在第一对括号内,是一个匿名函数,第二个括号会立即调用这个匿名函数的返回值,也就是匿名函数中的内容被立即执行。
这个怪胎的强大在于,它独立了一个作用域(括号中内容执行完后会被立即回收),内部变量外部无法访问,而它又能通过this保留字,来访问外部变量。
[code lang=”js”]
var i = 100;
(function() {
var j = 1;
this.plus_ij = function() {
j += i;
alert(j);
}
})
();
plus_ij();
plus_ij();
plus_ij();
//j只会执行一次,但是匿名函数执行后,还会保留j
(function() {
var aa = 1;
var bb = 2;
var a = function() { aa += i;
console.log(aa) }

function b() { bb += i;
console.log(bb) }
this.c = function() { a();
b(); }
})();
c();
c();
[/code]

canvas浏览器兼容性检测

在不兼容的情况下,尽量使用可代替的方法来实现相同功能

[code]
<canvas id="canvas" style="display: block;margin:0 auto;">
请使用高版本的浏览器!
</canvas>

<script>
var canvas = document.getElementById("canvas");
canvas.width = 800;
canvas.height = 800;
var cantext = canvas.getContext(‘2d’);
if(context.ellipse){
context.beginPath();
context.ellipse(400,400,300,200,0,0,Math.PI*2);
context.stroke();
}else{
alert("no ellipse");
}
</script>
[/code]

使用Canvas交互和isPointInPath

本节最大的理解就是:canvas绘制图形,最关键的就是“重新绘制”,配合time和事件,就可以做出来各种效果

[code lang=”js”]
//clearRect对指定区域执行清除
//isPointlnPath(x,y) 检测是否在区域内
function canvass23(context,canvas) {
var balls=[];
for(var i =0;i < 10;i++){
var aBall = {x:Math.random()*canvas.width,y:Math.random()*canvas.height,r:Math.random()*50+20};
balls[i] = aBall;
}
draw();
canvas.addEventListener(‘mouseup’,detect);

//首先绘制图形
function draw(){
for(var i =0;i<balls.length;i++){
//context.save();
context.beginPath();
var R = Math.floor(Math.random()*255);
var G = Math.floor(Math.random()*255);
var B = Math.floor(Math.random()*255);
context.fillStyle = "rgb(" + R + "," + G + "," + B + ")";
context.shadowColor = ‘#058’;
context.shadowOffsetX = 10;
context.shadowOffsetY = 10;
context.shadowBlur = 0.9;
context.arc(parseInt(balls[i].x),parseInt(balls[i].y),parseInt(balls[i].r),0,2*Math.PI,false);
context.arc(balls[i].x,balls[i].y,balls[i].r/2,0,2*Math.PI,true);
context.fill();
//context.restore();
}
}
//事件触发函数
function detect(event){
var x = event.clientX – canvas.getBoundingClientRect().left;
var y = event.clientY – canvas.getBoundingClientRect().top;
for(var i =0;i<balls.length;i++){
context.save();
context.beginPath();
context.shadowColor = ‘#058’;
context.shadowOffsetX = 10;
context.shadowOffsetY = 10;
context.shadowBlur = 0.5;
context.arc(balls[i].x,balls[i].y,balls[i].r,0,2*Math.PI,false);
context.arc(balls[i].x,balls[i].y,balls[i].r/2,0,2*Math.PI,true);
if(context.isPointInPath(x,y)) {//判断位置后,再次绘制
context.fillStyle = ‘red’;
context.fill();
}
context.restore();
}
}
}
[/code]

js判断是否是ie

[code lang=”js”]
<script type="text/javascript" language="JavaScript">// <![CDATA[
if ((navigator.userAgent.indexOf(‘MSIE’) >= 0)
&& (navigator.userAgent.indexOf(‘Opera’) < 0)){
alert(‘你是使用IE’)
}else if (navigator.userAgent.indexOf(‘Firefox’) >= 0){
alert(‘你是使用Firefox’)
}else if (navigator.userAgent.indexOf(‘Opera’) >= 0){
alert(‘你是使用Opera’)
}else{
alert(‘你是使用其他的浏览器浏览网页!’)
}
</script>
[/code]

ajax分析

原生js实现

//兼容ie6
[code lang=”js”]
var request = new XMLHttpRequest() || new ActiveXObject("Microsoft.XMLHTTP");
request.open("GET","get.php",true);
request.setRequestHeader("Content-type","application/x-www-form-urlencoded");
request.send();//post必须要写参数
request.onreadystatechange = function(){
if(request.readyState === 4&& request.status === 200){
//做一些事情 request.responseText,字符串形式
request.responseXML,xml形式
status和statusText,数字和文本形式返回HTTP状态码
getALLResponseHeader(),查询响应某个字段的值
}
}
[/code]

jquery实现

[code lang=”js”]
$.ajax({
type: "post",
contentType: "application/json; charset=gb2312",
url: ‘http://event.zygames.com/qqsm2/201501/weibo/AddLight’,
dataType: ‘jsonp’,
jsonp:’jsonpCallback’,
data: {"AreaID":AreaID},//传入AreaID
async: true,
success:function(data){
}
});
[/code]

跨域处理:
1、代理跨域(实际上是出后端备份到同一域名下)
2、jsonp只支持get请求
3、html5提供的XHR2(只支持ie10以上)
header(‘Access-Control-Allow-Origin:*’);
header(‘Access-Control-Allow-Methods:POST,GET*’);

JQUERY实现点击INPUT使光标移动到最后或指定位置

//光标放在最后 $(“#文本框ID”).textFocus();光标放在第二个字符后面 $(“#文本框ID”).textFocus(2);

[code lang=”js”]
(function($){
$.fn.textFocus=function(v){
var range,len,v=v===undefined?0:parseInt(v);
this.each(function(){
if($.browser.msie){
range=this.createTextRange();
v===0?range.collapse(false):range.move("character",v);
range.select();
}else{
len=this.value.length;
v===0?this.setSelectionRange(len,len):this.setSelectionRange(v,v);
}
this.focus();
});
return this;
}
})(jQuery);

//光标定位函数
//textFocus(obj,val)
(function(){
this.textFocus = function(dom,c) {
var _this = dom;
var range, len, v = c === undefined ? 0 : parseInt(c);
if ((navigator.userAgent.indexOf(‘MSIE’) >= 0) && (navigator.userAgent.indexOf(‘Opera’) < 0)) {
range = _this.createTextRange();
v === 0 ? range.collapse(false) : range.move("character", v);
console.log(v);
range.select();
} else {
len = _this.value.length;
v === 0 ? _this.setSelectionRange(len, len) : _this.setSelectionRange(v, v);
console.log(v);
}
}
})();

[/code]

Javascript 链式作用域(JavaScript中的函数运行在他们被定义的作用域里,而不是他们被执行的作用域里。)

JavaScript中的函数运行在他们被定义的作用域里,而不是他们被执行的作用域里。

其实对于Javascript链式作用域的描述,包括,JS权威指南,都有些太冗长了–但是很准确:JavaScript中的函数运行在他们被定义的作用域里,而不是他们被执行的作用域里。

这句话有点难懂,但程序的设计,基本都是为了简单,便于理解的。记住JS中经典的一句话是,一切皆对象。

说白了链式作用域,其实就是Javascript的一个特性:子函数中可以访问父函数的所有变量。当然也包括全局变量window(一般的函数定义function a(){},其实都是window对象的子函数)。另外补充一下,函数定义有两种方式,其实略有差别:var a=function(){}和function a(){},稍后再解释他们的区别。

所以,我们看Crockford的<<Javascript语言精粹>>中就提到,要在一个函数中定义变量,要养成良好的习惯,请直接在函数开头定义变量。JS中这点上有别于其它语言的要求—-尽量推迟变量定义(使用前定义)。

我们看一下laruence提供的例子:

var name = ‘laruence’;
functionecho(){
alert(name);
var name = ‘eve’;
alert(name);
alert(age);
}

echo();
这个例子其实很有迷惑性(会让人错误的以为,输出结果是:laruence,eve,error;其实结果是:undefined,eve,error),关键就是因为echo()函数中定义的var name=’eve’。但其实换个写法,这个例子就很清楚了:

var name = ‘laruence’;
function echo() {
var name;
alert(name);
name = ‘eve’;
alert(name);
alert(age);
}

echo();
其实,上面的函数在JS引擎解析的时候,就会被解析成这样。如果你是初学者,其实这样理解就可以了。但如果你有别的程序的编程经验,例如java。就很容易被惯用思维给套住了,PS:本人就是给套住的一个。所以,还是按照Crockford的建议把,定义变量,请在函数顶部!!

 

还记得之前的问题吗? var a=function(){}和function a(){}的区别。

它们的区别还变量的定义比较类似。一切皆对象。

他们两个在函数调用时,基本是等价的,但如果调用函数,在定义函数前就会有问题了。其实区别在于等号和function关键字。

var和function定义在预编译的时候被提前,var只是占位,具体赋值要等到JS引擎执行到这行。而function定义会在JS引擎预编译阶段就被直接放入到调用对象中。

还是要举例:

例子一:

alert( echo );//function echo(){return 1;};
function echo(){return 1;};
alert( a );//undefined

var a=function(){return 1;};

所以,函数的定义也可以引申出一句话,请将函数定义放在顶部(先定义后调用)!!

其实还是习惯的问题,JS中一些代码的优良习惯有别于其它语言。建议大家读一下<<Javascript语言精粹>>。在开始学习一门语言时,最好从欣赏优秀的代码开始。而JS中,大家都喜欢用一系列充满迷惑性的代码来加深自己的理解,这其实是一个误区。

另外说一点,this关键字,laruence的解释很简洁到位:”谁调用,谁就是this”。英文版更详细一点:“In JavaScript this always refers to the “owner” of the function we’re executing, or rather, to the object that a function is a method of. ”,中文解释:“在JavaScript中,this永远引用我们所执行函数的拥有者,更准确的说,this引用一个函数的方法对象”

看看下面的例子,也是误导人的:

function a(){
g_value=”uk”;
}
a();
alert(g_value);

其实,比较友好的写法应该是这样:

 

function a(){
this.g_value=”uk”;
}
a();//a.apply(this);
alert(this.g_value);
关于this关键字,和别的语言也有区别。首先它并不是实例的引用,而是调用它的上下文。上面例子的a(),等价于a.apply(this);

call和apply的用法是一样的,区别就在参数传递上。一个是一个一个传参数的,一个是将参数作为类数组传递的(注意这个地方是类数组)。

判断移动设备的浏览器版本

function checkBrowser(){
var browser={
versions:function(){
var u = navigator.userAgent, app = navigator.appVersion;
return {
//移动终端浏览器版本信息
trident: u.indexOf(‘Trident’) > -1, //IE内核
presto: u.indexOf(‘Presto’) > -1, //opera内核
webKit: u.indexOf(‘AppleWebKit’) > -1, //苹果、谷歌内核
gecko: u.indexOf(‘Gecko’) > -1 && u.indexOf(‘KHTML’) == -1, //火狐内核
mobile: !!u.match(/AppleWebKit.*Mobile.*/)||!!u.match(/AppleWebKit/), //是否为移动终端
//ios: !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/), //ios终端
android: u.indexOf(‘Android’) > -1 || u.indexOf(‘Linux’) > -1, //android终端或者uc浏览器
iPhone: u.indexOf(‘iPhone’) > -1 || u.indexOf(‘Mac’) > -1, //是否为iPhone或者QQHD浏览器
iPad: u.indexOf(‘iPad’) > -1, //是否iPad
webApp: u.indexOf(‘Safari’) == -1 //是否web应该程序,没有头部与底部
};
}(),
language:(navigator.browserLanguage || navigator.language).toLowerCase()
}
if( browser.versions.android || browser.versions.iPhone || browser.versions.iPad){
window.location.href=’http://cdn1.zygames.com/qqsm/events/201501/goHome/m/index.html’

}
}