this总结,mark一下:

Object中的this:

Object方法中的this,指向的就是该对象,即谁调用this就指向谁,与C#等服务器语言的思想比较一致。

  1. let
  2. demo = {
  3. name: "dqhan",
  4. action: function () {
  5. console.log(this); //{name: "dqhan", action: ƒ}
  6. (function () {
  7. console.log(this);//Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
  8. // "use strict";
  9. // console.log(this);//undefined
  10. })();
  11. }
  12. };
  13. demo.action();

demo对象调用action,action中的this指向的就是demo,action内部的自执行函数this则指向的是window,严格模式下为undefined。可以写个深层次的demo来看下会不会影响this的指向

  1. let
  2. demo = {
  3. name: "dqhan",
  4. action: function () {
  5. console.log(this) //{name: "dqhan", action: ƒ, innerDemo: {…}}
  6. },
  7. innerDemo: {
  8. name: 'innerDqhan',
  9. action: function () {
  10. console.log(this)//{name: "innerDqhan", action: ƒ}
  11. }
  12. }
  13. };
  14. demo.action();
  15. demo.innerDemo.action();

事实证明不会影响this的指向,这种方式的定义以及调用不参与原型链,不涉及this指向改变的问题。

函数中的this:

匿名函数中,函数体内的this指向为window,严格模式下为undefined。

  1. function demo(){
  2. console.log(this);//Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
  3. // "use strict"
  4. // console.log(this);//undefined
  5. }
  6. demo();
  1. foo = 'outer'
  2. function demo() {
  3. this.foo = 'inner';
  4. // "use strict";
  5. // this.foo = 'inner';//error
  6. }
  7. console.log(foo);//outer
  8. demo();
  9. console.log(foo);//inner

foo在不加var,let(ES6)下自动挂载window下,调用demo后在函数内部将foo重新赋值。严格开发下this为undefined报错。

构造函数中的this:

提到this常常想到的是构造函数,写个简单的demo如下

  1. function Demo() {
  2. this.name = "dqhan";
  3. this.action = function () {
  4. console.log(this)//Demo {name: "dqhan", action: ƒ}
  5. };
  6. };
  7.  
  8. let
  9. demo = new Demo();
  10. demo.action();
  11. console.log(demo.name);//dqhan

调用demo内的action,action中的this指向构造函数的实例化对象,原因是什么呢?这里需要了解一下let demo = new demo();到底发生了什么。

  1. //action1
  2. let
  3. demo = new Demo();
  4. //action2
  5. let
  6. demo = {};
  7. demo.__proto__ = Demo.prototype;
  8. Demo.call(demo);

js中new一个实例化对象的过程等价于action2的代码,最后一步通过call方法(apply,bind)将demo对象中的this传递到了Demo构造函数中,从而将构造函数中没有定义在原型中的属性与方法都定义到了demo 对象中,这就是为什么构造函数中的this会是实例化对象的原因。另外我们可以将属性或者方法都定义在原型中

  1. function Demo() {
  2. this.name = "dqhan";
  3. };
  4. Demo.prototype.action = function () {
  5. console.log(this)//Demo {name: "dqhan", action: ƒ}
  6. };
  7.  
  8. let
  9. demo = new Demo();
  10. console.log(demo.name);//dqhan

我们都清楚,构造函数类似于一个简单工厂模式,我们可以通过一个构造函数生成很多其他对象,我们将属性或者方法定义在原型中,这样可以达到原型共享的目的。

  1. function Demo() {
  2. this.name = "dqhan";
  3. };
  4. Demo.prototype.action = function () {
  5. console.log(this)//Demo {name: "dqhan", action: ƒ}
  6. };
  7. let
  8. demo = new Demo(),
  9. demo1 = new Demo(),
  10. demo2 = new Demo();
  11. demo.__proto__ === demo1.__proto__;//true
  12. demo1.__proto__ === demo2.__proto__;//true

当对象非常多的是时候,可以节约内存。

当函数内嵌套匿名函数

  1. function Demo() {
  2. this.name = "dqhan";
  3. };
  4. Demo.prototype.action = function () {
  5. console.log(this);//Demo {name: "dqhan", action: ƒ}
  6. (function () {
  7. console.log(this);//Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
  8. // "use strict";
  9. // console.log(this)//undefined
  10. })();
  11. };
  12. let
  13. demo = new Demo();
  14. demo.action();

