Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JavaScript 之 this 绑定/指向 #48

Open
felix-cao opened this issue Sep 4, 2018 · 0 comments
Open

JavaScript 之 this 绑定/指向 #48

felix-cao opened this issue Sep 4, 2018 · 0 comments

Comments

@felix-cao
Copy link
Owner

felix-cao commented Sep 4, 2018

在主流的面向对象的编程语言中(如 Java, C# 等),this 含义是明确且具体的,即指向当前对象,一般在编译期就绑定了。

JavaScript 中的 this 关键词是一个比较容易混乱的概念,在不同的场景下,this 会指向不同的对象,原因是由于 JavaScript 中的 this 在运行期进行的绑定,这是 JavaScriptthis 关键词具备多重含义的本质原因。

人们对 JavaScriptthis 的绑定常常有两个误解,一是指向函数本身,二是指向函数作用域,这两种想法都是错误的。this 并不指向函数本身,也不指向函数作用域

JavaScript 中的 this 总是指向一个对象,而具体指向哪个对象是在运行时基于函数的执行环境动态绑定的,而非函数被声明时的环境。

既然 this 是由函数的运行环境决定的,那么我们从函数式编程范式来解读一下,我们知道在JavaScript 中 “函数是一等公民”,函数不仅有自己的特性还具有值的一切特性。详情请移步《JavaScript 为什么说函数是一等公民》

因此 this 有以下4中情况:

  • 当函数作为普通函数调用时,this 指向全局对象 window 对象
  • 当函数作为构造器调用时,this 指向 new 操作符调用构造器创建的新对象
  • 当函数作为对象的方法调用时,this 指向这个对象
  • 当函数调用其原型对象中的方法 apply(), call(), bind() 方法时,this 指向这三个方法的第一个参数

下面分别来聊一聊

一、普通函数

JavaScript 中,最常见的函数调用类型就是普通函数调用,也就是“光秃秃”的调用 this 默认指向的是全局对象 window。这条作为默认绑定规则. 详情请移步 《JavaScript 之 this 的默认绑定规则》

function up8Wang() {
  console.log('this: ', this);
  console.log('this.local: ', this.local);
}
var local = "In global";
up8Wang(); // this绑定了window, 输出“In global”

默认绑定里的严格模式

在普通函数调用方式之前加上 'use strict', 则 this 不能绑定到全局对象, 而是指向 undefined

'use strict'
function up8Wang() {
  console.log('this: ', this);
  console.log('this.local: ', this.local);
}
var local = "In global";
up8Wang(); // Uncaught TypeError: Cannot read property 'local' of undefined 

可以看出,在严格模式下,普通函数调用中的 this 实际上指向的是 undefined

二、对象的方法

如果函数有所谓的“落脚点”,即有上下文对象时,隐式绑定规则会把函数中的 this 绑定到这个上下文对象。通俗点讲函数作为对象的一个属性

function getAge() {
  console.log('this.age: ', this.age);
}

var person = {
  age: 18,
  getAge: getAge
}
person.getAge(); // this.age: 18

上面的代码利用对象字面量创建的对象 persongetAge 函数的落脚点, 专业一点的说法就是上下文对象,因此 this 隐式指向 person 对象。这种隐式绑定容易导致隐式丢失,详情请移步《JavaScript 之 this 隐式丢失》

三、构造器及 Object.create

2.1、 new 操作符

通过 new 操作符调用构造器创建一个新对象时, this 绑定这个新对象,关于构造器,请移步阅读 《JavaScript 构造器》 一文,在这篇文章中有段代码,我们拿过来继续分析分析

function Person(name, age) {
  console.log('this: ', this);
  this.name = name;
  this.age = age;
  this.getName = function () {
    console.log(this.name);
  }
}

// 当做构造函数使用时
var person1 = new Person('Felix', 100); // this--> person1
person1.getName(); 

// 当做普通函数使用时
var person2 = Person('Felix Cao', 111); // this->window
getName(); // 或window.getName();
console.log('person2: ' + person2);

上面定义的 Person 函数,既可以作普通函数调用,又可以作构造器调用,

  • 普通函数: person2 对象把 Person 当成普通函数调用,没有 return 语句,因此 person2 的值为 undefined,当作普通函数调用时 this 绑定在了全局对象 window 上,此时全局对象上增加了 nameage 属性, 还增加了getName 方法(因此可以直接调用 geName 函数)。

  • 构造函数: person1 对象是用 new 操作符调用构造器 Person 创建的新对象,并且会把构造函数内的 this 绑定到这个对象上。

2.2、Object.create

Object.create() 方法是 ECMAScript 5 中新增的方法,这个方法用于创建一个新对象。被创建的对象会继承另一个对象的原型,在创建新对象时还可以指定一些属性

var person = {
  name:'Felix',
  getName: function(){
     console.log(this.name)
  }
}
var person_ch = Object.create(person);
person_ch.name='Felix Cao'
console.log(person_ch.getName()); // 指向新创建的对象 person_ch

四、显示绑定

JavaScript 为每个函数提供三种显示绑定的方法: apply, call, bind, 而bind则返回一个新函数。关于三者的详情,请移步 《JavaScript 函数的 call/apply/bind 方法》

箭头函数中的this绑定

  箭头函数是ES6里一个重要特性,其this规则跟以上四条都不一样,ES6的this遵循着JS的词法作用域, 而不是在运行期进行绑定,即在定义时就确定了指向其当前环境的对象,而不是运行是所在的对象,本篇也不做详细介绍,回头拉出来一篇做专门介绍。

@felix-cao felix-cao changed the title JavaScript中的this绑定/指向 JavaScript中的 this 绑定/指向 Oct 22, 2018
@felix-cao felix-cao changed the title JavaScript中的 this 绑定/指向 JavaScript this 绑定/指向 Dec 22, 2018
@felix-cao felix-cao changed the title JavaScript this 绑定/指向 JavaScript 之 this 绑定/指向 Dec 22, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant