结合自己编码遇到的小坑的积累吧。因此下面会有一些个人的见解,参考书籍《JavaScript高级程序设计》(第三版)
尽量不适用 var 声明局部变量
在 esc5 中 var 声明变量是一个万能的方式,往往因为太便利了就会出现一些问题。例如我其实只是想让一个变量在局部作用域中有效果,但是在下面的代码却出现了问题。
// 猜猜下面执行后的结果。
var a = { a: 2 }
var b = { a: 2 }
if (a) {
a.a = 1;
var a = new Object();
a.a = 3;
}
// 如果你讲 if 里的 var 换成 let 会抛出异常,需要将 a.a=1 注销掉才可以。
console.error(a); // 3
function str(b) {
b.a = 1;
var b = new Object();
b.a = 3;
}
str(b)
console.log(b); // 1
for (var i = 0; i < 3; i++) {
var b = 2
}
console.log(i); // 3
console.log(b); // 2
所以在声明变量的时候最好是用 let 而不是 var 这也是 ECMAScript6 推荐的做法。
Array 数组
其实数组里还是设计到数据结构栈类似的存储结构,对栈的认识 可以参考这个链接
array.length :不仅可读,还是可以通过设置长度截取或增加数组的内容。并且会更爱原数组;当然新增数组的内容默认值是 undefined
-
判断数组
-
针对一个网页,或者是一个框架环境的情况下,用 instanceof 就可以实现。
if( value instanceof Array){ //对数组执行操作 }
-
网页中如果包含多个框架,一个框架的 Array 值传递进入另一个框架做是否数组的判断。用Array.isArray()
if(Array.isArray( value )){ // 对数组执行的操作 }
-
-
数组排序 sort 、reserve
// sort 的排序方式是比较函数通过返回值小于零、大于零、等于零来影响排序结果,减法的操作就可以适用部分情况。 var arr = [2,3,1,3,4,5,1]; var sortArray = arr.sort( function (a, b){ return b - a; //return a < b ? 1 : -1; } ); // 倒叙排列 console.error(sortArray); // 正序排列 function compare(value1, value2){ if(value1 < value2){ return -1; }else if( value1 > value2){ return 1; }else{ return 0; } } //var sortArray =arr.sort(compare); // reserve 的作用就是反转已经排好的顺序。 var reverseSort = sortArray.reverse(); console.log(reverseSort);
-
数组合并 concat
var color = ['green']; // color 的值不变 var colors = color.concat('yellow', ['blue','red']);
-
数组截取 slice
// 不会影响原数组 var colors = ["green", "yellow", "blue", "red"]; colors.slice(1); // ["yellow", "blue", "red"]; // 返回起始位置的值,单不包含结束位置的值; colors.slice(1,3); //["yellow", "blue"]
-
数组splice 删除、新增、修改操作
var arr = [1,2,3,4]; // 删除 //arr.splice(起始下标, 删除项数) arr.splice(0,1); // 返回删除的项1, arr = [2,3,4]; //替换 or 新增 //arr.splice(起始下标, 删除项目,替换的值) arr.splice(0, 0 ,4); // arr = [4, 1, 2, 3, 4] arr.splice(0, 1, 5); // arr = [5, 2, 3, 4]
-
位置方法 indexOf、lastIndexOf
// 可以接受2个参数, 下标是可选的,如果字符有,下标正确,返回下标值,否则返回 -1 str.indexOf(字符, 下标); // 我们一般的书写代码习惯 let a = "foo"; if(a.indexOf('a') != -1){ //... } // 其实这个代码可以简化下 if(~a.indexOf(a)){ // 这样就简化了代码 } 这里就必须补充一个知识点了 ~42 ===> -(42+1) = -43 所以 ~-1 = 0
迭代数组,执行一个方法,查看返回值 every、filter、forEach、map、some
-
迭代数组的每一项 reduce、reduceRight
var arr = [1,2,3]; arr.reduce(function(prev, curr, index, array){ return prev + curr; }) // 6 reduce & reduceRight 功能都一致,只是顺序不同。
正则
RegExp 每次执行都会创建一个新的构造函数,并且只接收字符串
// exec 返回匹配的第一个值
// test
函数
-
内部属性 arguments、this、callee
// 解除递归 函数和函数名的耦合 function str(num){ if(num <= 1){ return 1; }else{ return num + arguments.callee(num -1); } } str(7); //28
apply、call
// 1、apply、和call 相同点:都是指定方法在被调用的作用域
// 不同点:apply,第二个参数是,方法接收参数用数组传递;call 是直接一个一个书写。
function a(num1, num2){
return num1 + num2;
}
function b(num1, num2){
//return a.apply(this, arguments);
return a.call(this, num1, num2);
}
b(1,2); //3
// 方法内部继承,实例化方法调用。
function animal(name){
this.name= name || "animal";
this.getName = function(name){
return this.name;
}
}
function dog(name){
animal.call(this, name);
}
var dog1= new dog("旺财");
console.log(dog1.getName()); // 旺财
// 实例化方法继承的方式
function Animal(){
this.name= "animal";
this.getName = function(name){
return this.name;
}
}
function Dog(){
this.name ='汪汪'
}
var dog= new Dog();
var animal = new Animal();
console.log(animal.getName.call(dog, ","));
// functionName.apply(作用域, 参数数组)
function sun(num1, num2){
return num1 - num2;
}
function cont(num1, num2){
return sun.apply(this, [num1,num2]); // 这两种都是可以的
//return sun.apply(this, arguments);
}
console.log(cont(1,10)); // -9
数字的处理 toFixed / toExponential / toPrecision
//toFixed
var a =10;
a.toFixed(2); // 10.00;
// 常见问题,如果对数据的精度要求不是很高的情况下,我们解决 0.1+0.2 != 0.3 的情况
Number((0.1+0.2).toFixed(2)) // 0.30
// 采用科学计数法显示
a.toExponential() // "1e+1"
// 会根据传入的参数,自动的用科学计数法,还是正常的显示十进制
a.toPrecision(1) // 1e+1;
字符方法 charAt、charCodeAt、concat、slice、substr、substring、toLowerCase、toLocaleLowerCase、toUpperCase、toLocaleUpperCase、fromCharCode、split
var str = 'hello world';
// 获取字符串中指定位置的字符
str.charAt(1); //e
// 获取指定位置字符的字符编码
str.charCodeAt(); //101
// 字符连接,当然后面是可以跟多个参数的。其实更多的时候我们是用 + 来实现字符串的链接
str.concat(" and"," you "); //"hello world and you"
//fromCharCode 的作用与 charCodeAt 方法效果是相反的。参数是字符和数字都可以,前提是能转换成整数
Sting.fromCharCode(101); //e
// split 经常用来将 string 转换成 Array 类型。
let a = "foo";
let b = a.split("");
b// ['f','o','o'];
// 当然如果想对字符串的操作用 Array 的方法其实可以不用将字符串 split 转换
1. 使用call
Array.prototype.join.call(a,"-"); // f-o-o
Array.prototype.map.call(a, (val) => {
return val.toLocaleUpperCase()
}).join(".") // F.O.O
replace 方法的使用
//在以前的时候我都是仅仅简单的使用 replace 替换字符,其实我们可以对 ,替换的字符做一些操作
// 可以给符合的字符增加字符并凭借在一起。
var str = "bat, cat, dat";
var word= str.replace(/(.at)/g, "word ($1)");
alert(word);
// 当然第二个参数也可以是一个方法,传入三个值
// match:匹配的字符
// originalText:被替换的字符
// positoin:被替换字符的位置
var word = str.replace(/(.at)/g, function(match, originalText, position){
switch(match){
case "bat" :
return "bb "+position +' '+originalText;
case "cat" :
return "cc "+ position+ ' ' +originalText;
case "dat" :
return "dd "+ position +' '+ originalText;
}
})
alert(word); // "bb 0 bat, cc 5 cat, dd 10 dat"
在数组中比较数字的大小
// 方法一排序 sort
var arr = [1,2,3,4];
var arrsort = arr.sort(function(a, b){
return b -a ; // return a-b; 升序
})
arrsort[0]; // 4
//方法二: Math.max, Math.min
//语法: Math.max(num1,num2,num3...); 但是如果我是想比较数组里的值怎么办呢,这时候就可以用到 eval了
var arr = [1,2,3,4];
var arrStr = arr.toString();
eval("Math.max("+ arrstr +")"); // 4
// 方法三,利用 apply 第二参数可以接收数组的特性,然后结合Math.max & Math.min js 提供的 2 个方法
var arr = [1,2,3,4];
function max(arr){
return Math.max.apply(Math,arr);
};
max(arr); // 4
// 方法 4 for 循环判断
var arr = [1,2,3,4];
function max(arr){
var curr = "";
for(var i in arr){
if(arr[i] > curr ){
curr = arr[i]
}
}
return curr;
}
max(arr); // 4
// 我知道的暂时就这四种,还缺少性能上的比较,后期看到了在更新。
Math 方法
// Math.max(num1, num2, num3 ...) 获取最大值
// Math.min(num1, num2, num3 ...) 获取最小值
// Math.ceil(num) // 执行向上舍入为最接近的整数
// Math.floor(num) // 执行向下舍入最接近的整数
// Math.round(num) // 执行标准的四舍五入,并且四舍五入小数后一位,只保留整数位置,和toFixed不同
// Math.random() //返回一个 0 ~ 1 之间的随机数,不包括 0 和 1
// 生成 0 - 9 的一个随机数
Math.floor(Math.random() * 10);
// 如果你想生成的 2 - 10 的一个随机数, 然后自己看半天蛮麻烦的。其实别人早已经想到方法了
function selectFrom(lowerValue, upperValue){
var choices = upperValue - lowerValue;
return Math.floor(Math.random() * choices + lowerValue );
}
备注常见的问题
- 解决 0.1 + 0.2 != 0.3 的情况
// 精度要求不高的情况下
Number((0.1+0.2).toFixed(2)) // 0.3
// 判断一个特定值
Number.EPSILON // 2.220446049250313e-16
if(a - b< Number.EPSILON){
return true; // 相等
}
- 取小数的整数部分
1、~~49.1 // 49
2、~~-49.1 // -49
3、 Number.parseInt(49.1) // 49
- 在使用 == 判断对象和数字的情况
let d = {
val: 1
}
console.log(d ==1); // false
let d = {
val: 1,
toString: function () {
return this.val;
},
}
console.log(d ==1); // false
let d = {
val: 1,
toString: function () {
return this.val;
},
valueOf: function () {
return this.val + 1;
}
}
console.log(d ==2); // true
// 在使用 == 判断相等的时候,js 会将引用类型数据获取 ToPrimitive 对应的值,会调用 toString 和 ValueOf。
- js 相等转换类型中的7个坑,真的是天坑。你会意想不到的,因为他们是相等的。
false == "0"; // true -- 晕!
false == 0; // true -- 晕!
false == ""; // true -- 晕!
false == []; // true -- 晕!
"" == 0; // true -- 晕!
"" == []; // true -- 晕!
0 == []; // true -- 晕!
- js switch 函数中 case 值的运用
var a = "hello world";
var b = 10;
switch (true) {
case (a || b == 10):
// 永远执行不到这里
console.log(123)
break;
default:
console.log("Oops");
}
// 如果细微的更改下
switch (true) {
case !!(a || b == 10):
console.log(123)
break;
default:
console.log("Oops");
}
// 这里执行的结果就是 123, 这样书写仅做参考。
备注
- 所有的对象都有 toLocaleString() 、 toString() 、 valueOf() 方法。可以看到方法执行的内容,不过每个浏览器对这三个方法返回内容和格式会有一定的差异,对调试代码还是很有用的。
- alert 方法只接收字符串的参数,当传入数组的时候,alert 会执行 toString() 方法,因此显示的结果是数组的字符串并以逗号隔开的形式。