定义在构造函数内的方法在传递的时候,实例化对象不会跟着一起传过去

  1. function Demo() {
  2. this.name = "dqhan";
  3. };
  4. Demo.prototype.action = function () {
  5. console.log(this);
  6.  
  7. };
  8. function foo(method){
  9. method();
  10. };
  11. let
  12. demo = new Demo();
  13. foo(demo.action);//Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
  1. function Demo() {
  2. this.name = "dqhan";
  3. };
  4. Demo.prototype.action = function (method) {
  5. console.log(this);
  6. method();
  7. };
  8. Demo.prototype.actionCallBack = function () {
  9. console.log(this);
  10. }
  11. let
  12. demo = new Demo();
  13. demo.action(demo.actionCallBack);
  14. //Demo {name: "dqhan"}
  15. //Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}

这两种情况都是将实例化对象中的方法当成参数进行传递。但是在执行函数中,this的上下文已经发生改变。解决方式可以通过bind,apply,call等改变上下文的方式。

  1. function Demo() {
  2. this.name = "dqhan";
  3. };
  4. Demo.prototype.action = function (method) {
  5. console.log(this);
  6. method()
  7. };
  8. Demo.prototype.actionCallBack = function () {
  9. console.log(this);
  10. }
  11. let
  12. demo = new Demo();
  13. demo.action(demo.actionCallBack.bind(demo));
  14. // Demo {name: "dqhan"}
  15. // Demo {name: "dqhan"}
  1. function Demo() {
  2. this.name = "dqhan";
  3. };
  4. Demo.prototype.action = function () {
  5. console.log(this);
  6. (function () {
  7. console.log(this);
  8. }).apply(this);
  9. };
  10. let
  11. demo = new Demo();
  12. demo.action();
  13. // Demo {name: "dqhan"}
  14. // Demo {name: "dqhan"}

setTimeout中的延迟函数中this

  1. let
  2. obj = {
  3. timerAction: function () {
  4. console.log(this);
  5. }
  6. };
  7. function foo(method) {
  8. method();
  9. };
  10. obj.timerAction();
  11. foo(obj.timerAction);
  12. setTimeout(obj.timerAction, 0);
  13. // {timerAction: ƒ}
  14. // Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
  15. // Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}

之前看过一篇关于setTimeout使用时延迟函数自动挂载window上。今天总结了一下,发现这种方式个人觉得可以理解成,以函数当做参数进行传递this都是传递不过去的。如果简单的写一个函数,那么问题就更不存在了,匿名函数本身就是挂载window下,没有争议了。

随机推荐

  1. 在Unity3D中连接WCF服务端

    服务端不多讲解,有一处需要改的地方.具体服务端请看WCF入门学习2-控制台做为宿主 建议实际项目不要拿去用,毕竟是mono不是原生.net.或许是个坑 由于Unity的mono版本问题不能直接用net ...

  2. [na]数据包由于isp不稳定丢包-seq&ack

    知识参考: http://www.xianren.org/net/wireshark-q.html 背景 总行wac管理分行ap.手机终端打不开portal页面. 2,分别抓包(portal页面从wa ...

  3. cocos2d-x 粒子动作 setTexture

    CCSize s = CCDirector::sharedDirector()->getWinSize(); CCNode* explosion = CCParticleSun::create( ...

  4. 中文转Punycode

    package cn.cnnic.ops.udf; public class GetPunycodeFromChinese { static int TMIN = 1; static int TMAX ...

  5. java 多线程11:volatile关键字

    直接先举一个例子普通的线程实例变量的非可见性: public class MyThread28 extends Thread { private boolean isRunning = true; p ...

  6. mysql 存入乱码问题

    在使用mysql开发是,遇到一问题,java脚本里面的中文很正常,持久化之后数据库里面的数据则变成乱码,解决方式,在spring配置文件连接中加入指定编码格式,有些系统不需要,有些服务器系统需要,统一 ...

  7. HOW TO:使用 Visual C# .NET 打印 RichTextBox 控件的内容

    概要 本分步指南介绍了如何打印 RichTextBox 控件的内容.RichTextBox 控件没有提供任何打印 RichTextBox 内容的方法.您可以扩展 RichTextBox 类以使用 EM ...

  8. C语言 · 前10名

    算法提高 前10名   时间限制:1.0s   内存限制:256.0MB      问题描述 数据很多,但我们经常只取前几名,比如奥运只取前3名.现在我们有n个数据,请按从大到小的顺序,输出前10个名 ...

  9. C中结构体的存储分配

    C中结构体的存储分配 对于C语言中结构体所占的存储空间的大小,也一直是笔试面试的常客,今天好好看了一下这方面,以前一直以为很清楚了,今天通过各种实际测试举例,发现原来还是没有搞透彻,好在现在是彻底懂了 ...

  10. CSS样式表——布局练习(制作360网页)

    以制作360网页为例(只做到了静态网页) 提纲:1.总共分为7部分 悬浮窗: 源代码: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Tra ...