js身为一种弱类型的语言,不用像c语言那样要定义int、float、double、string等等数据类型,由于容许变量类型的隐式转换和容许强制类型转换。咱们在定义一个变量的时候,就一个var、let、const搞定,不用担忧数据的类型。好比常见的字符串拼接,用+号能够实现变量和字符串的拼接。 总的来讲,通常的规则是javascript
ToPrimitive是指转换为js内部的原始值,若是是非原始值则转为原始值,调用valueOf()和obj.toString()来实现。valueOf返回对象的值:在控制台,当你定义一个对象按回车,控制台打印的是Object{...},obj.toString()返回对象转字符串的形式,打印的是"[object Object]"前端
![] //false;
+[] // 0
+![] // 0
[]+[] // ""
{}+{}//"[object Object][object Object]"
{}+[]//0
{a:0}+1 // 1
[]+{}//"[object Object]"
[]+![]//"false"
{}+[]//0
![]+[] // "false"
''+{} //"[object Object]"
{}+'' //0
[]["map"]+[] //"function map() { }"
[]["a"]+[] // "undefined"
[][[]] + []// "undefined"
+!![]+[] //"1"
+!![] //1
1-{} //NaN
1-[] //1
true-1 //0
{}-1 //-1
[]==![] //true
复制代码
你们也可能据说过[]!=[],主要是由于他们是引用类型,内存地址不一样因此不相等。那么为何加了一个!就能等于了?不是内存地址仍是不同吗? 这又引出一个问题,符号的优先度vue
1 | . [] () |
2 | ++ — ~ ! |
3 | * / % |
4 | + - + |
5 | << >> |
4 | + - + |
5 | < <= > >= |
4 | + - + |
6 | == != === !== |
能够看见,!优先度是第二,因此先判断!再判断= 给[]取反,会是布尔值,[]的取反的布尔值就是falsejava
非布尔类型转布尔类型:undefined、null 、0、±0、NaN、0长度的字符串=》false,对象=》true 非数字类型转数字类型:undefined=》NaN,null=》0,true=》1,false=》0,字符串:字符串数字直接转数字类型、字符串非数字=》NaNgit
[]也是对象类型(typeof [] == "object"),转为布尔类型的![]就是falsegithub
咱们知道,在比较类型的时候,先会进行各类各样的类型转换。 从开头的表格能够看见,他们比较的时候都是先转换为数字类型。右边是布尔值false,左边为一个空数组对象,对于左边,先进行P操做(ToPrimitive([])),先执行valueOf([])返回的是[],非原始类型,再 [].toString(),返回的是"",那P操做以后,结果就是""了 最后,左边""和右边false对比,他们再转换为数字,就是0==0的问题了数组
咱们知道,数组有本身的一套方法,好比var arr = [1,2];arr.push(1)
,咱们能够写成[1,2].push(1)
,还能够写成[1,2]['push'](1)
,那么前面抛出的问题就解决了ui
[]['push'](1) //[1]
[]["map"] //function map() { [native code] }
[]["map"]+[] // "function map() { [native code] }"
复制代码
咱们能够经过类型转换,得到0和1两个数字,既然能获得这两个数字,那么也能够获得其余的一切数字了: +[] === 0; +!![] === 1 那么, +!![]+!![] ===2,+((+![])+(+!![])+[]+(+![]))===10(注意:中间没[]的话,就是数字的1+0,结果就是1了,有的话就是'1'+''+'0') +((+![])+(+!![])+[]+(+![]))-!![] ===9 简直就是无所不能this
(![]+[])[+[]] //"f"
(![]+[])[+!![]] // "a"
复制代码
(![]+[])是"false",其实(![]+[])[+[]] 就至关于"false"[0],第一个字母,就是f 咱们就能够从上面的那些得到单词的字符串得到其中的字母了 好了,说道这里,要是谁说前端简单,那就给他一个(![]+[])[+!![]+!![]+!![]] +([]+{})[+!![]+!![]]spa
近来有人问这个问题(a==1 && a==2 && a==3) 或者(a===1 && a===2 && a===3) 能不能为true? 事实上是能够的,就是由于在==比较的状况下,会进行类型的隐式转换。前面已经说过,若是参数不是Date对象的实例,就会进行类型转换,先valueOf再obj.toString() 因此,咱们只要改变原生的valueOf或者tostring方法就能够达到效果:
var a = {
num: 0,
valueOf: function() {
return this.num += 1
}
};
var eq = (a==1 && a==2 && a==3);
console.log(eq);
//或者改写他的tostring方法
var num = 0;
Function.prototype.toString = function(){
return ++num;
}
function a(){}
//还能够改写ES6的symbol类型的toP的方法
var a = {[Symbol.toPrimitive]: (function (i) { return function(){return ++i } }) (0)};
复制代码
每一次进行等号的比较,就会调用一次valueOf方法,自增1,因此能成立。固然,若是换个位置就不行了,var eq = (a==2 && a==1 && a==3); 另外,减法也是同理:
var a = {
num: 4,
valueOf: function() {
return this.num -= 1
}
};
var eq = (a==3 && a==2 && a==1);
console.log(eq);
复制代码
若是没有类型转换,===的状况,仍是能够的。跑题... 在vue源码实现双向数据绑定中,就利用了defineProperty方法进行观察,观察到视图层的变化并实时反映到model层。 每一次访问对象中的某一个属性的时候,就会调用这个方法定义的对象里面的get方法。每一次改变对象属性的值,就会访问set方法 在这里,咱们本身定义本身的get方法:
var b = 1
Object.defineProperty(window, 'a', {
get:function() { return b++; }
})
var s = (a===1 && a===2 && a === 3 )
console.log(s)
复制代码
每一次访问a属性,a的属性值就会+1,固然仍是交换位置就不能为TRUE了