Maison  >  Article  >  interface Web  >  Compréhension approfondie de ce pointeur en javascript

Compréhension approfondie de ce pointeur en javascript

小云云
小云云original
2018-03-17 16:21:101537parcourir

Cet article partage principalement avec vous une compréhension approfondie du pointeur this en JavaScript Lors de l'écriture de Java, s'il est utilisé de manière incorrecte, idea signalera directement une erreur !

Par exemple...



En programmation orientée objet là Il y a deux concepts importants : L'un est une classe et l'autre est un objet instancié. Une classe est un concept abstrait, pour utiliser une métaphore vivante, une classe est comme un moule, et les objets instanciés le sont. moule.Pour les produits manufacturés, les objets instanciés sont les choses réelles dont nous avons besoin.Les classes et les objets instanciés sont étroitement liés, mais les fonctions des classes ne peuvent pas remplacer les objets instanciés lors de leur utilisation, tout comme les moules et les moules. les utilisations des deux sont différentes.

Nous pouvons voir à partir du code ci-dessus que le pointeur this ne peut être utilisé que dans les objets instanciés dans le langage Java. Le pointeur this est égal à l'objet instancié, et l'opérateur point est ajouté après cela. après l'opérateur, il y a ce qu'il a, comme : le nom, le travail, les mains, les pieds, etc.

En faitLe concept logique de ce pointeur en javascript est aussi un objet instancié Ceci est cohérent avec le pointeur this du langage java, mais le pointeur this en javascript est différent de celui du langage java. java. C'est très difficile à comprendre. Personnellement, je pense qu'il y a trois raisons fondamentales :

Raison 1 : Javascript est un langage de programmation fonctionnel. Ce qui est étrange, c'est qu'il possède également ce pointeur, qui s'affiche. qu'il s'agit d'une programmation fonctionnelle. Le langage est également un langage orienté objet. Pour être plus précis, la fonction en JavaScript est une fonction d'ordre supérieur dans le langage de programmation. En même temps, la fonction en JavaScript peut également être utilisée comme constructeur.Cette construction Les fonctions peuvent créer des objets instanciés, de sorte que le pointeur de ce pointeur continuera à changer lors de l'exécution de la méthode, ce qui est difficile à contrôler.

Raison 2 : La portée globale en JavaScript a un grand impact sur le pointeur this. À partir de l'exemple Java ci-dessus, nous pouvons voir que le pointeur this ne peut être modifié qu'après avoir utilisé le nouveau. opérateur. Cela prend effet, mais cela en JavaScript prendra également effet sans effectuer de nouvelle opération. À ce stade, cela pointera souvent vers la fenêtre de l'objet global.

Raison 3 : Les opérateurs call et apply en JavaScript peuvent modifier le pointeur this à volonté. Cela semble très flexible, mais cette approche déraisonnable détruit notre compréhension de la signification originale de ce pointeur et rend également difficile sa mise en œuvre. écrire du code. Il est difficile de comprendre à quoi cela signifie réellement



Les trois raisons ci-dessus violent toutes le Utilisation traditionnelle de ce pointeur Méthodes, elles ont toutes des compréhensions différentes de ce principe traditionnel, et dans le développement réel, les trois raisons sont souvent liées, donc, ça, tout est dans les nuages...


Livre d'introduction : Javascript professionnel pour les développeurs web, - la version avancée est comme ceci :

cela pointe toujours vers la méthode d'appel Objet!



var name="zhoulujun";

function say(){

console.log(this.name)

}

say(); //zhoulujun



