JavaScript这门语言中,最令人迷惑的地方有三个,闭包、this、原型。针对大多数人,可以利用词法作用域等避开this的坑,但是我们不能一直生活在舒适区,要敢于打破砂锅问到底,对我们来说也是一种提升。

  一、一般对this关键字的误解:

    1、this指向函数自身

    2、this指向函数声明的词法作用域

  我们可以看以下一段代码:

 function test() {
test.a = 1;
this.a = 2;
console.log(test.a);
console.log(this.a);
console.log(test.a === this.a);
} test();
console.dir(test);

  在上面这段代码中,我们在全局声明一个方法test,给test中的a属性赋值1,当前方法中的this中的a属性赋值2,加入this指向函数自身,那么test.a === this,a并且都等于2.

下面我们来看下这段代码的运行结果:

  

  从上可以看出,scopes为全局作用域window,this也指向这里,虽然函数本身也是一个对象,但是this并不指向这里。

  有一点我们一定要记住,this是在运行时进行绑定的,并不是在编写时绑定的,它的上下文取决于函数调用时的各种条件。this的绑定和函数声明的位置没有任何关系,只取决于函数的调用方式。

  既然this是在运行时绑定的,那我们有没有办法改变当前this的绑定,使其不指向window,而指向方法test呢?答案是肯定的,我们可以借助一些强制绑定方法,如call、apply、bind来改变this的指向,我们可以将代码改成下面这种方式:

 function test() {
test.a = 1;
this.a = 2;
console.log(test.a);
console.log(this.a);
console.log(test.a === this.a);
} test.call(test);
console.dir(test);

  运行结果如下:

  接下来我们看下this是否指向函数声明的词法作用域,以下有段比较有意思的代码:

 function parent() {
var a = 2; function child() {
console.log(this.a)
}
child(); }
parent();

  假如this指向函数的词法作用域,那么child方法中的this.a应该是存在,实际上的执行结果如下,child中的this指向仍为window:

  实际上,在JavaScript内部,作用域确实和对象类似,可见的标识符都是它的属性。但是作用域“对象”无法通过JavaScript代码访问,它存在JavaScript引擎内部。所以每当你想要把this和词法作用域的查找混合使用时,一定要提醒自己,这是无法实现的。

  二、this的绑定规则

    this的绑定规则大致分为以下几类:

      2.1 默认绑定

      2.2 隐式绑定

      2.3 显式绑定

      2.4 new绑定

    2.1 默认绑定

      上述示例中this的指向是指向window的,他们都有一个共同的特征,不带任何修饰的函数引用进行调用的,因此只能使用默认绑定,无法应用其他规则

    2.2 隐式绑定

      隐式绑定首先需要考虑的规则就是调用位置是否有上下文对象,或者说是否被某个对象拥有或包含,例如:

  这里的this就是指向对象obj。还有类似一些DOM事件的绑定,document.getElementById('xxx').addEventListener('click', function(){xxx});回调方法中的this是指向选择器选中的元素的。这种情况下可以简单的理解为this指向调用方法.前面的那个对象。

  2.3 显式绑定

   显示绑定在开发过程中运用的比较多,借助于这些显式绑定方法,可以直接改变当前方法的this指向,使得js语言非常的灵活。主要有call、apply和bind三种,基本使用如下:

  function sum() {
console.log(this.a + this.b);
}
var obj1 = {
a: 1,
b: 2
};
var test = sum.bind(obj1);
sum.call(obj1); //
sum.apply(obj1); //
test(); //

  注意事项:

    call && apply第一个参数接受的是this对象,call第二个参数以后可以接受字符串形式的参数,apply接受的是一个类数组/数组参数

    将null || undefined作为this的绑定对象传入call/apply/bind时,这些值在调用时会被忽略,实际应用的是默认绑定规则

  2.4 new绑定

    JavaScript语言中的new操作符和其他面向对象语言中的new操作符不大一样,因为在JavaScript中没有对象的概念。所有的函数都可以使用new来调用,new的调用又称为构造函数调用。在构造函数调用过程中,会自动执行下面的操作。

  1、创建(或者说构造)一个全新的对象

  2、这个对象会被执行[[Prototype]]连接

  3、这个新对象会绑定到函数调用的this

  4、如果函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个新对象

  构造函数也是js中常用的一种设计模式,如以下代码:

 function Test(a, b) {
this.a = a;
this.b = b;
this.add = function() {
debugger;
console.log(this.a + this.b);
}
}
var cc = new Test(1, 2);
cc.add();
console.log(cc);

  在new调用过程中,返回了一个新对象,并且该对象的this指向Test;

  如有问题,烦请及时指出,谢谢!

