在 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
上面的代码利用对象字面量创建的对象 person 是 getAge 函数的落脚点, 专业一点的说法就是上下文对象,因此 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 上,此时全局对象上增加了 name 和 age 属性, 还增加了getName 方法(因此可以直接调用 geName 函数)。
构造函数: person1 对象是用 new 操作符调用构造器 Person 创建的新对象,并且会把构造函数内的 this 绑定到这个对象上。
在主流的面向对象的编程语言中(如
Java
,C#
等),this
含义是明确且具体的,即指向当前对象,一般在编译期就绑定了。JavaScript
中的this
关键词是一个比较容易混乱的概念,在不同的场景下,this
会指向不同的对象,原因是由于JavaScript
中的this
在运行期进行的绑定,这是JavaScript
中this
关键词具备多重含义的本质原因。人们对
JavaScript
中this
的绑定常常有两个误解,一是指向函数本身,二是指向函数作用域,这两种想法都是错误的。this
并不指向函数本身,也不指向函数作用域JavaScript
中的this
总是指向一个对象,而具体指向哪个对象是在运行时基于函数的执行环境动态绑定的,而非函数被声明时的环境。既然
this
是由函数的运行环境决定的,那么我们从函数式编程范式来解读一下,我们知道在JavaScript
中 “函数是一等公民”,函数不仅有自己的特性还具有值的一切特性。详情请移步《JavaScript 为什么说函数是一等公民》因此
this
有以下4中情况:this
指向全局对象window
对象this
指向new
操作符调用构造器创建的新对象this
指向这个对象apply()
,call()
,bind()
方法时,this
指向这三个方法的第一个参数下面分别来聊一聊
一、普通函数
在
JavaScript
中,最常见的函数调用类型就是普通函数调用,也就是“光秃秃”的调用this
默认指向的是全局对象window
。这条作为默认绑定规则. 详情请移步 《JavaScript 之 this 的默认绑定规则》默认绑定里的严格模式
在普通函数调用方式之前加上
'use strict'
, 则this
不能绑定到全局对象, 而是指向undefined
。可以看出,在严格模式下,普通函数调用中的
this
实际上指向的是undefined
二、对象的方法
如果函数有所谓的“落脚点”,即有上下文对象时,隐式绑定规则会把函数中的
this
绑定到这个上下文对象。通俗点讲函数作为对象的一个属性上面的代码利用对象字面量创建的对象
person
是getAge
函数的落脚点, 专业一点的说法就是上下文对象,因此this
隐式指向person
对象。这种隐式绑定容易导致隐式丢失,详情请移步《JavaScript 之 this 隐式丢失》三、构造器及 Object.create
2.1、 new 操作符
通过
new
操作符调用构造器创建一个新对象时,this
绑定这个新对象,关于构造器,请移步阅读 《JavaScript 构造器》 一文,在这篇文章中有段代码,我们拿过来继续分析分析上面定义的
Person
函数,既可以作普通函数调用,又可以作构造器调用,普通函数:
person2
对象把Person
当成普通函数调用,没有return
语句,因此person2
的值为undefined
,当作普通函数调用时this
绑定在了全局对象window
上,此时全局对象上增加了name
和age
属性, 还增加了getName
方法(因此可以直接调用geName
函数)。构造函数:
person1
对象是用new
操作符调用构造器Person
创建的新对象,并且会把构造函数内的this
绑定到这个对象上。2.2、Object.create
Object.create()
方法是ECMAScript 5
中新增的方法,这个方法用于创建一个新对象。被创建的对象会继承另一个对象的原型,在创建新对象时还可以指定一些属性。四、显示绑定
JavaScript
为每个函数提供三种显示绑定的方法:apply
,call
,bind
, 而bind
则返回一个新函数。关于三者的详情,请移步 《JavaScript 函数的 call/apply/bind 方法》 。箭头函数中的this绑定
箭头函数是ES6里一个重要特性,其this规则跟以上四条都不一样,ES6的this遵循着JS的词法作用域, 而不是在运行期进行绑定,即在定义时就确定了指向其当前环境的对象,而不是运行是所在的对象,本篇也不做详细介绍,回头拉出来一篇做专门介绍。