全面介绍javascript实用技巧及单竖杠


Posted in Javascript onJuly 18, 2016

JavaScript 本身可以算是一门简单的语言,但我们也不断用智慧和灵活的模式来改进它。昨天我们将这些模式应用到了 JavaScript 框架中,今天这些框架又驱动了我们的 Web 应用程序。很多新手开发者被各种强大的 JavaScript 框架吸引进来,但他们却忽略了框架身后浩如星海的 JavaScript 实用技巧。本文将为你全面的介绍其中的知识点。

一、js整数的操作

使用|0和~~可以将浮点转成整型且效率方面要比同类的parseInt,Math.round 要快,在处理像素及动画位移等效果的时候会很有用。性能比较见此。

var foo = (12.4 / 4.13) | 0;//结果为3
var bar = ~~(12.4 / 4.13);//结果为3

还有一个小技巧,就是!!2个叹号,可以讲一个值,快速转化为布尔值。你可以测试一下!

var eee="eee";
alert(!!eee)

返回的是true,也就是说任何一个值前面加!!都可以恒等于true。除非这个值本来就是布尔值,或者为 undefined, null, 0, false, NaN, '',因为我提到的 undefined, null, 0, false, NaN, '' ,这些,本来就是false,所以加了两个!!之后,还是fasle。

二、重写原生alert,记录弹框次数

(function() {
 var oldAlert = window.alert,
 count = 0;
 window.alert = function(a) {
 count++;
 oldAlert(a + "\n You've called alert " + count + " times now. Stop, it's evil!");
 };
})();
alert("Hello Haorooms");

三、数字交换不声明中间变量的方法

两个数字之间做交换,我们的一般做法是声明一个中间变量,但是今天的做法比较奇葩,不用声明中间变量,看看是如何实现的!

var a=1,b=2;a=[b,b=a][0];
console.log('a:'+a+',b:'+b);

 //输出a:2,b:1

怎么样,这个方法是不是有一种焕然一新的感觉?

四、万物皆对象

在JavaScript的世界,万物皆对象。除了null和undefined,其他基本类型数字,字符串和布尔值都有对应有包装对象。对象的一个特征是你可以在它身上直接调用方法。

对于数字基本类型,当试图在其身上调用toString方法会失败,但用括号括起来后再调用就不会失败了,内部实现是用相应的包装对象将基本类型转为对象。所以(1).toString()相当于new Number(1).toString()。因此,你的确可以把基本类型数字,字符串,布尔等当对象使用的,只是注意语法要得体。

同时我们注意到,JavaScript中数字是不分浮点和整形的,所有数字其实均是浮点类型,只是把小数点省略了而以,比如你看到的1可以写成1.,这也就是为什么当你试图1.toString()时会报错,所以正确的写法应该是这样:1..toString(),或者如上面所述加上括号,这里括号的作用是纠正JS解析器,不要把1后面的点当成小数点。内部实现如上面所述,是将1.用包装对象转成对象再调用方法。

五、If语句的变形

当你需要写一个if语句的时候,不妨尝试另一种更简便的方法,用JavaScript中的逻辑操作符来代替。

var day=(new Date).getDay()===0;
//传统if语句
if (day) {
 alert('Today is Sunday!');
};
//运用逻辑与代替if
day&&alert('Today is Sunday!');

比如上面的代码,首先得到今天的日期,如果是星期天,则弹窗,否则什么也不做。我们知道逻辑操作存在短路的情况,对于逻辑与表达式,只有两者都真才结果才为真,如果前面的day变量被判断为假了,那么对于整个与表达式来说结果就是假,所以就不会继续去执行后面的alert了,如果前面day为真,则还要继续执行后面的代码来确定整个表达式的真假。利用这点达到了if的效果。

对于传统的if语句,如果执行体代码超过了1 条语句,则需要加花括号,而利用逗号表达式,可以执行任意条代码而不用加花括号。

if(conditoin) alert(1),alert(2),console.log(3);

六、使用===,而不是==

==(或!=)操作符在需要的时候会自动执行类型转换。===(或!==)操作不会执行任何转换。它将比较值和类型,而且在速度上也被认为优于==。

