Javascript Tips(1)

项目中遇到的问题总结,怕以后会忘记,遂在此记录一下。

1. 内部函数的变量 与 外部的变量 重名时 的相互关系

① 外部变量 与 函数形参 重名 —— 两者互不影响(函数内部只用来调用,外部变量不会被重新赋值)

var x = { }, b= 123
function define(x, b){
  x = {a: 22 };  
  b = "jjj"; 
}
define(x , b);
console.log(x); // Object {} 未变化
console.log(b); // 123  

var x = { }, b= 123
// var x = { a:123 } 这样定义时,也会被函数重新定义。 因为传递时,实参只是 x,而非x.a ,因此函数内部会把 x.a看出新的变量。
function define(x, b){
  x.a= 22; // 注意与上者的区别, 此时相当于 定义了一个新的全局变量 x.a
  b = "jjj"; // 此时相当于 只重新定义了 形参,但外部变量未不会重定义。
  console.log(arguments[1]); // 可用此做测试,第二个形参被改变了,输出 "jjj"
}
define(x , b);
console.log(x); // Object {a:22}
console.log(b); // 123

② 外部变量 与 函数形参 无重名 —— 若函数内使用的是全局变量,则重新覆盖外部的。否则互不影响

var x = { }, b= 123
function define(){
    x.a= 22; // 亦可写为x = {a: 22 };  
    b = "jjj"; // 与外部的 b 类型不一样
}
define();
console.log(x); // Object {a:22}
console.log(b); // “jjj”

2. 函数形参 与 实参 关系

1. 调用时实参与定义时形参数量一致时,实参与arguments互相影响,修改其中的一个其对应的也会被修改。

function func(x,y){
    //alert(x);
    y = 6;
    console.log(arguments[1]); 
}  
func(3, 2); // --> 6

2. 实参与形参数量不一致时,不关联,不互相影响。

function func(x,y){
    //alert(x);
    y = 6;
    console.log(arguments[1]); 
}  
func(3); // --> undefined

参考:

[1] http://www.cnblogs.com/snandy/archive/2011/03/17/1987084.html

[2] JavaScript函数参数的可修改性

[3] JavaScript中同名标识符优先级

3. var 的声明

如果变量在中间 声明,javascript会默认提到首行,但不执行,只有到该行才会执行。

function callName(){
   alert(name); 
   var name = "marry";
}
callName();  // 提示undefined , 此时只声明了 var name, 但未赋值 name = "marry";

参考:

[1] javascript函数内部用var声明临时变量需要注意的

4. 检测滚动事件(scroll down / scroll up)

检测滚动:

Firefoxdom.on('DOMMouseScroll',function(){} );

IE \ Opera \ Safarimousewheel

// Jquery
var lastScrollTop = 0;
$(window).scroll(function(event){
   var st = $(this).scrollTop();
   if (st > lastScrollTop){
       // downscroll code
   } else {
      // upscroll code
   }
   lastScrollTop = st;
});

 // Firefox
 $('#elem').bind('DOMMouseScroll', function(e){
     if(e.originalEvent.detail > 0) {
         //scroll down
         console.log('Down');
     }else {
         //scroll up
         console.log('Up');
     }

     //prevent page fom scrolling
     return false;
 });

 // IE, Opera, Safari
 $('#elem').bind('mousewheel', function(e){
     if(e.originalEvent.wheelDelta < 0) {
         //scroll down
         console.log('Down');
     }else {
         //scroll up
         console.log('Up');
     }

     //prevent page fom scrolling
     return false;
 });

5. documentElement 、 window.scrollY 、 window.pageYOffset

IE下会分quick mode, standard mode两种,

quick mode下

For cross-browser compatibility, use window.pageYOffset instead of window.scrollY.Additionally, older versions of Internet Explorer (< 9) do not support either property and must be worked around by checking other non-standard properties. A fully compatible example:

var x = (window.pageXOffset !== undefined) ? window.pageXOffset : (document.documentElement || document.body.parentNode || document.body).scrollLeft;
var y = (window.pageYOffset !== undefined) ? window.pageYOffset : (document.documentElement || document.body.parentNode || document.body).scrollTop;

或者

return window.pageYOffset || documentElement.scrollTop || body.scrollTop || 0;
// or this
Math.max(window.pageYOffset, documentElement.scrollTop, body.scrollTop)

附:

测试结果
各浏览器对 document、document.body、document.documentElement 对象的 onscroll 事件支持情况

6. 注意字符串拼接时的数学计算

不加括号的则直接拼接,不会计算

var a =1, b =2;
var s = 'xxx' + a + b + 'xxx'  // xxx12xxx
var s = 'xxx' + (a + b) + 'xxx'  // xxx3xxx

7. 对象间复制

如果直接定义,改变现有对象,则会影响原有对象

var a = {s:123 }
var b = a
b.s = 333
a // {s:333}

因此,最简洁方法,使用jquery的 $.extend

var b = $.extend({}, a, {s:333})

此时a对象不会受影响

同时,可以利用此特性,共享数据

var x = {a:33, b: 22}
x.share = x
x.share.a =44 // 此时,x.a = 44

8. 调用浏览器全屏模式

addEventListener("click", function() {
    var el = document.documentElement, 
        rfs = el.requestFullScreen || el.webkitRequestFullScreen || el.mozRequestFullScreen;
    rfs.call(el);
});

9. 几种js运算 Math vs Bitwise

Math.round —— 四舍五入

Math.ceil —— 向上取整

Math.floor —— 向下取整(只能是数字,但纯数字的字符串也可以)

    Math.floor('12ppp') // NaN   
    Math.floor('12') // 12

parseInt —— 向下取整(可将字符串转为数字)

    parseInt('12ppp') // 12

以上四种,parseInt最慢

最快的是 位运算, 其次是MathparseInt最慢

测试结果:

http://jsperf.com/math-floor-vs-math-round-vs-parseint/55

http://jsperf.com/math-ceil-vs-bitwise

Math.ceil

var f = (n << 0),
    f = f == n ? f : f + 1;

关于小数点截取,舍位运算

思路如下:乘以10的N次方,向下取整,再除以10的N次方(N为小数位数)

( Math.floor( num * Math.pow(10, digits) ) / Math.pow(10, digits) ).toString()

需要toString,由于浮点运算的准确性问题,详见此 .toFixed() returns a string in JavaScript