es5 es6 this指向

深入剖析JavaScript中this关键字的指向规则,包括全局作用域、对象方法、构造函数及特殊情况下的指向,以及ES6箭头函数中this的行为。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

例子1:

function a(){
    var user = "追梦子";
    console.log(this.user); //undefined
    console.log(this); //Window
}
a();

按照我们上面说的this最终指向的是调用它的对象,这里的函数a实际是被Window对象所点出来的,下面的代码就可以证明。

function a(){
    var user = "追梦子";
    console.log(this.user); //undefined
    console.log(this);  //Window
}
window.a();

和上面代码一样吧,其实alert也是window的一个属性,也是window点出来的。

例子2:

复制代码

var o = {
    user:"追梦子",
    fn:function(){
        console.log(this.user);  //追梦子
    }
}
o.fn();

复制代码

  这里的this指向的是对象o,因为你调用这个fn是通过o.fn()执行的,那自然指向就是对象o,这里再次强调一点,this的指向在函数创建的时候是决定不了的,在调用的时候才能决定,谁调用的就指向谁,一定要搞清楚这个。

 

其实例子1和例子2说的并不够准确,下面这个例子就可以推翻上面的理论。

如果要彻底的搞懂this必须看接下来的几个例子

本文出处:追梦子博客

例子3:

复制代码

var o = {
    user:"追梦子",
    fn:function(){
        console.log(this.user); //追梦子
    }
}
window.o.fn();

复制代码

  这段代码和上面的那段代码几乎是一样的,但是这里的this为什么不是指向window,如果按照上面的理论,最终this指向的是调用它的对象,这里先说个而外话,window是js中的全局对象,我们创建的变量实际上是给window添加属性,所以这里可以用window点o对象。

  这里先不解释为什么上面的那段代码this为什么没有指向window,我们再来看一段代码。

复制代码

var o = {
    a:10,
    b:{
        a:12,
        fn:function(){
            console.log(this.a); //12
        }
    }
}
o.b.fn();

复制代码

  这里同样也是对象o点出来的,但是同样this并没有执行它,那你肯定会说我一开始说的那些不就都是错误的吗?其实也不是,只是一开始说的不准确,接下来我将补充一句话,我相信你就可以彻底的理解this的指向的问题。

  情况1:如果一个函数中有this,但是它没有被上一级的对象所调用,那么this指向的就是window,这里需要说明的是在js的严格版中this指向的不是window,但是我们这里不探讨严格版的问题,你想了解可以自行上网查找。

  情况2:如果一个函数中有this,这个函数有被上一级的对象所调用,那么this指向的就是上一级的对象。

  情况3:如果一个函数中有this,这个函数中包含多个对象,尽管这个函数是被最外层的对象所调用,this指向的也只是它上一级的对象,例子3可以证明,如果不相信,那么接下来我们继续看几个例子。

复制代码

var o = {
    a:10,
    b:{
        // a:12,
        fn:function(){
            console.log(this.a); //undefined
        }
    }
}
o.b.fn();

复制代码

尽管对象b中没有属性a,这个this指向的也是对象b,因为this只会指向它的上一级对象,不管这个对象中有没有this要的东西。

还有一种比较特殊的情况,例子4:

复制代码

var o = {
    a:10,
    b:{
        a:12,
        fn:function(){
            console.log(this.a); //undefined
            console.log(this); //window
        }
    }
}
var j = o.b.fn;
j();

复制代码

这里this指向的是window,是不是有些蒙了?其实是因为你没有理解一句话,这句话同样至关重要。

  this永远指向的是最后调用它的对象,也就是看它执行的时候是谁调用的,例子4中虽然函数fn是被对象b所引用,但是在将fn赋值给变量j的时候并没有执行所以最终指向的是window,这和例子3是不一样的,例子3是直接执行了fn。

  this讲来讲去其实就是那么一回事,只不过在不同的情况下指向的会有些不同,上面的总结每个地方都有些小错误,也不能说是错误,而是在不同环境下情况就会有不同,所以我也没有办法一次解释清楚,只能你慢慢地的去体会。

 

构造函数版this:

