使用js的过程中出现过一些意向不到的输出,在这里做个整理,已备查阅。
一:
["0", "1", "2"].map(parseInt)
原因:输出结果为[0, NaN, NaN]。原因是map传递给parseInt的参数为3个,分别是element,index,array,指元素的值,索引,整个数组。parseInt接收2个参数,第一个为待转换字符,第二个为进制(2-36,0代表10进制)。当element为"1"时,index为1,不满足2-36之间;当element为"2"时,index为2,二进制时不能有数字大于等于2,因此仍是NaN。
二:
NaN === NaN NaN == NaN
原因:返回值均为false,false。NaN不等于自身,要判断是否是NaN,要用isNaN()方法。
isNaN(NaN)
三:
在尝试自己写双向绑定时,发现通过Object.defineProperty()方法设置属性时,无法通过set外部修改属性的值,如下:
var obj = {}; Object.defineProperty(obj, 'txt', { get: function () { return obj; }, set: function (newValue) { document.getElementById('input').value = newValue; document.getElementById('show').innerHTML = newValue; } }); document.getElementById('input').addEventListener('keyup', function (e) { obj.txt = e.target.value; });
在console中打印obj.txt,输出为undefined,说明obj.txt = e.target.value仅将将值传进set函数,并未真正改变obj.txt的值。尝试在set中赋值,如下:
var obj = {}; Object.defineProperty(obj, 'txt', { get: function () { return obj; }, set: function (newValue) { obj.txt = newValue; document.getElementById('input').value = newValue; document.getElementById('show').innerHTML = newValue; } }); document.getElementById('input').addEventListener('keyup', function (e) { obj.txt = e.target.value; });
会发生死循环,因为在set中又进行了赋值,会再次调用set。
解决办法,构造函数,保存变量。
function defineProperty(obj, key){ var val; Object.defineProperty(obj, 'txt', { get: function () { return val; }, set: function (newValue) { if(newValue === val){ return; } val = newValue; document.getElementById('input').value = newValue; document.getElementById('show').innerHTML = newValue; } }); } var obj = {}; defineProperty(obj, 'txt'); document.getElementById('input').addEventListener('keyup', function (e) { obj.txt = e.target.value; });
四:
0.2-0.1 == 0.3-0.2
结果为false,因为0.2-0.1=0.1,0.3-0.2=0.09999999。
五:
var a = []; for (var i = 0; i<3; i++){ a[i] = function () { console.log(i); }; } a[0]();
输出为3。a[i]绑定的i为全局变量i,当调用a[i]时,会输出全局变量i。
var a = []; for (let i = 0; i<3; i++){ a[i] = function () { console.log(i); }; } a[0]();
输出为0。a[i]绑定局部变量i,因此每次声明都会重新分配一个i给a[i],因此当调用a[i]时,输出的是单独分配的i。
六:
参考阮一峰的ESMAScript6入门,var变量提升会导致如下输出。
var tmp = new Date(); function f() { console.log(tmp); if (false) { var tmp = 'hello world'; } } f(); // undefined
var会“穿过”if作用域,因此相当于外层会先声明var tmp,此时tmp未赋值,因此打印undefined。
七:
function test(x) { console.log(x); var x = 2; console.log(x); } test(1);
输出为1,2。
for (var x = 0; x < 3; x++) { console.log(x); var x = 2; console.log(x); }
输出为0,2。上面两个例子说明function、for括号内的作用域是花括号{}的父作用域。
for (var x = 0; x < 3; x++) { let x = 2; console.log(x); }
输出为3个2。此时内部使用let重新声明x,但不会改变圆括号内父作用域的同名变量。
八:
var test1 = [1, 2], test2 = 3; function func1(test) { test[0] += 1; } function func2(test) { test += 1; } func1(test1); func2(test2); console.log(test1);//[ 2, 2 ] console.log(test2);//3
函数参数传递是按值传参,但当传入的是对象时,传入的是指向对象的指针。因此在函数内修改对象会改变对象本身。
九:
function test (x, x, x) { console.log(x); } test(1, 2, 3);//3
非严格模式下,函数可以有同名参数,后面的会覆盖前面的。
十:
var a = {n:1}; var b = a; a.x = a = {n:2}; console.log(a.x); console.log(b.x);
结果为undefined,{n:2}。由此可知多个等号的赋值顺序:先获取最左侧的地址,再由右向左依次赋值。
function test () { let a = b = 1; } test(); console.log(b);//1
如果多个等号赋值的中间某一变量之前未声明,则在非严格模式下提升为全局变量,严格模式下报错。
十一:
(function f(f){ return typeof f();//"number" })(function(){ return 1; });
传入的参数是一个函数,函数执行后返回1,因此typeof 1是number。虽然函数名和参数名同名,但互不影响。
function test (test) { console.log(typeof test); } test(1);//number
上面的例子说明函数参数中有与函数名同名的变量时,会覆盖函数名,说明参数域是一个独立的子作用域。
var test = function test2() { console.log(typeof test2); }; test();//function console.log(typeof test);//function console.log(typeof test2);//undefined
函数可以通过三种方式声明:1、函数声明;2、函数表达式;3、new Function("x","return x;")构造函数。当函数以函数表达式的方式声明时,等号后可以是匿名函数,也可以带函数名,但函数名只能在函数体内引用。