这里有新鲜出炉的 Javascript 教程,程序狗速度看过来!
undefined
Javascript 是一种由 Netscape 的 LiveScript 发展而来的原型化继承的基于对象的动态类型的区分大小写的客户端脚本语言,主要目的是为了解决服务器端语言,比如 Perl,遗留的速度问题,为客户提供更流畅的浏览效果。
本文主要对 JavaScript 易错知识点进行整理和汇总。需要的朋友可以看下,希望对大家有所帮助
前言
undefined
本文是我学习 JavaScript 过程中收集与整理的一些易错知识点,将分别从变量作用域,类型比较,this 指向,函数参数,闭包问题及对象拷贝与赋值这 6 个方面进行由浅入深的介绍和讲解,其中也涉及了一些 ES6 的知识点。
undefined
JavaScript 知识点
undefined
1. 变量作用域
undefined
- var a = 1;
- function test() {
- var a = 2;
- console.log(a); // 2
- }
- test();
undefined
上方的函数作用域中声明并赋值了 a,且在 console 之上,所以遵循就近原则输出 a 等于 2。
undefined
- var a = 1;
- function test2() {
- console.log(a); // undefined
- var a = 2;
- }
- test2();
undefined
上方的函数作用域中虽然声明并赋值了 a,但位于 console 之下,a 变量被提升,输出时已声明但尚未被赋值,所以输出 "undefined"。
undefined
- var a = 1;
- function test3() {
- console.log(a); // 1
- a = 2;
- }
- test3();
undefined
上方的函数作用域中 a 被重新赋值,未被重新声明,且位于 console 之下,所以输出全局作用域中的 a。
undefined
- let b = 1;
- function test4() {
- console.log(b); // b is not defined
- let b = 2;
- }
- test4();
undefined
上方函数作用域中使用了 ES6 的 let 重新声明了变量 b,而 let 不同于 var 其不存在变量提升的功能,所以输出报错 "b is not defined"。
undefined
- function test5() {
- let a = 1; {
- let a = 2;
- }
- console.log(a); // 1
- }
- test5();
undefined
上方的函数作用域中用 let 声明了 a 为 1,并在块级作用域中声明了 a 为 2,因为 console 并不在函数内的块级作用域中,所以输出 1。
undefined
2. 类型比较
undefined
- var arr = [],
- arr2 = [1];
- console.log(arr === arr2); // false
undefined
上方两个不同的数组比较,console 为 false。
undefined
- var arr = [],
- arr2 = [];
- console.log(arr === arr2); // false
undefined
上方两个相同的数组比较,因为数组与数组比较恒为 false,所以 console 为 false。
undefined
- var arr = [],
- arr2 = {};
- console.log(typeof(arr) === typeof(arr2)); // true
undefined
上方利用 typeof 比较数组和对象,因为 typeof 获取 NULL、数组、对象的类型都为 object,所以 console 为 true。
undefined
- var arr = [];
- console.log(arr instanceof Object); // true
- console.log(arr instanceof Array); // true
undefined
上方利用 instanceof 判断一个变量是否属于某个对象的实例,因为在 JavaScript 中数组也是对象的一种,所以两个 console 都为 true。
undefined
3.this 指向
undefined
- var obj = {
- name: 'xiaoming',
- getName: function() {
- return this.name
- }
- };
- console.log(obj.getName()); // 'xiaoming'
undefined
上方对象方法中的 this 指向对象本身,所以输出 "xiaoming"。
undefined
- var obj = {
- myName: 'xiaoming',
- getName: function() {
- return this.myName
- }
- };
- var nameFn = obj.getName;
- console.log(nameFn()); // undefined
undefined
上方将对象中的方法赋值给了一个变量,此时方法中的 this 也将不再指向 obj 对象,从而指向 window 对象,所以 console 为 "undefined"。
undefined
- var obj = {
- myName: 'xiaoming',
- getName: function() {
- return this.myName
- }
- };
- var obj2 = {
- myName: 'xiaohua'
- };
- var nameFn = obj.getName;
- console.log(nameFn.apply(obj2)); // 'xiaohua'
undefined
上方同样将 obj 对象中的方法赋值给了变量 nameFn,但是通过 apply 方法将 this 指向了 obj2 对象,所以最终 console 为'xiaohua'。
undefined
4. 函数参数
undefined
- function test6() {
- console.log(arguments); // [1, 2]
- }
- test6(1, 2);
undefined
上方利用函数中的 arguments 对象获取传入函数的参数数组,所以输出数组 [1, 2]。
undefined
- function >
- var args = [1, 2];
- function test9() {
- console.log(arguments); // [1, 2, 3, 4]
- }
- Array.prototype.push.call(args, 3, 4);
- test9(...args);
undefined
上方利用 Array.prototype.push.call()方法向 args 数组中插入了 3 和 4,并利用 ES6 延展操作符 (…) 将数组展开并传入 test9,所以 console 为[1, 2, 3, 4]。
undefined
5. 闭包问题
undefined
- var elem = document.getElementsByTagName('div'); // 如果页面上有5个div
- for (var i = 0; i < elem.length; i++) {
- elem[i].onclick = function() {
- alert(i); // 总是5
- };
- }
undefined
上方是一个很常见闭包问题,点击任何 div 弹出的值总是 5,因为当你触发点击事件的时候 i 的值早已是 5,可以用下面方式解决:
undefined
- var elem = document.getElementsByTagName('div'); // 如果页面上有5个div
- for (var i = 0; i < elem.length; i++) { (function(w) {
- elem[w].onclick = function() {
- alert(w); // 依次为0,1,2,3,4
- };
- })(i);
- }
undefined
在绑定点击事件外部封装一个立即执行函数,并将 i 传入该函数即可。
undefined
6. 对象拷贝与赋值
undefined
- var obj = {
- name: 'xiaoming',
- age: 23
- };
- var newObj = obj;
- newObj.name = 'xiaohua';
- console.log(obj.name); // 'xiaohua'
- console.log(newObj.name); // 'xiaohua'
undefined
上方我们将 obj 对象赋值给了 newObj 对象,从而改变 newObj 的 name 属性,但是 obj 对象的 name 属性也被篡改,这是因为实际上 newObj 对象获得的只是一个内存地址,而不是真正 的拷贝,所以 obj 对象被篡改。
undefined
- var obj2 = {
- name: 'xiaoming',
- age: 23
- };
- var newObj2 = Object.assign({},
- obj2, {
- color: 'blue'
- });
- newObj2.name = 'xiaohua';
- console.log(obj2.name); // 'xiaoming'
- console.log(newObj2.name); // 'xiaohua'
- console.log(newObj2.color); // 'blue'
undefined
上方利用 Object.assign() 方法进行对象的深拷贝可以避免源对象被篡改的可能。因为 Object.assign() 方法可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。
undefined
- var obj3 = {
- name: 'xiaoming',
- age: 23
- };
- var newObj3 = Object.create(obj3);
- newObj3.name = 'xiaohua';
- console.log(obj3.name); // 'xiaoming'
- console.log(newObj3.name); // 'xiaohua'
undefined
我们也可以使用 Object.create() 方法进行对象的拷贝,Object.create() 方法可以创建一个具有指定原型对象和属性的新对象。
undefined
结语
undefined
学习 JavaScript 是一个漫长的过程,不能一蹴而就。希望本文介绍的几点内容能够帮助学习 JavaScript 的同学更加深入的了解和掌握 JavaScript 的语法,少走弯路。
来源: http://www.phperz.com/article/17/0524/329891.html