function Fn(){
    this.user = "追梦子";
}
var a = new Fn();
console.log(a.user); //追梦子

  这里之所以对象a可以点出函数Fn里面的user是因为new关键字可以改变this的指向,将这个this指向对象a,为什么我说a是对象,因为用了new关键字就是创建一个对象实例,理解这句话可以想想我们的例子3,我们这里用变量a创建了一个Fn的实例(相当于复制了一份Fn到对象a里面),此时仅仅只是创建,并没有执行,而调用这个函数Fn的是对象a,那么this指向的自然是对象a,那么为什么对象a中会有user,因为你已经复制了一份Fn函数到对象a中,用了new关键字就等同于复制了一份。

  除了上面的这些以外,我们还可以自行改变this的指向,关于自行改变this的指向请看JavaScript中call,apply,bind方法的总结这篇文章,详细的说明了我们如何手动更改this的指向。

 

更新一个小问题当this碰到return时

复制代码

function fn()  
{  
    this.user = '追梦子';  
    return {};  
}
var a = new fn;  
console.log(a.user); //undefined

复制代码

再看一个

复制代码

function fn()  
{  
    this.user = '追梦子';  
    return function(){};
}
var a = new fn;  
console.log(a.user); //undefined

复制代码

再来

复制代码

function fn()  
{  
    this.user = '追梦子';  
    return 1;
}
var a = new fn;  
console.log(a.user); //追梦子

复制代码

复制代码

function fn()  
{  
    this.user = '追梦子';  
    return undefined;
}
var a = new fn;  
console.log(a.user); //追梦子

复制代码

什么意思呢?

  如果返回值是一个对象,那么this指向的就是那个返回的对象,如果返回值不是一个对象那么this还是指向函数的实例。

复制代码

function fn()  
{  
    this.user = '追梦子';  
    return undefined;
}
var a = new fn;
console.log(a); //fn {user: "追梦子"}

复制代码

  还有一点就是虽然null也是对象,但是在这里this还是指向那个函数的实例,因为null比较特殊。

复制代码

function fn()  
{  
    this.user = '追梦子';  
    return null;
}
var a = new fn;  
console.log(a.user); //追梦子

es6 this 

// ES6
function foo() {
  setTimeout(() => {
    console.log('id:', this.id);
  }, 100);
}