[10] === 10 // is false
[10] == 10 // is true
'10' == 10 // is true
'10' === 10 // is false
 [] == 0 // is true
 [] === 0 // is false
 '' == false // is true but true == "a" is false
 '' === false // is false

七、使用闭包实现私有变量

function Person(name, age) {
 this.getName = function() { return name; };
 this.setName = function(newName) { name = newName; };
 this.getAge = function() { return age; };
 this.setAge = function(newAge) { age = newAge; };

 //未在构造函数中初始化的属性
 var occupation;
 this.getOccupation = function() { return occupation; };
 this.setOccupation = function(newOcc) { occupation = 
  newOcc; };
}

八、创建对象的构造函数

function Person(firstName, lastName){
 this.firstName = firstName;
 this.lastName = lastName;
}

var Saad = new Person("Saad", "Mousliki");

九、小心使用typeof、instanceof和constructor

var arr = ["a", "b", "c"];
typeof arr; // return "object"
arr instanceof Array // true
arr.constructor(); //[]

十、创建一个自调用函数(Self-calling Funtion)

这个经常被称为自调用匿名函数(Self-Invoked Anonymous Function)或者即时调用函数表达式(IIFE-Immediately Invoked Function Expression)。这是一个在创建后立即自动执行的函数,通常如下:

(function(){
 // some private code that will be executed automatically
})();
(function(a,b){
 var result = a+b;
 return result;
})(10,20)

十一、从数组中获取一个随机项

var items = [12, 548 , 'a' , 2 , 5478 , 'foo' , 8852, , 'Doe' , 2145 , 119];

var randomItem = items[Math.floor(Math.random() * items.length)];

十二、在特定范围内获取一个随机数

这个代码片段在你想要生成测试数据的时候非常有用,比如一个在最小最大值之间的一个随机薪水值。

var x = Math.floor(Math.random() * (max - min + 1)) + min;

十三、在0和设定的最大值之间生成一个数字数组

var numbersArray = [] , max = 100;

for( var i=1; numbersArray.push(i++) < max;); // numbers = [0,1,2,3 ... 100]

十四、生成一个随机的数字字母字符串

function generateRandomAlphaNum(len) {
 var rdmstring = "";
 for( ; rdmString.length < len; rdmString += Math.random().toString(36).substr(2));
 return rdmString.substr(0, len);
}

//调用方法generateRandomAlphaNum(15);

十五、打乱一个数字数组

var numbers = [5, 458 , 120 , -215 , 228 , 400 , 122205, -85411];
numbers = numbers.sort(function(){ return Math.random() - 0.5});
/* the array numbers will be equal for example to [120, 5, 228, -215, 400, 458, -85411, 122205] */

十六、 String的trim函数

String.prototype.trim = function(){return this.replace(/^\s+|\s+$/g, "");};

十七、 附加(append)一个数组到另一个数组上

var array1 = [12 , "foo" , {name: "Joe"} , -2458];

var array2 = ["Doe" , 555 , 100];
Array.prototype.push.apply(array1, array2);
/* array1 will be equal to [12 , "foo" , {name "Joe"} , -2458 , "Doe" , 555 , 100] */

十八、将arguments对象转换成一个数组

var argArray = Array.prototype.slice.call(arguments);
【译者注:arguments对象是一个类数组对象,但不是一个真正的数组】

十九、验证参数是否是数字(number)

function isNumber(n){
 return !isNaN(parseFloat(n)) && isFinite(n);
}

二十、验证参数是否是数组

function isArray(obj){
 return Object.prototype.toString.call(obj) === '[object Array]' ;
}

注意:如果toString()方法被重写了(overridden),你使用这个技巧就不能得到想要的结果了。或者你可以使用:

Array.isArray(obj); // 这是一个新的array的方法

如果你不在使用多重frames的情况下,你还可以使用 instanceof 方法。但如果你有多个上下文,你就会得到错误的结果。

var myFrame = document.createElement('iframe');
document.body.appendChild(myFrame);

var myArray = window.frames[window.frames.length-1].Array;
var arr = new myArray(a,b,10); // [a,b,10]

// instanceof will not work correctly, myArray loses his constructor
// constructor is not shared between frames
arr instanceof Array; // false

【译者注:关于如何判断数组网上有不少讨论,大家可以google一下。这篇就写的挺详细的。】

