When it comes to this, many abstract concepts that make people dizzy come out. Here I will only talk about the core point - this in a function always points to the object that calls it. , the following stories will all revolve around this point.
[Story] There is a young man named "Dis" (this). One day, Dis accidentally traveled to a different world called "Gavaskeli" (javascript). At this moment, Dis Being penniless, the first thing he has to do is to find his place to stay - the object to call the function
default binding of this
[Story - Line 1] If Dis (this) is not available until dark Unable to find a place to take him in, he was about to live the life of an African refugee. At this time, a kind-hearted magician village chief - window savior appeared like a savior: Stay in my house first!
[Text]
When a function does not have a clear calling object, that is, when it is simply called as an independent function , the default binding will be used for this of the function: bound to the global window object
function fire () {
console.log(this === window)
}
fire(); // 输出true
I believe the above example will be useful for everyone Most people are very simple, but sometimes it can be confusing if we change the example:
function fire () {
// 我是被定义在函数内部的函数哦! function innerFire() {
console.log(this === window)
}
innerFire(); // 独立函数调用}
fire(); // 输出true
The function innerFire is declared and called in an external function fire, so who does its this point to? Still window
Many people may be concerned about the impact of the scope of the fire function on innerFire, but we only need to seize our theoretical weapon-when there is no clear calling object, we will use this of the function Default binding: Bind to the global window object to get the correct answer
The enhanced version of the example below also outputs true
var obj = {
fire: function () {
function innerFire() {
console.log(this === window)
}
innerFire(); // 独立函数调用 }
}
obj.fire(); //输出 true
[Note] In this example, obj The call to .fire() actually uses the implicit binding of this. This is what I will talk about below. I will continue to explain this example next.
[Summary] Everything function is called as an independent function , no matter where it is, its behavior is the same as calling it directly in the global environment
The hidden meaning of this Type binding
[Story - Route 2] When Dis (this) traveled to the different world "Gavaskeli" (javascript), he happened to have some money with him, so he found a hotel to stay. Come down
When a function is "contained" by an object, we say that the this of the function is implicitly bound to the object. This At this time, you can directly access other properties in the bound object through this, such as the following a property
##
var obj = {
a: 1,
fire: function () {
console.log(this.a)
}
}
obj.fire(); // 输出1
Now we need to do some deeper thinking about the common code operations. First, the following two paragraphs The effect achieved by the code is the same:
// 我是第一段代码function fire () {
console.log(this.a)
}
var obj = {
a: 1,
fire: fire
}
obj.fire(); // 输出1
// 我是第二段代码var obj = {
a: 1,
fire: function () {
console.log(this.a)
}
}
obj.fire(); // 输出1
The fire function does not make any difference because it is defined inside and outside the obj object. That is to say, in the above two forms of implicit binding, fire The a property in obj can still be accessed through this, which tells us:
1. This is dynamically bound, or it is bound during the code running period rather than during the writing period
2. The independence of functions from objects, the problem of loss of this transmission
(下面的描述可能带有个人的情感倾向而显得不太严谨,但这是因为我希望阅读者尽可能地理解我想表达的意思)
隐式绑定下,作为对象属性的函数,对于对象来说是独立的
基于this动态绑定的特点,写在对象内部,作为对象属性的函数,对于这个对象来说是独立的。(函数并不被这个外部对象所“完全拥有”)
我想表达的意思是:在上文中,函数虽然被定义在对象的内部中,但它和“在对象外部声明函数,然后在对象内部通过属性名称的方式取得函数的引用”,这两种方式在性质上是等价的(而不仅仅是效果上)
定义在对象内部的函数只是“恰好可以被这个对象调用”而已,而不是“生来就是为这个对象所调用的”
借用下面的隐式绑定中的this传递丢失问题来说明:
var obj = {
a: 1, // a是定义在对象obj中的属性 1 fire: function () {
console.log(this.a)
}
}
var a = 2; // a是定义在全局环境中的变量 2var fireInGrobal = obj.fire;
fireInGrobal(); // 输出 2
上面这段简单代码的有趣之处在于: 这个于obj中的fire函数的引用( fireInGrobal)在调用的时候,行为表现(输出)完全看不出来它就是在obj内部定义的,其原因在于:我们隐式绑定的this丢失了!! 从而 fireInGrobal调用的时候取得的this不是obj,而是window
上面的例子稍微变个形式就会变成一个可能困扰我们的bug:
var a = 2;var obj = {
a: 1, // a是定义在对象obj中的属性 fire: function () {
console.log(this.a)
}
}
function otherFire (fn) {
fn();
}
otherFire(obj.fire); // 输出2
在上面,我们的关键角色是otherFire函数,它接受一个函数引用作为参数,然后在内部直接调用,但它做的假设是参数fn仍然能够通过this去取得obj内部的a属性,但实际上, this对obj的绑定早已经丢失了,所以输出的是全局的a的值(2),而不是obj内部的a的值(1)
在一串对象属性链中,this绑定的是最内层的对象
在隐式绑定中,如果函数调用位置是在一串对象属性链中,this绑定的是最内层的对象。如下所示:
var obj = {
a: 1,
obj2: {
a: 2,
obj3: {
a:3,
getA: function () {
console.log(this.a)
}
}
}
}
obj.obj2.obj3.getA(); // 输出3
this的显式绑定:(call和bind方法)
【故事——线路3】 迪斯(this)穿越来异世界“伽瓦斯克利”(javascript),经过努力的打拼,积累了一定的财富,于是他买下了自己的房子
上面我们提到了this的隐式绑定所存在的this绑定丢失的问题,也就是对于 “ fireInGrobal = obj.fire”
fireInGrobal调用和obj.fire调用的结果是不同的,因为这个函数赋值的过程无法把fire所绑定的this也传递过去。这个时候,call函数就派上用场了
call的基本使用方式: fn.call(object)
fn是你调用的函数,object参数是你希望函数的this所绑定的对象。
fn.call(object)的作用:
1.即刻调用这个函数(fn)
2.调用这个函数的时候函数的this指向object对象
例子:
var obj = {
a: 1, // a是定义在对象obj中的属性 fire: function () {
console.log(this.a)
}
}
var a = 2; // a是定义在全局环境中的变量 var fireInGrobal = obj.fire;
fireInGrobal(); // 输出2fireInGrobal.call(obj); // 输出1
原本丢失了与obj绑定的this参数的fireInGrobal再次重新把this绑回到了obj
但是,我们其实不太喜欢这种每次调用都要依赖call的方式,我们更希望:能够一次性 返回一个this被永久绑定到obj的fireInGrobal函数,这样我们就不必每次调用fireInGrobal都要在尾巴上加上call那么麻烦了。
怎么办呢? 聪明的你一定能想到,在fireInGrobal.call(obj)外面包装一个函数不就可以了嘛!
var obj = {
a: 1, // a是定义在对象obj中的属性 fire: function () {
console.log(this.a)
}
}
var a = 2; // a是定义在全局环境中的变量 var fn = obj.fire;var fireInGrobal = function () {
fn.call(obj) //硬绑定}
fireInGrobal(); // 输出1
如果使用bind的话会更加简单
var fireInGrobal = function () {
fn.call(obj) //硬绑定}
可以简化为:
var fireInGrobal = fn.bind(obj);
call和bind的区别是:在绑定this到对象参数的同时:
1.call将立即执行该函数
2.bind不执行函数,只返回一个可供执行的函数
【其他】:至于apply,因为除了使用方法,它和call并没有太大差别,这里不加赘述
在这里,我把显式绑定和隐式绑定下,函数和“包含”函数的对象间的关系比作买房和租房的区别。
因为this的缘故
在隐式绑定下:函数和只是暂时住在“包含对象“的旅馆里面,可能过几天就又到另一家旅馆住了
在显式绑定下:函数将取得在“包含对象“里的永久居住权,一直都会”住在这里“
new绑定
【故事】 迪斯(this)组建了自己的家庭,并生下多个孩子(通过构造函数new了许多个对象)
执行new操作的时候,将创建一个新的对象,并且将构造函数的this指向所创建的新对象