The amazing this_javascript trick in Javascript
This in Javascript is a completely different mechanism from other languages, which may confuse some engineers who write other languages.
1. Mistakenly thinking that this points to the function itself
According to the English grammar of this, it is easy to understand this appearing in a function as the function itself. In JavaScript, functions are first-class citizens and can indeed store attribute values when called. But if you use it incorrectly, it may lead to inconsistencies with actual expectations. For specific circumstances, please see the code below
function fn(num){ this.count++; } fn.count = 0; for(var i=0;i<3;i++){ fn(i); } console.log(fn.count); // 0
If this in the fn function points to its own function, then the attribute value of the count attribute should change, but in fact it remains unchanged. For this problem, some people will use scope to solve it, for example, write like this
var data = { count:0 }; function fn(num){ data.count++; } for(var i=0;i<3;i++){ fn(i); } console.log(data.count); //3
Or more directly like this
function fn(num){ fn.count++; } fn.count = 0; for(var i=0;i<3;i++){ fn(i); } console.log(fn.count);//3
Although both methods output the correct results, they avoid the problem of where this is bound. If the working principle of a thing is not clear, it will often lead to headaches and pain, which will lead to ugly code and poor maintainability.
2. This magical binding rule
2.1 Default binding rules
The first one is the most common this binding, take a look at the code below
function fn(){ console.log(window === this); //浏览器环境 } fn(); //true
Function fn is called directly in the global scope without any other modifications. In this case, the default binding of this is used when the function is called, pointing to the global object.
This makes it clear that this in the first example points to the global variable in the fn function, so this.count++ is equivalent to window.count++ (in the browser environment). Of course, it will not affect the count of the fn function. properties have an impact.
One thing to note is that the above situation can only occur in non-strict mode (strict mode). In strict mode, this will be bound to undefined by default. To avoid contamination of global variables.
2.2 Implicit binding rules
If the function is called with an object as the context, the binding of this will change. this will be bound to the object calling this function, see the following code:
var obj = { a:1, fn:function(){ console.log(this.a); } } obj.fn(); //1
Even if the function declaration is not in the object, the this pointer will still change
function fn(){ console.log(this.a); } var obj = { a:1, fn:fn } obj.fn(); //1
It can be seen that the binding of this is not related to the location of the function definition, but to the caller and the calling method.
Under the implicit binding rules, there are some special things that need to be paid attention to.
2.2.1 Multi-layer object calls this pointer
function fn(){ console.log(this.a); } var obj = { a:1, obj2:obj2 } var obj2 = { a:2, obj3:obj3 } var obj3 = { a:3, fn:fn } obj.obj2.obj3.fn(); //3
Under multi-level object references, this points to the object of the called function.
2.2.2 Implicit assignment may be lost
View the code below
function fn(){ console.log(this); } var obj = { fn:fn } var fun = obj.fn; fun(); //window
Although fn refers to obj.fun, the method of calling the function is still without any modification, so this is still bound to window.
There is another situation that is easy for everyone to overlook, that is, when passing parameters, implicit assignment will actually be performed.
function fn(){ console.log(this); } function doFn(fn){ fn(); } var obj = { fn:fn } doFn(obj.fn); //window
Implicit binding of this is not a very recommended method, because it is very likely to be lost. If there are requirements for the binding of this in the business, it is recommended to use explicit binding.
2.3 Explicit binding rules
Explicit binding uses the apply and call methods on the function prototype to bind this. The usage is to pass the object you want to bind as the first parameter.
function fn(){ console.log(this); } var obj = {}; fn.call(obj); //{}
Sometimes you want to bind the this of a function to an object, but do not need to call it immediately. In this case, it cannot be done directly using call or apply.
function fn(){ console.log(this); } function bind(fn){ fn(); } var obj = { fn:fn } bind.call(obj,fn); //window
The above example seems to work, but in fact, this of the bind function is bound to the object obj, but fn is still called without any modification, so fn is still the default binding method.
function fn(){ console.log(this); } function bind(fn,obj){ return function(){ fn.apply(obj,arguments); } } var obj = { fn:fn } var fun = bind(fn,obj); fun(); //obj
这样调用,就可以将灵活多变的 this ,牢牢的控制住了,因为 fn 的调用方式为 apply 调用。所以,this 就被绑定在传入的 obj 对象上,在 ES5 当中,函数的原型方法上多了一个 bind。效果与上面的函数基本一致,具体用法限于篇幅就不多说了。
2.4 new 绑定
new 是一个被很多人误解的一个关键字,但实际上 javascript 的 new 与传统面向对象的语言完全不同。
个人把 new 理解为一种特殊的函数调用,当使用 new 关键字来调用函数的时候,会执行下面操作,
- 创建一个全新的对象
- 将空对象的 __proto__ 指向构造函数的 prototype
- 将新对象的 this 绑定到调用的函数上
- 如果函数返回值为基本类型或者为 this又或者不返回任何值,那么将会返回这个创建的新对象,如果返回了一个对象,那么则会返回这个对象,而不会返回创建的新对象。
function fn(a){ this.a = a; } fn.prototype.hi = function(){ console.log('hi') } var obj = new fn(2); console.log(obj); function fn(a){ this.a = a; return {}; } var obj = new fn(2); console.log(obj); //{}
2.5 特殊的传参
null 和 undefined 也是可以作为 this 的绑定对象的,但是实际上应用的是默认的绑定。
但是这种传参的实际效用是什么呢?
常见的用法是将一个数组展开,作为参数传入参数。比如
function fn(a,b){ console.log('a:',a,'b:',b); } fn.apply(null,[1,2]); // a: 1 b: 2
但是这种用法会有一个坑,那就是如果函数存在了 this ,那么就会应用默认的绑定规则,将 this 绑定在全局对象上,发生于预期不一致的情况。为了代码更加稳健,可以使创建一个比空对象更空的对象。
var obj = Object.create(null); console.log(obj.__proto__); //undefined var obj2 = {} console.log(obj2.__proto__); //Object {}
Object原型上有一个 create 方法,这个方法会创建一个对象,然后将对象的原型指向传入的参数,所以传入 null 的话,产生一个没有 prototype 的对象,所以会比空对象更加"空"。
所以传入这个对象,会比传入 null 更加安全。
var obj = Object.create(null); fn.apply(obj,[1,2]);
2.6 根据作用域来决定 this 的绑定
在 ES6 当中,出现了一个新的函数类型,箭头函数。
如果使用箭头函数,那么就不会使用上面提到的四种 this 绑定方式,而是根据作用域来决定
比较常见的是用于事件函数和定时器的情况。
下面是比较常见的传统 this 写法
function fn(){ var _this = this; setTimeout(function(){ console.log(_this.a); },100) } var obj = { a:2 } fn.call(obj); //2
如果使用箭头函数则可以这么写
function fn(){ setTimeout(()=>{ //this 来源于 fn 函数的作用域 console.log(this.a); },100) } var obj = { a:2 } fn.call(obj); //2
2.7 事件函数当中 this 的绑定机制
如果是在事件函数当中,this 的绑定是指向触发事件的 DOM 元素的,
$('body')[0].addEventListener('click',function(){ console.log(this); },false);
点击 body 元素之后,控制台则会显示 body 元素
3. 小结
如果想判断一个函数的 this 绑定在哪里,首先是找到函数的调用位置,之后是按照规则来判断。
- 如果函数调用时没有任何修饰条件,那么在严格模式下则会绑定到 undefined ,非严格模式下会绑定到全局。
- 如果是用对象做上下文,来对函数进行调用,那么则会绑定到调用的这个对象上。
- 如果是用 call 或者 apply 方法来进行调用的,则会绑定到第一个传入参数上。
- 如果是使用 new 关键字来调用函数的,则会绑定到新创建的那个对象上.
- 如果是在事件函数内,则会绑定到触发事件的那个DOM元素上。
以上就是关于Javascript中神奇的this的相关介绍,希望对大家的学习有所帮助。

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics



How to use WebSocket and JavaScript to implement an online speech recognition system Introduction: With the continuous development of technology, speech recognition technology has become an important part of the field of artificial intelligence. The online speech recognition system based on WebSocket and JavaScript has the characteristics of low latency, real-time and cross-platform, and has become a widely used solution. This article will introduce how to use WebSocket and JavaScript to implement an online speech recognition system.

WebSocket and JavaScript: Key technologies for realizing real-time monitoring systems Introduction: With the rapid development of Internet technology, real-time monitoring systems have been widely used in various fields. One of the key technologies to achieve real-time monitoring is the combination of WebSocket and JavaScript. This article will introduce the application of WebSocket and JavaScript in real-time monitoring systems, give code examples, and explain their implementation principles in detail. 1. WebSocket technology

Introduction to how to use JavaScript and WebSocket to implement a real-time online ordering system: With the popularity of the Internet and the advancement of technology, more and more restaurants have begun to provide online ordering services. In order to implement a real-time online ordering system, we can use JavaScript and WebSocket technology. WebSocket is a full-duplex communication protocol based on the TCP protocol, which can realize real-time two-way communication between the client and the server. In the real-time online ordering system, when the user selects dishes and places an order

How to use WebSocket and JavaScript to implement an online reservation system. In today's digital era, more and more businesses and services need to provide online reservation functions. It is crucial to implement an efficient and real-time online reservation system. This article will introduce how to use WebSocket and JavaScript to implement an online reservation system, and provide specific code examples. 1. What is WebSocket? WebSocket is a full-duplex method on a single TCP connection.

JavaScript and WebSocket: Building an efficient real-time weather forecast system Introduction: Today, the accuracy of weather forecasts is of great significance to daily life and decision-making. As technology develops, we can provide more accurate and reliable weather forecasts by obtaining weather data in real time. In this article, we will learn how to use JavaScript and WebSocket technology to build an efficient real-time weather forecast system. This article will demonstrate the implementation process through specific code examples. We

JavaScript tutorial: How to get HTTP status code, specific code examples are required. Preface: In web development, data interaction with the server is often involved. When communicating with the server, we often need to obtain the returned HTTP status code to determine whether the operation is successful, and perform corresponding processing based on different status codes. This article will teach you how to use JavaScript to obtain HTTP status codes and provide some practical code examples. Using XMLHttpRequest

Usage: In JavaScript, the insertBefore() method is used to insert a new node in the DOM tree. This method requires two parameters: the new node to be inserted and the reference node (that is, the node where the new node will be inserted).

JavaScript is a programming language widely used in web development, while WebSocket is a network protocol used for real-time communication. Combining the powerful functions of the two, we can create an efficient real-time image processing system. This article will introduce how to implement this system using JavaScript and WebSocket, and provide specific code examples. First, we need to clarify the requirements and goals of the real-time image processing system. Suppose we have a camera device that can collect real-time image data