二十一、获取一个数字数组中的最大值或最小值

var  numbers = [5, 458 , 120 , -215 , 228 , 400 , 122205, -85411];
var maxInNumbers = Math.max.apply(Math, numbers);
var minInNumbers = Math.min.apply(Math, numbers);
【译者注:这里使用了Function.prototype.apply方法传递参数的技巧】

二十二、清空一个数组

var myArray = [12 , 222 , 1000 ];
myArray.length = 0; // myArray will be equal to [].

二十三、不要使用 delete 来删除一个数组中的项。

使用 splice 而不要使用 delete 来删除数组中的某个项。使用 delete 只是用 undefined 来替换掉原有的项,并不是真正的从数组中删除。

不要使用这种方式:

var items = [12, 548 ,'a' , 2 , 5478 , 'foo' , 8852, , 'Doe' ,2154 , 119 ];
items.length; // return 11
delete items[3]; // return true
items.length; // return 11
/* items will be equal to [12, 548, "a", undefined × 1, 5478, "foo", 8852, undefined × 1, "Doe", 2154, 119] */

而使用:

var items = [12, 548 ,'a' , 2 , 5478 , 'foo' , 8852, , 'Doe' ,2154 , 119 ];
items.length; // return 11
items.splice(3,1) ;
items.length; // return 10
/* items will be equal to [12, 548, "a", 5478, "foo", 8852, undefined × 1, "Doe", 2154, 119] */

delete 方法应该被用来删除一个对象的某个属性。

二十四、使用 length 来截短一个数组

跟上面的清空数组的方式类似,我们使用 length 属性来截短一个数组。

var myArray = [12 , 222 , 1000 , 124 , 98 , 10 ];
myArray.length = 4; // myArray will be equal to [12 , 222 , 1000 , 124].

此外,如果你将一个数组的 length 设置成一个比现在大的值,那么这个数组的长度就会被改变,会增加新的 undefined 的项补上。 数组的 length 不是一个只读属性。

myArray.length = 10; // the new array length is 10
myArray[myArray.length - 1] ; // undefined

二十五、使用逻辑 AND/OR 做条件判断

同(五),if变形语句!

var foo = 10;
foo == 10 && doSomething(); // 等价于 if (foo == 10) doSomething();
foo == 5 || doSomething(); // 等价于 if (foo != 5) doSomething();

逻辑 AND 还可以被使用来为函数参数设置默认值

function doSomething(arg1){
 Arg1 = arg1 || 10; // 如果arg1没有被设置的话,Arg1将被默认设成10
}

二十六、使用 map() 方法来遍历一个数组里的项

var squares = [1,2,3,4].map(function (val) {
 return val * val;
});
// squares will be equal to [1, 4, 9, 16]

二十七、四舍五入一个数字,保留N位小数

var num =2.443242342;
num = num.toFixed(4); // num will be equal to 2.4432

二十八、浮点数问题

0.1 + 0.2 === 0.3 // is false
9007199254740992 + 1 // is equal to 9007199254740992
9007199254740992 + 2 // is equal to 9007199254740994

为什么会这样? 0.1+0.2等于0.30000000000000004。你要知道,所有的JavaScript数字在内部都是以64位二进制表示的浮点数,符合IEEE 754标准。更多的介绍,可以阅读这篇博文。你可以使用 toFixed() 和 toPrecision() 方法解决这个问题。

二十九、使用for-in遍历一个对象内部属性的时候注意检查属性

下面的代码片段能够避免在遍历一个对象属性的时候访问原型的属性

for (var name in object) {
 if (object.hasOwnProperty(name)) {
 // do something with name
 }
}

三十、 逗号操作符

var a = 0;
var b = ( a++, 99 );
console.log(a); // a will be equal to 1
console.log(b); // b is equal to 99

三十一、缓存需要计算和查询(calculation or querying)的变量

对于jQuery选择器,我们最好缓存这些DOM元素。

var navright = document.querySelector('#right');
var navleft = document.querySelector('#left');
var navup = document.querySelector('#up');
var navdown = document.querySelector('#down');

三十二、在调用 isFinite()之前验证参数

isFinite(0/0) ; // false
isFinite("foo"); // false
isFinite("10"); // true
isFinite(10); // true
isFinite(undifined); // false
isFinite(); // false
isFinite(null); // true !!!

