1.全局上下文中 thisnode
/* 1.全局上下文中的 this node环境下: 严格模式下: {} {} 报错 非严格模式下:{} {} {} */ 'use strict'; // 严格模式 // demo 1: console.log(this); // {} // demo 2: var a = this; console.log(a); // {} var b = 1; console.log(global.b); // undefined // demo 3: b = this; // 注意:严格模式下,变量必须得声明;非严格模式,能够省略声明符 console.log(b); // {} c = 1; console.log(global.c); // 1 /* 分析: node环境下: node环境下 的上下文组成 与 浏览器环境下 有些不一样; 扩展了解一下,Node.js的全局对象 global: 定义:Node.js中的全局对象是 global, 全部全局变量(除了 global 自己之外)都是global对象的属性; 在 Node.js 中,咱们能够直接访问到 global属性,而不须要在应用中包含它; 也就是说,global 是全局对象,可是它仍是 global.global的属性值,这是递归的过程; 这跟浏览器下的 window对象 是一个逻辑,window对象仍是 window.window 的属性值; 全局对象 与 全局变量的关系: global的根本做用是做为全局变量的宿主,按照 ECMAScript的定义,知足如下条件的变量为全局变量: 1.在最外层定义的变量 2.全局对象的属性 3.隐式定义的变量(未定义直接赋值的变量) 当你定义一个全局变量时,这个变量同时也会成为全局对象的属性,反之亦然。须要注意的是,在 Node.js中你不可能在最外层定义变量, 由于全部用户代码都是属于当前模块的,而模块自己不是最外层上下文。 注意:永远使用 var 定义变量以免引入全局变量,由于全局变量会污染命名空间,提升代码的耦合风险。 因此,以上三个demo 获取 this 的方式: demo 1: 直接获取 this, 实际上 demo 1 建立执行上下文的过程是在 当前模块中进行的,因此说这个模块的上下文环境才是,demo 1 代码执行时的执行上下文, 也就是说 环境对象是当前模块对象,而这个模块对象是个 新对象{},而结果输出 {}, 也就符合“this 指向其执行上下文的环境对象”这一结论了; demo 2: 根据定义,因为用var 声明的变量,实际上并非在最外层上下文中声明的变量,是在当前模块声明的变量(global.b 值为 undefined,已经证实这点了), 可是,整个代码的执行过程仍是在 当前模块的上下文中进行的,同上 输出 {},也就符合“this 指向其执行上下文的环境对象”这一结论; demo 3: 能够看出 demo 3 在非严格模式下隐式定义了一个变量,而且给它赋了值,根据全局变量的定义,这样隐式定义变量的方式, 其实是在全局对象上定义一个属性,也称为全局变量,因此 经过 global对象能够获取到(global.c 的值为 1,已证实这点); 可是要弄清楚,在这个全局变量的 定义过程,仍是在 当前模块进行的,因此 此时 this指向依然是 当前模块的执行上下文对象 {}; 因此,“this 指向其执行上下文的环境对象” 这一结论依然成立; 总结: Node环境下: 全局的执行上下文 进行的过程是在 当前模块下进行的,因此全局执行上下文的环境对象是当前模块{},因此全局中 this 指向当前模块对象{}; */
2.函数上下文的 this浏览器
/* 2.函数上下文中的 this Node环境下: 严格模式下: this 指向被指定的环境对象,即便指定的是 null 或者 undefined; 非严格模式下:this 指向被指定的环境对象,若是指定的是 null 或者 undefined,会转为全局对象 global对象; */ "use strict" // demo 1: function aa(){ console.log(this); } aa(); // 做为单独函数执行(没有指定 环境对象):strict-->"undefined" nostrict-->"global" // demo 2: var obj = { a: 1, b: function(){ console.log(this); } } obj.b(); // 做为对象方法执行: strict-->obj nostrict-->obj // demo 3: aa.call(obj); // 做为单独函数执行(指定 环境对象为 obj): strict-->obj nostrict-->obj // demo 4: aa.call(null); // 做为单独函数执行(指定 环境对象为 null):strict-->null nostrict-->global // demo 5: aa.call(undefined); //做为单独函数执行(指定 环境对象为 undefined):strict-->undefined nostrict-->global /* 总结:函数上下文中的 this Node环境 严格模式下: 函数做为单独函数 执行: 1.函数执行上下文的环境对象 是指定的,指定什么就是什么;this指向这个指定的环境对象;即便指定的是 null 或者 undefined; 函数做为对象方法 执行: 2.这个函数执行上下文的环境对象就是这个拥有它的对象;this指向这个拥有它的对象; Node环境 非严格模式下: 函数做为单独函数 执行: 1.函数执行上下文的环境对象 是指定的,指定什么就是什么;this指向这个指定的环境对象,若是指定的是 null 或者 undefined,会转为全局对象 global对象; 函数做为对象方法 执行: 2.这个函数执行上下文的环境对象就是这个拥有它的对象;this指向这个拥有它的对象; */
3.对象属性中的 thisapp
/* 3.对象属性中的 this 注意:这里指的是以下的形式,不要把它和 对象方法中的 this搞混;对象方法中的 this,要规划到 函数上下文的 this中; Node环境下: 严格模式下:{} 非严格模式下: {} */ 'use strict' var obj = { a: 1, b: 2, c: this, sayHi: function(){ console.log('Hi'); } } console.log(obj.c); // {} /* 分析: 其实,这样的对象字面量的形式,可能看起来会有些困惑,咱们能够变形来分析;由于对象字面量的形式,其实是由以下的形式简化而来的写法; var obj = new Object(); obj.a =1; obj.b = 2; obj.c = this; obj.sayHi = function(){ console.log('Hi'); } 这样看来就清晰不少了,上边这段代码执行的时候,不就是把全局执行上下文的环境对象赋给 obj.c 属性吗,关于 Node中全局上下文的环境对象 为 一个新对象{},咱们已经介绍过了; 并且结果,也正符合咱们此时所得出的结果; 因此,这样做为对象中的 this,能够规到全局执行上下文中的 this 一类中,this 指向 全局执行上下文的环境对象{}; */ /* 一个例子,可能没有什么说服力,咱们再来个嵌套形式的 来证明咱们的结论, 以下: */ var o1 = { a: 1, b: this, o2: { a: 1, b: this } } console.log(o1.o2.b); // {} /* 结果依然是 {}, 其实 如上的形式,能够变形为: var o1 = new Object(); o1.a = 1, o1.b = this; o1.o2 = new Object(); o1.o2.a = 1; o1.o2.b = this; 上面这段代码 在执行时,它的执行上下文的环境对象依然是 全局上下文的环境对象;因此说 this依然指向 {}; */ /* 归纳:对象属性中的 this指向为 全局执行上下文的环境对象{}; */
4.构造函数 和 原型方法中的 this函数
/* 4.构造函数 和 原型方法中的 this 浏览器环境下: 严格模式下:以构造函数名命名的新对象 非严格模式下: 以构造函数名命名的新对象 */ "use strict" function Person(){ console.log(this); // Person {} this.name = 'jack'; console.log(this); // Person {name: "jack"} } Person.prototype.sayThis = function(){ console.log(this); } Person.prototype.sayThis(); // {sayThis: ƒ} new Person(); // Person {} --> // Person {name: "jack"} /* 分析 1: 构造函数与普通函数的最重要的不一样之处,就是构造函数可经过 new操做符,创造实例; 那么在利用构造函数创造实例的过程到底发生了什么呢? 其实呢,是要经历如下几个过程的: 1.创造一个 新对象,做为执行上下文的环境对象;(注意:这里为何说成是新对象,而不说成是空对象呢,由于 function默认是有 prototype属性存在的,它指向原型对象) 2.构造函数开始执行,它的执行上下文环境对象就为这个新对象,也就是说 this指向这个新对象; 3.利用 this来给这个新对象赋值; 4.返回这个被赋值以后的 新对象; 经过上面 new Person() 执行后输出的结果来看,确实是这样的一个过程;没有没给 this赋值前输出的是 Person{}, 赋值后,输出的 Person{name:'jack'}; 因此 归纳: 构造函数中的执行上下文的环境对象为,以构造函数名命名的新对象; 分析 2: 至于原型方法中 this, 其实,在咱们了解了 “函数上下文的 this” 以后,应该很清楚了,它指向给它指定的环境对象,也就是肯定了的 构造函数的原型对象; 因此,Person.prototype.sayThis() 执行后,输出的结果是 Person构造函数的原型对象 --> Person.prototype 对象; */
5.应用 call、apply、bind 方法后的 thisthis
/* 5.应用 call、apply、bind 方法后的 this 了解:call、apply、bind 这三个方法是 Function对象才有的方法;它们的做用,主要是指定函数中 this中的指向,只是用法稍有不一样; 浏览器环境下: 严格模式下:this指向 这三个方法所指定的这个值,不管是什么,即便是 null、undefined, this 也指向它们; 非严格模式下:this指向 这三个方法所指定的这个值,null 和 undefined 值会被转换为全局对象 window; */ "use strict" // demo 1: var o1 = { a: 11, b: 12, sayA: function(){ console.log(this.a); } } var o2 = { a: 21, b: 22 } o1.sayA.call(o2); // 21 // demo 2: function sayB(){ console.log(this.b); } sayB.call(o2); // 22 sayB.apply(o2); // 22 var bSayB = sayB.bind(o2); bSayB(); // 22 /* 其实这块不该该单提出来一个做总结分析的,彻底能够规划到“函数上下文的 this”中去,只是在咱们平时 coding的时候, 这三个方法是常常要用到的 因此单拿出来,以做记忆吧; */
原创:转载注明出处,谢谢 :)spa