同样根据浮点数的定义,非整数的 Number 类型无法用 (= 也不行) 来比较,console.log( 0.1 + 0.2 == 0.3)
输出的结果是 false,这是由于浮点数运算的精度问题导致的。
比较0.1+0.2 == 0.3的正确方式是使用 JavaScript 提供的最小精度值:
console.log( Math.abs(0.1 + 0.2 - 0.3) <= Number.EPSILON)
这段代码结果就是 true 了。
for of 实质执行的是对象中key为Symbol.iterator的方法,该方法返回一个含有next方法的对象,next方法返回一个含有value和done的对象。
for of会重复执行next函数,返回value的值,done是next函数终止的条件。
下面是一个示范。
var o = new Object
o[Symbol.iterator] = function() {
var v = 0
return {
next: function() {
return { value: v++, done: v > 10 }
}
}
};
for(var v of o)
console.log(v); // 0 1 2 3 ... 9
使用这种方法,for of 能做到的事情更多了,需要注意的是,你的同事可能会说:救命!他的 for of 怎么和我的不一样!。
{ a: 5 }
,求 b > 3 为 true ?同事一段代码中,b = { a: 5 }
,后面在b > 3的比较中却为true,我的代码中却为false,这不科学。
对象怎能与数字比较?
实际是,这涉及到js的比较机制,js在比较前会进行类型的转换,而在对象到number、对象到string的转换时,会进行拆箱操作。
简单的说,就是访问对象中的valueOf方法和toString方法,将其返回值用作对比。
在对象到number的转换中优先使用valueOf方法,而在对象到string的转换时优先使用toString方法。
重回问题,b = { a: 5 }
得情况下,如何使 b > 3 呢?
首先我们确定它的执行流程,先将b替换成b.valueOf(),然后做比较。
那我们是不是修改valueOf()的返回值就可以了呢。
我们为b对象添加一个valueOf函数,覆盖原生的valueOf。再进行比较。
b.valueOf = function() {
return this.a
}
console.log(b, b > 3)
// {a: 5, valueOf: ƒ} true
可以看到 b = { a: 5 }
时, b > 3 为 true 了。
接下来的诡异事件是,当我将一个对象的属性赋值后,该对象属性却发生了和赋值不同的变化。
a.num = 1
console.log(a.num) // 3
要清楚这一点,首先要清楚对象的属性分两种,数据属性和访问器属性,数据属性就是常用的属性。
访问器属性可以通过两个函数来定义,get函数取属性值时被调用,set函数在设置属性值时被调用。
get和set函数的返回值就是读或取得值,它允许使用者在写和读属性时,得到完全不同的值。
回到刚才得问题,我写入了1,取到了3,可能是num属性实际为访问器属性。
var a = {
_num: null,
set num(val) {
this._num = val + 2
},
get num() {
return this._num
}
}
a.num = 1
console.log(a.num) // 3
代码的执行顺序会影响执行结果,看看下面这段代码的执行结果是什么呢?
new Promise(resolve => {
console.log(1);
setTimeout(() => console.log(2),0)
Promise.resolve().then(() => console.log(3))
resolve();
}).then(() => console.log(4))
console.log(5)
promise用来实现异步操作,也就是操纵代码执行顺序的一种方式。
promise接受一个回调函数,该回调函数会立刻执行,它是同步的。
回调函数中接受一个参数res,res()意味着代码结束,可以进行接下来的异步逻辑了,异步逻辑通过then绑定。
其中setTimeout会提交一个任务到等待队列,等代码全部执行完后,去执行等待队列可执行的逻辑。
上面的代码中,执行结果为1、5、3、4、2,你猜对了吗?
with实际上是不被推荐的使用,尤其是内部包含变量定义的时候。
举个栗子。
如果你要更改下面这段代码,代码当前的执行结果应该比较明了。
var b = 1;
void function(){
var env = {b:1};
b = 2;
console.log("In function b:", b); // 2
}();
console.log("Global b:", b); // 2
你在此基础上加了一段代码,猜一猜这次的执行结果是什么?
var b = 1;
void function(){
var env = {b:1};
b = 2;
console.log("In function b:", b);
with(env) {
var b = 3;
console.log("In with b:", b);
}
}();
console.log("Global b:", b);
with中,创建b=3实际上是为env对象的b赋值,读取b是读取env对象的b属性,with创建了一个以env对象为基础的环境。
但是with中声明的var变量也会被提升到function中,这意味着function中有了一个b。
执行结果:
In function b: 2
In with b: 3
Global b: 1
函数定义方式有很多种。
如果你看到下面的代码。
var a = 1
function showThis() {
console.log(a);
}
showThis()
你一时觉得这样定义函数太麻烦了,顺手给改了。
var a = 1
var showThis = () => {
console.log(a);
...
}
showThis()
一运行,代码却崩了,这是为啥?
仔细一看,下面还有一行。
var o = {
b: 1,
showThis: showThis
}
o.showThis();
原来,箭头函数和普通函数不同的是,普通函数的this是指向调用者的,箭头函数的this的执向定义时的外界环境。
将普通函数换为箭头的定义方式,该取的值取不到了,代码就崩了。
在o.showThis()中,如果我们使用this.b去取值,使用箭头函数定义的showThis方法会到全局中找b,自然找不到。