三十三、避免数组中的负数索引(negative indexes)

var numbersArray = [1,2,3,4,5];
var from = numbersArray.indexOf("foo") ; // from is equal to -1
numbersArray.splice(from,2); // will return [5]

确保调用 indexOf 时的参数不是负数。

三十四、基于JSON的序列化和反序列化(serialization and deserialization)

var person = {name :'Saad', age : 26, department : {ID : 15, name : "R&D"} };
var stringFromPerson = JSON.stringify(person);
/* stringFromPerson is equal to "{"name":"Saad","age":26,"department":{"ID":15,"name":"R&D"}}" */
var personFromString = JSON.parse(stringFromPerson);
/* personFromString is equal to person object */

三十五、避免使用 eval() 和 Function 构造函数

使用 eval 和 Function 构造函数是非常昂贵的操作,因为每次他们都会调用脚本引擎将源代码转换成可执行代码。

var func1 = new Function(functionCode);
var func2 = eval(functionCode);

三十六、避免使用 with()

使用 with() 会插入一个全局变量。因此,同名的变量会被覆盖值而引起不必要的麻烦。

三十七、避免使用 for-in 来遍历一个数组

避免使用这样的方式:

var sum = 0;
for (var i in arrayNumbers) {
 sum += arrayNumbers[i];
}

更好的方式是:

var sum = 0;
for (var i = 0, len = arrayNumbers.length; i < len; i++) {
 sum += arrayNumbers[i];
}

附加的好处是,i 和 len 两个变量的取值都只执行了一次,会比下面的方式更高效:

for (var i = 0; i < arrayNumbers.length; i++)

为什么?因为arrayNumbers.length每次循环的时候都会被计算。

三十八、在调用 setTimeout() 和 setInterval() 的时候传入函数,而不是字符串。

如果你将字符串传递给 setTimeout() 或者 setInterval(),这个字符串将被如使用 eval 一样被解析,这个是非常耗时的。

不要使用:

setInterval('doSomethingPeriodically()', 1000);
setTimeOut('doSomethingAfterFiveSeconds()', 5000)

而用:

setInterval(doSomethingPeriodically, 1000);
setTimeOut(doSomethingAfterFiveSeconds, 5000);

三十九、使用 switch/case 语句,而不是一长串的 if/else

在判断情况大于2种的时候,使用 switch/case 更高效,而且更优雅(更易于组织代码)。但在判断的情况超过10种的时候不要使用 switch/case。

四十、在判断数值范围时使用 switch/case

在下面的这种情况,使用 switch/case 判断数值范围的时候是合理的:

function getCategory(age) {
 var category = "";
 switch (true) {
 case isNaN(age):
 category = "not an age";
 break;
 case (age >= 50):
 category = "Old";
 break;
 case (age <= 20):
 category = "Baby";
 break;
 default:
 category = "Young";
 break;
 };
 return category;
}
getCategory(5); // will return "Baby"

【译者注:一般对于数值范围的判断,用 if/else 会比较合适。 switch/case 更适合对确定数值的判断】

四十一、为创建的对象指定prototype对象

写一个函数来创建一个以指定参数作为prototype的对象是有可能:

function clone(object) {
 function OneShotConstructor(){};
 OneShotConstructor.prototype= object;
 return new OneShotConstructor();
}
clone(Array).prototype ; // []

四十二、一个HTML转义函数