// ES5
function foo() {
  var _this = this;

  setTimeout(function () {
    console.log('id:', _this.id);
  }, 100);
}
<think>我们正在讨论ES5ES6的特性差异。根据引用[1][2][3][4][5]的内容,ES6(ECMAScript 2015)是JavaScript的一个重大更新,引入了许多新特性以解决ES5的不足。下面我将详细列出ES5ES6的主要特性差异,并解释它们之间的区别。 ### 一、ES5的新特性 ES5(ECMAScript 5)于2009年发布,主要特性包括: 1. **严格模式(Strict Mode)** 通过`"use strict";`启用,提供更严格的语法检查,避免一些常见错误[^1][^3]。 2. **JSON支持** 新增`JSON.parse()`和`JSON.stringify()`方法,用于解析和序列化JSON数据[^1][^3]。 3. **数组方法增强** 新增数组迭代方法: - `Array.prototype.forEach()` - `Array.prototype.map()` - `Array.prototype.filter()` - `Array.prototype.reduce()` - `Array.prototype.some()` - `Array.prototype.every()`[^1][^3][^5] 4. **对象属性控制** 引入`Object.defineProperty()`方法,用于定义或修改对象属性的特性(如可枚举性、可配置性、可写性等)[^1][^3]。 5. **函数绑定** 新增`Function.prototype.bind()`方法,用于永久绑定函数的`this`值[^1][^3]。 ### 二、ES6的新特性 ES6(ECMAScript 2015)于2015年发布,是JavaScript的一次重大更新,主要特性包括: 1. **块级作用域变量声明** - `let`:声明块级作用域的变量 - `const`:声明块级作用域的常量(不可重新赋值)[^2][^4][^5] 2. **箭头函数(Arrow Functions)** 简化函数写法,自动绑定当前上下文的`this`值: ```javascript // ES5 var add = function(a, b) { return a + b; }; // ES6 const add = (a, b) => a + b; ``` 3. **模板字符串(Template Literals)** 支持多行字符串和嵌入表达式: ```javascript const name = "Alice"; console.log(`Hello, ${name}!`); // 输出: Hello, Alice! ``` 4. **解构赋值(Destructuring Assignment)** 从数组或对象中提取值并赋值给变量: ```javascript // 数组解构 const [x, y] = [1, 2]; // 对象解构 const { name, age } = { name: "Bob", age: 30 }; ``` 5. **类(Class)** 提供更接近传统面向对象语言的类语法: ```javascript class Person { constructor(name) { this.name = name; } sayHello() { console.log(`Hello, ${this.name}!`); } } ``` 6. **模块化(Modules)** 支持`import`和`export`语法: ```javascript // math.js export const add = (a, b) => a + b; // main.js import { add } from './math.js'; ``` 7. **Promise对象** 提供更优雅的异步编程解决方案: ```javascript const fetchData = () => new Promise((resolve, reject) => { // 异步操作 }); ``` 8. **Symbol类型** 新增基本数据类型,表示唯一值: ```javascript const id = Symbol("uniqueId"); ``` 9. **扩展运算符(Spread Operator)** 用于展开数组或对象: ```javascript const arr1 = [1, 2]; const arr2 = [...arr1, 3, 4]; // [1, 2, 3, 4] ``` 10. **函数参数默认值** 允许为函数参数设置默认值: ```javascript function greet(name = "Guest") { return `Hello, ${name}!`; } ``` ### 三、ES5ES6的核心区别 | **特性** | **ES5** | **ES6** | **区别说明** | |--------------------|----------------------------------|----------------------------------|------------------------------| | **作用域** | 函数作用域(var) | 块级作用域(let/const) | 避免变量提升问题[^2][^4] | | **函数写法** | function关键字 | 箭头函数(=>) | 简化代码,自动绑定this | | **字符串处理** | 字符串拼接(+) | 模板字符串(``) | 支持多行和嵌入表达式 | | **异步处理** | 回调函数 | Promise/async/await | 解决回调地狱问题[^2] | | **面向对象** | 构造函数+原型 | class语法糖 | 更接近传统OOP | | **模块化** | 无原生支持(依赖CommonJS等) | 原生import/export | 浏览器直接支持模块加载 | | **数据结构** | 数组和普通对象 | 新增Set/Map/WeakSet/WeakMap | 提供更丰富的数据结构 | ### 四、实际应用场景对比 1. **变量声明** - ES5:`var`存在变量提升问题 ```javascript console.log(x); // undefined (不报错) var x = 5; ``` - ES6:`let`/`const`避免提升 ```javascript console.log(y); // ReferenceError let y = 10; ``` 2. **回调函数处理** - ES5:多层嵌套回调(回调地狱) ```javascript getData(function(a) { getMoreData(a, function(b) { // ... }); }); ``` - ES6:Promise链式调用 ```javascript getData() .then(a => getMoreData(a)) .then(b => { /* ... */ }); ``` ### 五、兼容性与工具链 | **方面** | **ES5** | **ES6** | |----------------|------------------------------|------------------------------| | **浏览器支持** | 所有主流浏览器完全支持 | 现代浏览器支持,旧浏览器需转译 | | **转译工具** | 不需要 | 需Babel等工具转译为ES5[^2] | | **开发效率** | 较低(代码冗余) | 更高(语法简洁) | > 总结:ES6通过引入块级作用域、箭头函数、类、模块化等现代语言特性,显著提升了JavaScript的开发效率和代码可维护性,是当前前端开发的主流选择[^2][^4]。对于旧浏览器环境,可通过Babel等工具将ES6代码转译为ES5。 §§相关问题§§ 1. 如何将ES6代码转换为ES5以兼容旧浏览器? 2. ES6的箭头函数与普通函数在`this`绑定上有何本质区别? 3. ES6的Class语法在底层是如何通过原型链实现的? 4. 为什么说Promise解决了回调地狱问题?请举例说明。</think>### ES5ES6特性差异详解 #### 一、核心差异概览 | **特性分类** | **ES5** | **ES6** | **核心区别** | |--------------------|--------------------------------------|--------------------------------------|----------------------------------| | **作用域管理** | `var`(函数作用域) | `let`/`const`(块级作用域) | 避免变量提升和污染全局作用域[^4] | | **函数特性** | `function`声明 | 箭头函数、参数默认值、rest参数 | 简化语法 + 自动绑定`this`[^2] | | **面向对象** | 构造函数+原型链 | `class`语法糖 | 接近传统OOP写法[^5] | | **异步处理** | 回调函数 | `Promise`/`async/await` | 解决回调地狱[^2] | | **数据结构** | Array/Object | `Set`/`Map`/`Symbol`/`WeakMap` | 扩展数据操作能力[^5] | | **字符串处理** | 拼接字符串(`+`) | 模板字符串(`` ` ``) | 支持多行和嵌入表达式[^4] | | **模块化** | 无原生支持 | `import`/`export` | 浏览器原生模块支持[^3] | --- #### 二、ES5核心特性(2009年发布) 1. **严格模式** ```javascript "use strict"; // 禁止隐式变量声明,提高安全性[^1] ``` 2. **JSON处理** ```javascript JSON.parse('{"name":"Alice"}'); // 字符串→对象 JSON.stringify({name:"Bob"}); // 对象→字符串[^3] ``` 3. **数组方法增强** ```javascript [1,2,3].map(x => x*2); // [2,4,6] [1,2,3].filter(x => x>1); // [2,3][^5] ``` 4. **对象属性控制** ```javascript Object.defineProperty(obj, 'key', { writable: false // 设置不可变属性[^1] }); ``` --- #### 三、ES6革命性特性(2015年发布) 1. **块级作用域变量** ```javascript if (true) { let local = 10; // 仅在此块生效 const PI = 3.14; // 常量声明 } console.log(local); // ReferenceError[^4] ``` 2. **箭头函数** ```javascript // ES5 function add(a, b) { return a + b; } // ES6 const add = (a, b) => a + b; // 自动绑定外层this[^2] ``` 3. **解构赋值** ```javascript // 数组解构 const [x, y] = [1, 2]; // x=1, y=2 // 对象解构 const { name, age } = { name: "Alice", age: 30 };[^4] ``` 4. **类与继承** ```javascript class Person { constructor(name) { this.name = name; } greet() { console.log(`Hello, ${this.name}!`); } } class Student extends Person { constructor(name, grade) { super(name); this.grade = grade; } }[^5] ``` 5. **Promise异步处理** ```javascript fetch('/api/data') .then(response => response.json()) .then(data => console.log(data)) .catch(error => console.error(error));[^2] ``` 6. **模块化系统** ```javascript // math.js export const add = (a, b) => a + b; // app.js import { add } from './math.js'; console.log(add(2, 3)); // 5[^3] ``` --- #### 四、关键区别解析 1. **作用域机制** - ES5:`var`存在变量提升 ```javascript console.log(x); // undefined (不报错) var x = 5; ``` - ES6:`let`/`const`形成暂时性死区 ```javascript console.log(y); // ReferenceError let y = 10; ``` 2. **`this`绑定差异** - ES5函数中`this`由调用者决定 ```javascript const obj = { value: 10, getValue: function() { console.log(this.value); // 动态绑定 } }; ``` - ES6箭头函数继承外层`this` ```javascript const obj = { value: 10, getValue: () => { console.log(this.value); // 始终指向定义时的this } }; ``` 3. **循环机制优化** ES5的`for-in`循环问题: ```javascript var arr = [10, 20, 30]; for (var i in arr) { console.log(i); // 输出"0","1","2" (字符串!) } ``` ES6的`for-of`解决方案: ```javascript const arr = [10, 20, 30]; for (const item of arr) { console.log(item); // 直接输出数字 10,20,30 } ``` --- #### 五、兼容性与开发建议 | **场景** | **推荐方案** | |------------------|--------------------------------------| | 旧浏览器兼容 | 使用Babel转译ES6ES5[^2] | | 常量声明 | 优先用`const`,次选用`let` | | 异步操作 | 用`Promise`+`async/await`替代回调 | | 模块组织 | 使用ES6模块化代替IIFE[^3] | | 框架开发 | Vue/React全面拥抱ES6特性 | > 总结:ES6通过**块级作用域**、**箭头函数**、**类语法**、**Promise**等特性,解决了ES5在作用域管理、异步处理、代码组织等方面的痛点,使JavaScript成为更现代化的开发语言[^2][^4]。当前主流项目应优先采用ES6+语法开发,通过构建工具保证兼容性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值