Javascript是一门很灵活的语言,我们可以使用它动态地实现各种各样的功能。但是动态带来便利的同时,也存在一些令人费解的行为,稍不注意就会进入误区一个接着一个的坑。虽然我使用JavaScript的时间还不算长,也是遇到了一些有意思的场景,一开始百思不得其解,弄清楚之后又让我哭笑不得。现在就来跟大家一起分享一下。
语法糖带来的浅拷贝
先来预测一下下面代码的输出内容:
const user = {name: 'zong',location: {city: 'Shanghai',state: 'Shanghai'}
};
const copy = Object.assign({}, user);
// 或者
// const copy = { ...user };
copy.location.city = 'Suzhou';
console.log('original: ', user.location);
console.log('copy:', copy.location);
输出结果应该是:
original: {city: 'Shanghai',state: 'Shanghai'
}
copy: {city: 'Shanghai',state: 'Shanghai'
}
咦?为什么操作复制的对象会修改原来的对象呢?这是因为Object.assign
跟spread operator
只做了一层浅拷贝
,这意味着只有对象的第一层属性会被复制,如果某个属性是个嵌套的对象,那么只有引用会被复制,所以我们操作修改的对象的属性影响到了原来的对象。
所以在我们这个例子中copy
的location
属性将仍然指向原来user
对象对应的location
属性。
JavaScript从右向左赋值的行为
function display() {var a = b = 10;
}display();console.log('b', typeof b === 'undefined');
console.log('a', typeof a === 'undefined');
输出是:
b false
a true
这是因为JavaScript赋值操作符是从右向左的,这意味着我们的赋值操作也是从右向左来的,手先b
会被赋值10
,然后它被赋给了a
。
所以:
function display() {var a = b = 10;
}
等同于:
function display() {b = 10;var a = b;
}
所以b
没有用var
声明成了一个全局变量,所以在外部可以被访问到,而a
只是个局部变量,所以外部会打印出a === undefined
为true
。
但是如果上面的代码在严格模式
中执行的话,情况又不一样了,由于严格模式不允许创建全局变量所以这段代码会直接抛出异常。
提升
var num = 8;var display = function () {console.log(num);var number = 20;
};display();
猜猜这里的输出结果是什么?它不是8
而是undefined
,这又是为什么?
这是因为JavaScript里面有个现象叫提升
。提升
是JavaScript中把变量声明移到当前作用域最顶部的一种行为。
所以上面的代码可以转换成如下:
var num = 8;var display = function () {var num;console.log(num);num = 20;
};display();
我们可以看到只有声明被移到了函数的最顶端,而赋值操作还在原地,所以这边num
由于还未赋值会打印出undefined
。
delete的作用对象
const num = 1;const result = (function () {delete num;return num;
})();console.log(result);
这边的代码不会报出任何错,因为我们是在number
类型上使用的delete
,它还是会打印出1
。
The delete
操作符被用来删除一个对象的属性,在这儿num
并不是一个对象所以它会返回这个变量对应的值,也就是1
。
const num = 1;const result = (function (num) {delete num;return num;
})(10);console.log(result);
上面的代码将输出10
。
这边我们把10
作为参数传给函数,同样地delete
在这里对原始类型也不起作用,所以会照常打印出10
。
好啦,今天的分享就到这里啦,主要是在使用JavaScript的过程中可能会经常遇到的一些细节问题,希望能给大家带来一丢丢的收获,happy coding~