1.逻辑与"&&",逻辑或"||"
先看代码
1)逻辑与
var a = 10;
var b = 0;
var c = b && a++;
var d = a++ && b;
console.log(a);
console.log(b);
console.log(c);
console.log(d);
在逻辑与"&&"中,遵从从左到右的运算规则,先看第一个操作数的值是否能够决定运算的结果,如果是0的话,就会结束运算,在c的运算中,结果c=0;a的值并没有运算,还是10;如果b的值是5,那么就会看第二个操作数,运算结果就由第二个操作数所决定,所以运算结果是c的值是10,而a 的值变成了11。
2)逻辑或
var a = 0;
var b = 2;
var c = a || b++;
console.log(a); // 0
console.log(b); // 3
console.log(c); // 2
在逻辑或中,第一个操作数并不能决定整个式子的运算结果,当a的值为0的时候就会看第二个操作数,只要有一个操作数是true,那么整个式子的运算结果就是真的。所以式子中的c的值是2,b的值自增1,为3.
注意
像0、-0、null、undefined、"",他们在经过隐式类型转化后都会转为false。
//来看一个例子
let x = 1 || 2 && 3 || 4 && 0 || 5;
逻辑与的优先级大于逻辑或的优先级,所以在运算的时候先算逻辑与,剩下来的都是或运算,先看第一个操作数,因为第一个数都已经决定了值,就不用往下运算了。所以x的值是1.
2.同步与异步
在我们平常写的代码中,95%的代码都是同步的,代码从上到下顺序执行,但也有异步的,目前经常遇见的有三种,像事件的绑定、计时器、ajax,这些都是异步的。代码在读取的时候会跳过异步的代码。
//先来看这个例子
<button id="btn1">按钮1</button>
<button id="btn2">按钮2</button>
<button id="btn3">按钮3</button>
<script>
let btns=document.getElementsByTagName("button");
var a=document.getElementById("btn1");
for(var i=0;i<btns.length;i++){
btns[i].onclick=function(){
alert("这是第"+i+"个按钮");
}
}
</script>
// 问题:异步提交是不按顺序执行的,所以代码执行完i的值是3,
// 不会因为按按钮而产生变化,只会弹出第三个按钮,
这里列举了三种解决办法
//第一种,使用闭包
for(var i=0;i<btns.length;i++){
btns[i].onclick=(function(i){
return function f(){
alert("这是第"+i+"个按钮");
}
})(i);
}
第一种使用闭包,既然他会跳过不执行,那么我们就想办法在每次循环让里面的先执行,并且把每次循环的i值保存起来,还有绑定的事件发生;函数可以使用括号包裹,使用IIFE,又因为里面的代码段会引用外面函数的变量,外面函数就保存循环的i值,里面的函数可以引用外面函数的局部变量。并返回地址给onclick,这样就可以使每次点击中的i值为所想的值。
//第二种方法,使用属性
for(var i=0;i<btns.length;i++){
btns[i].index=i;
btns[i].onclick=function(){
alert("这是第"+this.index+"个按钮");
}
}
第二种方法使用变量,给每个按钮设置一个属性,每次循环获取的i值保存在属性里面,每次使用的时候就调用这个属性,就可以那到i值,但是直接使用属性会报错,因为函数中并没有这个属性,这里可以使用this关键字,这里的this指向事件源btns,就可以调用属性了。
//第三种方法,使用let加大括号
for(let i=0;i<btns.length;i++){
btns[i].onclick=function(){
alert("这是第"+i+"个按钮");
}
}
第三种方法使用let加括号,形成块级作用域。每次循环都会形成一个EC,所以i值就成了局部变量,并且不会和其他的EC中的i值发生混淆。
3.数组查重和数组重复统计
//定义个数组
var a=[1,2,1,2,3,5,5,8,8,4,4];
//再定义一个数组,用来存储查重后的数据
var b=[];
//1)定义一个对象,用来判断是否有重复的数据
//2)还用来输出数据的重复次数
var c={};
//使用for循环进行遍历a数组
for(var i=0;i<a.length;i++){
//定义c对象的属性
var t=a[i];
//判断c中是否有a[i]这个属性,如果有跳过,没有
//就把他添加到新的数组中
if(c[t]){ //或者用(c.hasOwnProperty(t))
//同相同的数据,自身加一
c[t]+=1;
}else{
//添加值
b.push(a[i]);
//给对象遍历过的属性赋值,下次对象中就会有这个
//属性,因为要统计重复数量,这里赋值1.
c[t]=1;
}
}
//因为对象中的属性是数字,不能用打点来调用
//只能用[]
4.typeof的不足之处
不足:
当用typeof判断变量的数据类型的时候,如果变量是基本数据类型
那么用typeof判断是ok的,如果是函数function那么也是可以的,但
他判断其他类型的时候就会都报成object的类型,像 math、Array、
RegExp()正则表达式;
改进:
我们可以使用Object.prototype.toString.call()方法来判断数据类型
这里是引用了Object.prototype中的toString方法,通过call()来让他的
this指向call()括号里面的对象,并且让toString方法运行。
<script>
// 利用Object.prototype.toString.call可以非常精确地检测一个数据的数据类型
// toString() Object.prototype上面的方法
console.log(Object.prototype.toString.call(1));
// 此时会把1瞬间包装成对象
console.log(Object.prototype.toString.call("hello"));
// 此时"hello"也瞬间包装成对象了
console.log(Object.prototype.toString.call(true))
var a;
console.log(Object.prototype.toString.call(a))
// call 1)改变toString中的this的指向 指向了{}
// 2)让toString执行
console.log(Object.prototype.toString.call({}))
console.log(Object.prototype.toString.call([]))
function f(){}
console.log(Object.prototype.toString.call(f))
let d = new Date()
console.log(Object.prototype.toString.call(d))
let r = new RegExp();
console.log(Object.prototype.toString.call(r))
</script>
5.new是个运算符,new的作用
//创建一个空对象
//this指向这个空对象
//返回这个空对象
注意:
function F(){
}
var a=new F();
var b=new F;
//在实例化对象的时候,后面的括号可以不写,他的区别是
//能否传参的问题;
6.关于This的结论
这里只是把结论罗列了出来,自己可以尝试推导
1)如果this出现在普通的函数中,this表示window,如果你通过window打点调用一个函数,这个函数中的this也是window。
2)事件绑定,事件处理程序,事件发生时,浏览器帮我们调用这个函数,此函数中的this表示事件源
3)在一个对象中,如果有方法(函数),如果通过这个对象调用方法,方法中的this表示这个对象
4)在IIFE中,this表示window
5)前四点都是在非严格模式下,在严格模式下,调用一个普通函数,this表示und,IIFE中的this也表示und
334

被折叠的 条评论
为什么被折叠?



