JavaScrip中的this、作用域代码输出题
一、函数调用中的 this
 
var name = "Global";function printName() {console.log(this.name);
}var obj = {name: "Object",printName: printName
};printName();         // 输出是什么?
obj.printName();     // 输出是什么?
-  printName();- 在全局环境中直接调用函数,this默认指向全局对象(浏览器中是window,Node.js 中是global)。
- this.name等同于- window.name,所以输出- "Global"。
 
- 在全局环境中直接调用函数,
-  obj.printName();- 函数作为对象的方法被调用,this指向调用该方法的对象obj。
- this.name等同于- obj.name,所以输出- "Object"。
 
- 函数作为对象的方法被调用,
二、this 与箭头函数
 
var name = "Global";var obj = {name: "Object",regularFunc: function() {console.log(this.name);},arrowFunc: () => {console.log(this.name);}
};obj.regularFunc();  // 输出是什么?
obj.arrowFunc();    // 输出是什么?
-  obj.regularFunc();- 普通函数,this指向调用者obj。
- 输出 "Object"。
 
- 普通函数,
-  obj.arrowFunc();- 箭头函数,this不绑定到obj,而是继承自外层作用域。
- 在全局作用域中,this指向全局对象,this.name等同于window.name,输出"Global"。
 
- 箭头函数,
三、作用域与闭包
for (var i = 0; i < 3; i++) {setTimeout(function() {console.log(i);}, 1000);
}
以上代码在一秒后会输出什么?
- setTimeout的回调函数在事件队列中等待,循环结束后才执行。
- 此时,i已经变为3,所以会输出三次3。(因为var i是全局作用变量,每次设定回调函授,执行时i已经到达3)
如何修复问题:
方法一:使用 let 替代 var
for (let i = 0; i < 3; i++) {setTimeout(function() {console.log(i);}, 1000);
}
-  let声明的变量具有 块级作用域,在每次循环中,i都是一个新的变量。
-  setTimeout回调函数中的i会各自引用循环中当前的i值。
-  输出结果: -  0 
-  1 
-  2 
 
-  
方法二:使用立即执行函数表达式(IIFE)创建闭包
for (var i = 0; i < 3; i++) {(function(j) {setTimeout(function() {console.log(j);}, 1000);})(i);
}
-  使用 IIFE(Immediately Invoked Function Expression)创建了一个新的作用域。 
-  将当前的 i值作为参数j传递给 IIFE,j是 IIFE 内部的局部变量。
-  setTimeout回调函数中的console.log(j);会引用 IIFE 中的j,即当前循环中的i值。
-  输出结果 -  0 
-  1 
-  2 
 
-  
方法三:使用 forEach 等迭代方法
 
[0, 1, 2].forEach(function(i) {setTimeout(function() {console.log(i);}, 1000);
});
-  forEach的回调函数中,i是每次迭代的当前元素。
-  i在每次迭代中都是一个新的变量,不会相互干扰。
-  输出结果: -  0 
-  1 
-  2 
 
-  
四、this 与函数内的函数
 
var length = 10;function fn() {console.log(this.length);
}var obj = {length: 5,method: function(fn) {fn();                   // 输出是什么?  10arguments[0]();         // 输出是什么?  1}
};obj.method(fn);
arguments[0]()解释:
- arguments对象是函数内部的一个局部变量,包含了函数调用时的所有参数。
- arguments.length:表示传递给函数的参数数量。
- arguments是一个类数组对象,具有索引和- length属性。
- arguments[0]就是传入的- fn函数。
- arguments对象的- length属性表示传入参数的数量,此处为- 1。
- 相当于方法调用:arguments对象调用其属性0上的函数。
- 等价于:arguments[0].call(arguments);
五、对象方法中的 this 绑定
 
var obj = {name: "Alice",getName: function() {return this.name;}
};var getName = obj.getName;console.log(getName());     // 输出是什么? undefined
console.log(obj.getName()); // 输出是什么? Alice
-  getName();- 函数被赋值给变量并在全局环境中调用,this指向全局对象。
- 如果全局对象没有 name属性,输出undefined。
 
- 函数被赋值给变量并在全局环境中调用,
-  obj.getName();- 方法作为对象的属性调用,this指向obj。
- 输出 "Alice"。
 
- 方法作为对象的属性调用,
六、构造函数与原型链中的 this
 
function Person(name) {this.name = name;
}Person.prototype.getName = function() {return this.name;
};var person = new Person("Bob");console.log(person.getName()); // 输出是什么?
- Person是构造函数,- new关键字创建一个新的对象,- this指向新创建的对象。
- person.getName()中,- this指向- person对象。
- 输出 "Bob"。