JavaScript之扑朔迷离的this的更多相关文章

  1. 【转】javascript运行机制之this详解

    this是面向对象语言中一个重要的关键字,理解并掌握该关键字的使用对于我们代码的健壮性及优美性至关重要.而javascript的this又有区别于Java.C#等纯面向对象的语言,这使得this更加扑 ...

  2. 正确理解javascript的this关键字

    javascript有this关键字,它和javascript的执行上下文有着密切的关系,就是说this具体指代什么要根据它的上下文来判断. 一.this和对象的关系    var Person={ ...

  3. JavaScript中this的指向问题

    this是面向对象语言中一个重要的关键字,理解并掌握该关键字的使用对于我们代码的健壮性及优美性至关重要.而javascript的this又有区别于Java.C#等纯面向对象的语言,这使得this更加扑 ...

  4. JavaScript之父Brendan Eich,Clojure 创建者Rich Hickey,Python创建者Van Rossum等编程大牛对程序员的职业建议

    软件开发是现时很火的职业.据美国劳动局发布的一项统计数据显示,从2014年至2024年,美国就业市场对开发人员的需求量将增长17%,而这个增长率比起所有职业的平均需求量高出了7%.很多人年轻人会选择编 ...

  5. javascript中的Array对象 —— 数组的合并、转换、迭代、排序、堆栈

    Array 是javascript中经常用到的数据类型.javascript 的数组其他语言中数组的最大的区别是其每个数组项都可以保存任何类型的数据.本文主要讨论javascript中数组的声明.转换 ...

  6. Javascript 的执行环境(execution context)和作用域(scope)及垃圾回收

    执行环境有全局执行环境和函数执行环境之分,每次进入一个新执行环境,都会创建一个搜索变量和函数的作用域链.函数的局部环境不仅有权访问函数作用于中的变量,而且可以访问其外部环境,直到全局环境.全局执行环境 ...

  7. 探究javascript对象和数组的异同,及函数变量缓存技巧

    javascript中最经典也最受非议的一句话就是:javascript中一切皆是对象.这篇重点要提到的,就是任何jser都不陌生的Object和Array. 有段时间曾经很诧异,到底两种数据类型用来 ...

  8. 读书笔记:JavaScript DOM 编程艺术(第二版)

    读完还是能学到很多的基础知识,这里记录下,方便回顾与及时查阅. 内容也有自己的一些补充. JavaScript DOM 编程艺术(第二版) 1.JavaScript简史 JavaScript由Nets ...

  9. 《Web 前端面试指南》1、JavaScript 闭包深入浅出

    闭包是什么? 闭包是内部函数可以访问外部函数的变量.它可以访问三个作用域:首先可以访问自己的作用域(也就是定义在大括号内的变量),它也能访问外部函数的变量,和它能访问全局变量. 内部函数不仅可以访问外 ...

随机推荐

  1. Codeforces 1037E Trips

    原题 题目大意: 有\(n\)个人,起初他们都不是朋友.总共有\(m\)天,每天会有两个人成为朋友.他们计划在晚上出去旅游,对于一个人,有如下两种情况: 1.要么他不出去旅游 2.要么有至少\(k\) ...

  2. django系列8:优化vote页面,使用通用视图降低代码冗余

    修改detail.html,将它变为一个可用的投票页面 <h1>{{ question.question_text }}</h1> {% if error_message %} ...

  3. FreeNAS系统总结

    FreeNAS简介 FreeNAS是一套免费的NAS服务器,它能将一部普通PC变成网络存储服务器.该软件基于FreeBSD,Samba 及PHP,支持CIFS (samba), FTP, NFS pr ...

  4. linux系统无法启动或无法登入

    修改root权限: https://blog.csdn.net/houjue2298/article/details/78539827 修改密码: https://www.cnblogs.com/we ...

  5. 剑指Offer_编程题_23

    题目描述 输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果.如果是则输出Yes,否则输出No.假设输入的数组的任意两个数字都互不相同. class Solution { public: ...

  6. busybox(三)最小根文件系统

    目录 busybox(三)最小根文件系统 引入 构建终端 构造inittab 配置应用程序 构建C库 制作映像文件yaffs title: busybox(三)最小根文件系统 tag: arm dat ...

  7. sublime中编译的sass如何改变css输出风格?【这里有答案】

    由于在网上找了一遍没找到如果在sublime中将sass编译的css转换成为自己喜欢的风格,所以换了一种思路搜索到了答案,这里我将讲述如果更改. 首先sass总共有四种编译风格 (1) nested( ...

  8. RubyMine 2017.3.2破解教程

    下载地址:http://www.3322.cc/soft/35519.html RubyMine 2017.3.2破解版是一款专为Ruby和Rails开发者准备的IDE(被誉为最智能的Ruby和Rai ...

  9. scala使用slick查询的全过程(使用cass class)

    1. 首先导包 <dependency> <groupId>com.typesafe.slick</groupId> <artifactId>slick ...

  10. 四十四、Linux 线程——线程同步之死锁以及线程和信号

    44.1 死锁 死锁: 两个线程试图同时占有两个资源,并按不同的次序锁定相应的共享资源 解决方式: 按相同的次序锁定相应的共享资源 使用函数 pthread_mutex_trylock(),它是函数 ...