Dans la balise script nous pouvons utiliser ce pointeur directement , ce pointeur (pointant vers l'objet fenêtre, le résultat) est l'objet fenêtre , ils sont égaux même si le triple signe égal est utilisé. La portée globale interfère souvent avec notre compréhension des fonctionnalités du langage JavaScript. L'essence de cette interférence est la suivante :

Dans le langage JavaScript la portée globale peut être comprise comme l'objet fenêtre , rappelez-vous que Window est un objet plutôt qu'une classe, ce qui signifie la fenêtre est un objet instancié. Ce processus d'instanciation est complété par le moteur JavaScript lorsque la page est chargée. Les éléments de la page entière sont condensés dans cette fenêtre. objet, car les programmeurs ne peuvent pas contrôler et exploiter ce processus d'instanciation via des langages de programmation, nous n'avons donc pas le sentiment de construire ce pointeur pendant le développement, et l'ignorons souvent. Cela interfère avec notre compréhension du fait que ce pointeur pointe vers une fenêtre dans le. situation de code.

Ici, cela pointe vers l'objet fenêtre, donc this.name->zhoulujun !



Lors de l'exécution de la fonction say, JavaScript créera un contexte d'exécution (contexte d'exécution), qui contient toutes les informations nécessaires pendant l'exécution de la fonction say. Le contexte d'exécution possède également sa propre chaîne de portée Lorsque la fonction s'exécute, le moteur JavaScript initialise d'abord la chaîne de portée du contexte d'exécution à partir de la chaîne de portée à l'aide de la fonction say.

Ici, vous pouvez vous rappeler grossièrement :

var myObj={
name:"zhoulujun",
fn:function(){
console.log(this.name)
}
};
myObj.fn();



这里的this指向obj,因为fn()运行在obj里面……

然后再来看……

var name="zhoulujun";
function say(){
console.log(this.name)
console.log(this)
}
say();
function say2(){
var site="zhoulujun.cn";
console.log(this.site);
}
say2();


myObj2={
site:"zhoulujun.cn",
fn:function(){
console.log(this.site)
}
}



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

然后,我们更深入(受不了 …………

myObj3={
site:"zhoulujun.cn",
andy:{
site:"www.zhoulujun.cn",
fn:function(){
console.log(this.site)
}
}
};
myObj3.andy.fn();



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

如果,你实在理解不了,就这么样背下来吧!

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

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

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

这样既对了吗??深入点(就受不了了……讨厌……

myObj3={
site:"zhoulujun.cn",
andy:{
site:"www.zhoulujun.cn",
fn:function(){
console.log(this)
console.log(this.site)
}
}
};
//    myObj3.andy.fn();
var fn=myObj3.andy.fn;
fn();



其实,这里的 fn等价于

fn:function(age){

console.log(this.name+age);

}

下面我们来聊聊函数的定义方式:声明函数和函数表达式

我们最上面第一个案例定义函数的方式在javascript语言称作声明函数,第二种定义函数的方式叫做函数表达式,这两种方式我们通常认为是等价的,但是它们其实是有区别的,而这个区别常常会让我们混淆this指针的使用,我们再看看下面的代码:



Pourquoi say peut-il être exécuté mais say3 ne peut pas ? C'est parce que :



Pourquoi le résultat d'impression de say3 est indéfini, j'ai mentionné dans l'article précédent que indéfini ? est La zone de pile de la mémoire a déjà le nom de la variable, mais il n'y a pas de valeur de variable dans la zone de pile. En même temps, il n'y a pas d'objet spécifique dans la zone de tas . le moteur JavaScript analyse les définitions de variables pendant le préchargement, mais le résultat de l'impression de ftn01 est très surprenant, puisque la définition de fonction terminée est imprimée et que le code n'est pas exécuté dans l'ordre, cela ne peut expliquer qu'un seul problème :

Dans le langage JavaScript, les fonctions sont définies en déclarant des fonctions, et le moteur JavaScript est en cours de prétraitement. Les opérations de définition et d'affectation des fonctions sont terminées ici. J'ajouterai ici les caractéristiques du prétraitement en JavaScript. l'environnement d'exécution. Dans l'article précédent, j'ai mentionné qu'il existe deux grands types d'environnements d'exécution : l'environnement d'exécution global et l'environnement d'exécution local. L'environnement d'exécution se reflète à travers les variables de contexte. .Le prétraitement est une autre façon de construire l'environnement d'exécution.En bref, l'objectif principal du prétraitement et de la construction de l'environnement d'exécution est de clarifier la définition des variables, de distinguer les limites des variables, mais il existe certaines différences pour déclarer des fonctions lors de la construction de la portée globale. ou le prétraitement des variables globales. La déclaration des fonctions terminera les opérations de définition et d'affectation des variables en même temps, nous voyons donc les résultats d'exécution du code ci-dessus. Puisque les fonctions déclarées sont complétées lors de la construction de la portée globale, les fonctions déclarées sont toutes des attributs de l'objet window. Cela explique pourquoi, peu importe où nous déclarons la fonction, la fonction déclarée appartient finalement à l'objet window.

Il est recommandé de jeter un œil ici - l'ordre d'exécution d'une classe Java :

http://www.zhoulujun.cn/zhoulujun/html/java/javaBase/7704.html



其实在javascript语言里任何匿名函数都是属于window对象,它们也都是在全局作用域构造时候完成定义和赋值,但是匿名函数是没有名字的函数变量,但是在定义匿名函数时候它会返回自己的内存地址,如果此时有个变量接收了这个内存地址,那么匿名函数就能在程序里被使用了,因为匿名函数也是在全局执行环境构造时候定义和赋值,所以匿名函数的this指向也是window对象,所以上面代码执行时候fn的this都是指向window,因为javascript变量名称不管在那个作用域有效,堆区的存储的函数都是在全局执行环境时候就被固定下来了,变量的名字只是一个指代而已。

类似的情况(面试题喜欢这么考!)……比如:



this都是指向实例化对象,前面讲到那么多情况this都指向window,就是因为这些时候只做了一次实例化操作,而这个实例化都是在实例化window对象,所以this都是指向window。我们要把this从window变成别的对象,就得要让function被实例化,那如何让javascript的function实例化呢?答案就是使用new操作符。

再来看 构造函数:

function  User(){
this.name="zhoulujun";
console.log(this);
}
var andy=new User();
console.log(andy.name)



why andy 的name  是 zhoulujun,那是:因为:

new关键字可以改变this的指向,将这个this指向对象andy,

那andy什么时候又成了思密达,oh,no,is Object?

Parce qu'utiliser le new mot-clé consiste à créer une instance d'objet (lire les choses importantes en silence trois fois)

Ici, nous utilisons la variable andy pour créer une instance d'utilisateur User (équivalent à copier Une copie de User dans l'objet andy). À ce stade, il est simplement créé et non exécuté. L'objet qui appelle cette fonction User est l'objet andy, donc naturellement cela pointe vers l'objet andy. Alors pourquoi y a-t-il un nom dans. l'objet User ? Parce que vous avez déjà Une copie de la fonction User est copiée dans l'objet andy. Utiliser le mot-clé new équivaut à copier une copie.

programmeur Java : Class user=new User(); cela semble familier...



function est à la fois une fonction et un objet. Lorsque function est une fonction, elle peut également être utilisée comme constructeur de javascript On pense souvent que les classes et les constructeurs sont combinés en un seul Bien sûr, il n'y a pas de concept de classe dans la spécification du langage JavaScript , mais ma compréhension peut l'être. utilisés comme constructeurs et fonctions ordinaires. Une différence qui sera plus facile à comprendre .

Ci-dessous je poste l'explication du nouvel opérateur dans "Programmation JavaScript avancée" :

Le nouvel opérateur provoquera les modifications suivantes dans le constructeur :

1 . Créez un nouvel objet ;

2. Attribuez la portée du constructeur au nouvel objet (pour que cela pointe vers le nouvel objet) ; 🎜>3. Exécutez le code dans le constructeur (ajoutez des attributs à ce nouvel objet )

4.       返回新对象

……

妈的:读的那么拗口,不明觉厉…………看图……还不

不明白……

var myObj5={
name:"andy"
};
var myObj6=new Object();
myObj6.name="andy";
function  say5(name){
console.log(name)
}
var say6=new Function("name","console.log(name)");
console.log(myObj5)
console.log(myObj6)
say5("andy");
say6("andy");



还不明白,就请奶奶买块豆腐,撞死算了……

第四点也要着重讲下,记住构造函数被new操作,要让new正常作用最好不能在构造函数里写return,没有return的构造函数都是按上面四点执行,有了return情况就复杂了

return这王八蛋……



那么我这样呢……



does it have to be like this?Tell me why(why),is there something I have missed?

Tell me why(why),cos I don't understand…………



那是因为……because of u?no  return……



所以:如果返回的是基本类型,就会丢掉…只能返回Object类型……typeof  xx ===“object”

看到called 没有?什么鬼!!

其实new关键字会创建一个空的对象,然后会自动调用一个函数apply方法,将this指向这个空对象,这样的话函数内部的this就会被这个空的对象替代。

var a={
name:"andy",
site:"zhoulujun.cn",
fn:function(age){
console.log(this.name+age);
}
};
var b={
name:"zhoulujun",
site:"www.zhoulujun.cn",
fn:function(age){
console.log(this.name+age);
}
};
a.fn(2); //andy2
a.fn.call(b,2) //zhoulujun2
a.fn.apply(b,[2])//zhoulujun2
当然,还有bind……
var arr = [1, 2];
var add = Array.prototype.push.bind(arr, 3);
// effectively the same as arr.push(3)
add();
// effectively the same as arr.push(3, 4)
add(4);
console.log(arr);
// <- [1, 2, 3, 3, 4]
在下面的例子,this将无法在作用域链中保持不变。这是规则的缺陷,并且常常会给业余开发者带来困惑。
function scoping () {
console.log(this);
return function () {
console.log(this);
};
}
scoping()();
// <- Window
// <- Window
有一个常见的方法,创建一个局部变量保持对this的引用,并且在子作用域中不能有同命变量。子作用域中的同名变量将覆盖父作用域中对this的引用。
function retaining () {
var self = this;
return function () {
console.log(self);
};
}
retaining()();
// <- Window
除非你真的想同时使用父作用域的this,以及当前this值,由于某些莫名其妙的原因,我更喜欢是使用的方法.bind函数。这可以用来将父作用域的this指定给子作用域。
function bound () {
return function () {
console.log(this);
}.bind(this);
}
bound()();
// <- Window

写到这里,都看不下去,逻辑有点混乱,有的是从前辈哪里引用的。

改天有时间整理下,然后,在去讲下闭包(……closer





Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn