使用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;")构造函数。当函数以函数表达式的方式声明时,等号后可以是匿名函数,也可以带函数名,但函数名只能在函数体内引用。