ES6中setTimeout函数的执行上下文

本文探讨了在ES5和ES6中使用setTimeout时this关键字的行为差异。通过具体示例展示了ES5中setTimeout内的函数执行上下文为全局上下文,而ES6的箭头函数则保留了定义时的上下文。

简介:setTimeout,延迟执行函数里的执行上下文

(1)ES5中,setTimeout里面的函数的执行上下文为全局上下文,举例来说:

function log(){
  setTimeout(function(){console.log(this.id)},100)
}
var id=42
log.call({id:21})

//输出的结果为42

我们可以看到setTimeout,被延迟执行的函数,里面的this,指向的是全局作用域,也就是这个函数的上下文为全局上下文。

(2)在ES6的箭头函数中,setTimeout里面,如果执行了一个箭头函数,那么这个函数的执行上下文为定义这个箭头函数所在的函数。

function log(){
  setTimeout(()=>{
     console.log(this.id)
  },100)
}
var id=42;
log.call({id:21})

//这次输出的是21

总结:

因为ES6中,箭头函数的this,规定的指向定义这个箭头函数所在的那个函数。于是这里箭头函数里面的this,就固定bind了{id:21}。

<think>我们正在讨论ES6箭头函数与传统函数的区别。根据用户要求,我们需要使用中文回答,并遵循格式要求(行内数学表达式用$...$,独立公式用$$...$$并单独成段)。同时,在回答末尾生成相关问题,并在引用处添加引用标识。 首先,我们整理箭头函数与传统函数的主要区别: 1. **语法**: - 箭头函数语法更简洁。 - 例如:`const add = (a, b) => a + b;` 2. **`this`的绑定**: - 传统函数:`this`的值取决于函数如何被调用(动态作用域)。 - 箭头函数:`this`继承自外围作用域(词法作用域),即定义时的作用域。 3. **构造函数**: - 传统函数:可以用作构造函数,使用`new`关键字创建实例。 - 箭头函数:不能用作构造函数,使用`new`会抛出错误。 4. **`arguments`对象**: - 传统函数:有`arguments`对象,包含所有传入参数。 - 箭头函数:没有自己的`arguments`对象,但可以访问外围函数的`arguments`(使用剩余参数`...args`替代)。 5. **方法定义**: - 在对象方法中使用传统函数时,`this`指向调用该方法的对象。 - 使用箭头函数作为对象方法时,`this`指向定义时的上下文(通常是全局对象或外层函数上下文),这通常不是预期的。 6. **原型属性**: - 传统函数:有`prototype`属性(用于构造函数)。 - 箭头函数:没有`prototype`属性。 7. **生成器函数**: - 箭头函数不能用作生成器函数(不能使用`yield`)。 8. **重复命名参数**: - 传统函数:在非严格模式下允许重复命名参数,严格模式不允许。 - 箭头函数:不允许重复命名参数(无论严格模式与否)。 9. **`super`和`new.target`**: - 箭头函数没有自己的`super`或`new.target`绑定,它们从外围函数中获取。 下面我们按照要求组织回答,注意在适当的地方使用数学表达式(虽然这个主题可能不需要太多数学表达式,但如果有涉及,比如在解释作用域时可以用到变量,我们可以用行内数学表达式表示变量等)。 另外,在回答中,我们可能会引用一些外部资源,但由于用户没有提供具体的引用来源,我们可以参考权威文档(如MDN)并在末尾添加引用标识。注意:用户要求“引用的段落末尾自然地添加引用标识”,所以如果引用了某个观点,需要添加。 由于问题本身不涉及数学公式,但为了满足系统指令,我们可以在解释作用域时提到变量作用域,用行内数学表达式表示变量(如$x$)或函数(如$f(x)$)等。但注意不要牵强。 现在开始组织回答:</think>### ES6箭头函数与传统函数的区别 ES6箭头函数(`=>`)与传统函数(`function`)在JavaScript中有以下核心区别: 1. **`this`绑定机制** - 传统函数的`this`由调用方式动态决定(如对象方法、构造函数等): ```javascript const obj = { value: 42, traditional: function() { console.log(this.value) } // 输出42 }; obj.traditional(); ``` - 箭头函数的`this`继承自**定义时**的外层作用域(词法作用域),不受调用方式影响: ```javascript const obj = { value: 42, arrow: () => console.log(this.value) // 输出undefined(继承全局this) }; obj.arrow(); ``` [^1] 2. **构造函数能力** - 传统函数可作为构造函数(使用`new`关键字): ```javascript function Person(name) { this.name = name; } const p = new Person("Alice"); // 有效 ``` - 箭头函数**不能**作为构造函数: ```javascript const Arrow = () => {}; const a = new Arrow(); // TypeError: Arrow is not a constructor ``` 3. **`arguments`对象** - 传统函数内置`arguments`对象存储参数: ```javascript function sum() { return [...arguments].reduce((a,b) => a+b); } sum(1,2,3); // 6 ``` - 箭头函数**无**`arguments`对象,需用剩余参数`...args`替代: ```javascript const sum = (...args) => args.reduce((a,b) => a+b); ``` 4. **语法简洁性** - 箭头函数省略`function`关键字,单参数可省括号,单表达式可省`return`: ```javascript // 传统函数 const square = function(x) { return x*x; }; // 箭头函数 const square = x => x*x; ``` 5. **原型与方法属性** - 传统函数有`prototype`属性(用于原型继承): ```javascript function Foo() {} console.log(Foo.prototype); // 存在 ``` - 箭头函数**无**`prototype`属性: ```javascript const Bar = () => {}; console.log(Bar.prototype); // undefined ``` 6. **生成器函数** 箭头函数**不能**用作生成器(无法使用`yield`关键字)。 --- ### 典型应用场景对比 | **场景** | 传统函数 | 箭头函数 | |------------------------|----------|----------| | 对象方法 | ✅ | ❌(`this`错误) | | 构造函数 | ✅ | ❌ | | 事件处理器(需动态`this`) | ✅ | ❌ | | 回调函数(需固定`this`) | ❌ | ✅ | | 立即执行函数(IIFE) | ✅ | ✅ | > 示例:回调函数中固定`this` > ```javascript > // 传统函数需要bind绑定 > setTimeout(function() { console.log(this.id) }.bind(this), 100); > > // 箭头函数自动继承this > setTimeout(() => console.log(this.id), 100); > ``` > [^2]