function escapeHTML(text) {
 var replacements= {"<": "<", ">": ">","&": "&", "\"": """};
 return text.replace(/[<>&"]/g, function(character) {
 return replacements[character];
 });
}

四十三、避免在循环内部使用 try-catch-finally

在运行时,每次当 catch 从句被执行的时候,被捕获的异常对象会赋值给一个变量,而在 try-catch-finally 结构中,每次都会新建这个变量。

避免这样的写法:

var object = ['foo', 'bar'], i;
for (i = 0, len = object.length; i <len; i++) {
 try {
 // do something that throws an exception
 }
 catch (e) {
 // handle exception
 }
}

而使用:

var object = ['foo', 'bar'], i;
try {
 for (i = 0, len = object.length; i <len; i++) {
 // do something that throws an exception
 }
}
catch (e) {
 // handle exception
}

四十四、为 XMLHttpRequests 设置超时。

在一个XHR请求占用很长时间后(比如由于网络问题),你可能需要中止这次请求,那么你可以对XHR调用配套使用 setTimeout()。

var xhr = new XMLHttpRequest ();
xhr.onreadystatechange = function () {
 if (this.readyState == 4) {
 clearTimeout(timeout);
 // do something with response data
 }
}
var timeout = setTimeout( function () {
 xhr.abort(); // call error callback
}, 60*1000 /* timeout after a minute */ );
xhr.open('GET', url, true); 

xhr.send();

此外,一般你应该完全避免同步的Ajax请求。

四十五、处理WebSocket超时

通常,在一个WebSocket连接创建之后,如果你没有活动的话,服务器会在30秒之后断开(time out)你的连接。防火墙也会在一段时间不活动之后断开连接。

为了防止超时的问题,你可能需要间歇性地向服务器端发送空消息。要这样做的话,你可以在你的代码里添加下面的两个函数:一个用来保持连接,另一个用来取消连接的保持。通过这个技巧,你可以控制超时的问题。

使用一个 timerID:

var timerID = 0;
function keepAlive() {
 var timeout = 15000;
 if (webSocket.readyState == webSocket.OPEN) {
 webSocket.send('');
 }
 timerId = setTimeout(keepAlive, timeout);
}
function cancelKeepAlive() {
 if (timerId) {
 cancelTimeout(timerId);
 }
}

keepAlive()方法应该被添加在webSOcket连接的 onOpen() 方法的最后,而 cancelKeepAlive() 添加在 onClose() 方法的最后。

四十六、牢记,原始运算符始终比函数调用要高效。使用VanillaJS。

举例来说,不使用:

var min = Math.min(a,b);
A.push(v);

而用:

var min = a < b ? a b;
A[A.length] = v;

四十七、从整数中,随机选取一个数值

有如下公式,非常有用,可以让我们随机显示某些名人名言或者新闻事件!

值=Math.floor(Math.random()*可能值的总数+第一个可能的值)
例如:要想选择一个介于2到10之间的值,我们可以这么写

var num=Math.floor(Math.random()*9+2)

请记住上面公式!~

js运算符单竖杠“|”的用法和作用及js数据处理

刚才在js整数操作的时候,相当于去除小数点,parseInt。在正数的时候相当于Math.floor(),负数的时候相当于Math.ceil() 注:

1. Math.ceil()用作向上取整。
2. Math.floor()用作向下取整。
3. Math.round() 我们数学中常用到的四舍五入取整。

console.log(0.6|0)//0
console.log(1.1|0)//1
console.log(3.65555|0)//3
console.log(5.99999|0)//5
console.log(-7.777|0)//-7

注:除了Math的三个方法处理数字,我们还经常用parseInt()、parseFloat()、toFixed()与toPrecision() 等等。 简单解释:

toFixed方法用法如下:

100.456001.toFixed(2); //100.47

100.456001.toFixed(3); //100.456

Number.prototype.toFixed.call(100.456001,2); //100.47

缺点:用之后就会变成字符串。

toPrecision用法如下:

99.456001.toPrecision(5); //99.456

100.456001.toPrecision(5); //100.46

Number.prototype.toPrecision.call(10.456001,5); //10.456

单竖杠的运算规则

看了上面的例子,大体知道单竖杠可以进行取整运算,就是只保留正数部分,小数部分通过拿掉,但是“|0”,又是如何进行运算的呢,为什么能“|0”能达到取整的目的呢?单竖杠不是0有会是多少呢?

带着这些问题,我们看下面例子:

console.log(3|4); //7
console.log(4|4);//4
console.log(8|3);//11
console.log(5.3|4.1);//5
console.log(9|3455);//3455

好像无规律可以寻找啊?网上搜索吧。http://tools.3water.com/table/priority

这里面提到了单竖杠“|”但是没有javascript的。

好吧,我在这里公布答案吧。其实单竖杠“|”就是转换为2进制之后相加得到的结果。例如我们拿简单的举例:

3|4
转换为二进制之后011|100 相加得到111=7

4|4
转换为二进制之后100 |100 相加得到100=4

8|3
转换为二进制之后1000 |011 相加得到1011=11

以此类推,我在这里就不一一列举了,单竖杠“|”运算就是转换为2进制之后相加得到的结果!都学会了吗?

Javascript 相关文章推荐
Mootools 1.2教程 Fx.Morph、Fx选项和Fx事件
Sep 15 Javascript
在jQuery ajax中按钮button和submit的区别分析
Oct 07 Javascript
微信分享的标题、缩略图、连接及描述设置方法
Oct 14 Javascript
JS实现仿新浪黄色经典滑动门效果代码
Sep 27 Javascript
noty ? jQuery通知插件全面解析
May 18 Javascript
鼠标经过出现气泡框的简单实例
Mar 17 Javascript
JavaScript 2018 中即将迎来的新功能
Sep 21 Javascript
小程序指纹验证的实现代码
Dec 04 Javascript
Vue开发Html5微信公众号的步骤
Apr 11 Javascript
JS浮点数运算结果不精确的Bug解决
Aug 01 Javascript
vue.js 实现a标签href里添加参数
Nov 12 Javascript
JS实现可控制的进度条
Mar 25 Javascript
Bootstrap 布局组件(全)
Jul 18 #Javascript
js验证真实姓名与身份证号,手机号的简单实例
Jul 18 #Javascript
Bootstrap零基础入门教程(三)
Jul 18 #Javascript
15位和18位身份证JS校验的简单实例
Jul 18 #Javascript
Bootstrap零基础入门教程(二)
Jul 18 #Javascript
Bootstrap插件全集
Jul 18 #Javascript
全面了解javascript中的错误处理机制
Jul 18 #Javascript
You might like
PHP 截取字符串函数整理(支持gb2312和utf-8)
2010/02/16 PHP
phpnow php探针环境检测代码
2014/11/04 PHP
php中FTP函数ftp_connect、ftp_login与ftp_chmod用法
2014/11/18 PHP
php实现的中文分词类完整实例
2017/02/06 PHP
详解PHP防止盗链防止迅雷下载的方法
2017/04/26 PHP
PHP mysqli事务操作常用方法分析
2017/07/22 PHP
PHP微信H5支付开发实例
2018/07/25 PHP
用JS剩余字数计算的代码
2008/07/03 Javascript
JavaScript CSS 修改学习第四章 透明度设置
2010/02/19 Javascript
js中设置元素class的三种方法小结
2011/08/28 Javascript
Javascript insertAfter() 实现函数代码
2011/10/12 Javascript
Js sort排序使用方法
2011/10/17 Javascript
关闭浏览器时提示onbeforeunload事件
2013/12/25 Javascript
jQuery实现统计复选框选中数量
2014/11/24 Javascript
Jquery组件easyUi实现手风琴(折叠面板)示例
2016/08/23 Javascript
JavaScript实现短信倒计时60s
2017/10/09 Javascript
详解webpack4之splitchunksPlugin代码包分拆
2018/12/04 Javascript
js 计算图片内点个数的示例代码
2019/04/04 Javascript
解决vue 单文件组件中样式加载问题
2019/04/24 Javascript
vue项目实现设置根据路由高亮对应的菜单项操作
2020/08/06 Javascript
python中list常用操作实例详解
2015/06/03 Python
Python实现的基于优先等级分配糖果问题算法示例
2018/04/25 Python
Python 获取ftp服务器文件时间的方法
2019/07/02 Python
PyCharm2019安装教程及其使用(图文教程)
2019/09/29 Python
Python高阶函数、常用内置函数用法实例分析
2019/12/26 Python
详解Python中的Lock和Rlock
2021/01/26 Python
为什么UNION ALL比UNION快
2016/03/17 面试题
JVM是一个编译程序还是解释程序
2012/09/11 面试题
英语简历自我评价
2014/01/26 职场文书
董事长助理工作职责范本
2014/07/01 职场文书
助学金感谢信
2015/01/20 职场文书
仓管员岗位职责范本
2015/04/01 职场文书
2016大学生求职自荐信范文
2016/01/28 职场文书
2016年优秀少先队员事迹材料
2016/02/26 职场文书
Spring依赖注入多种类型数据的示例代码
2022/03/31 Java/Android
Ubuntu安装Mysql+启用远程连接的完整过程
2022/06/21 Servers