首先看一下这几个定义

  • this对象是在运行时基于函数的执行环境绑定的:在全局函数中,this等于window,而当函数被视为某个对象的方法调用时,this等于那个对象。
    不过,匿名函数的执行环境具有全局性,因此其this对象通常指向window.

  • 每个函数在被调用的过程中都会自动取得两个特殊变量:this和arguemtns。内部函数在搜索这两个变量的时候,只会搜索到其活动对象为止,因此永远不可能访问外部函数中的这两个变量。

  • this实际上是在函数被调用时发生的绑定,它指向什么完全取决于函数在哪里被调用。

首先,先排除几个错误的认知:
1、this对象是指向自身的。
function foo(num){
console.log(num);
this.count++;
}
foo.count=0;
for(var i=0;i<5;i++){
foo(i)
};
console.log(foo.count); //0
通过这个实例可以看出,count虽然被设置为了foo的属性。但是这里的this并不是指向foo自身的,因此当输出foo.count值的时候,其依然是0.

2、this是指向自身的词法作用域的,也可以简单理解成对于变量对象的引用吧。
function foo(){
var a=2;
console.log(this.a);
}
foo(); //undefined;
我们在foo函数的作用域内定义了a的值为2,然而当我们输出a的值的时候却可以的到undefined,因此这样的理解也是不对的。

实际上,this是在函数被调用时发生的绑定,它指向什么完全取决于在哪里调用。
所以说,我们的第一步就是判断函数的调用位置。

 function baz(){
//当前调用栈是:baz
//因此,当前的调用位置是全局作用域
console.log('baz');
bar();//bar的调用位置
}
function bar(){
//当前调用栈是baz->bar
//因此调用位置是在baz中
console.log('bar');
foo();//<-foo的调用位置 }
function foo(){
//目前调用栈是baz->bar->foo
//因此,当前调用位置是在bar中
console.log('foo') }
baz();//<--baz的调用位置

分析出了他们的调用位置之后,接下来就是要判断它是应用于哪种绑定规则的。
1、默认绑定 独立函数调用-指向全局
var a=2;
function foo(){
console.log(this.a);
}
foo(); //2
这个例子中,函数的调用位置是全局环境,所以其指向全局即等于window(注意这是在非严格模式下)
var a=2;
function foo(){
'use strict';
console.log(this.a);
}
foo(); //undefined
这时,由于严格模式的原因将会输出undefined;
var a=100;
function foo(){
var a='foo中的a';
bar();
}
function bar(){
console.log(this.a);
}
foo();//100
由调用位置决定的另外一个示例。

2、隐式绑定 调用位置是否有上下文对象,或者说是否被某个对象拥有或者包含。
function foo(){
console.log(this.a);
}
var obj={
a:2,
foo:foo
}
obj.foo(); //2
当函数引用有上下文对象时,隐式绑定规则会把函数调用中的this绑定到这个上下文对象中。当然,也有一些隐式绑定的函数丢失绑定对象的问题,例如:
var a='全局中的a';
function foo(){
console.log(this.a);
}
var obj={
a:2,
foo:foo
}
var s=obj.foo;
s(); //全局中的a;
s只是obj.foo的一个引用,而在当s调用的时候已经没有了上下文对象,因此将会默认绑定,从而输出‘全局中的a’
还有一种情况:
var a='全局中的a';
function s(fn){
fn();<--调用位置
}
function foo(){
console.log(this.a);
}
var obj={
a:2,
foo:foo
}
s(obj.foo);
fn只是引用了obj.foo,而在obj.foo的调用位置没有任何特殊绑定,所以是默认绑定指向全局。

3、显式绑定 用call/apply方法。
function foo(){
console.log(this.a);
}
var obj={
a:'董志强',
foo:foo
}
foo.call(obj);
//通过foo.call(..),我们可以在调用foo时强制把他的this绑定到obj上。

4、new绑定
1创建一个新对象
2这个对象会被执行[proto]连接
3这个新对象会绑定到函数调用的this.
4如果函数没有返回其他对象,那么new表达式中的函数会自动返回这个新对象。
function foo(a){
this.a=a;
}
var b=new foo(2);
console.log(bar.a);//2

大概就是这样子的吧,判断出具体的位置之后,再判断绑定方式,这样就可以判断出this的指向了。也有一些例外情况,例如foo.call(null)或者foo.apply(undefined)的情况,在没有其他绑定的情况下,这时foo函数里面的this是指向全局的。

这时你会发现是不是好多问题都理解更深刻了,像下面,.
function Person(name,age){
this.name='dong';
this.age=29
}
Person.prototype.z=2;

var person=new Person();
alert(person.z);//2
alert(person.name);//'dong'
都知道,person.z是person对象沿着原型链向上查找得到的,因为Person.prototype属性里面有z这个属性。
而对于name和age来说他们,则是new绑定,this会指向当前new的对象,所以相当于自身创建了name和age这两个属性,而不是向上查找得到的。

javascript中关于this的理解的更多相关文章

  1. javascript中concat方法深入理解

    最近在恶补js知识的时候,总是会因为js强大的语法而感到震撼.因为以前对前端方面的疏忽,导致了一些理解的错误.因此痛改前非,下定决心,不管做什么事情,都要有专研的精神. 在介绍前,抛出一个问题:如何将 ...

  2. JavaScript - javascript 中的 "||" 与 "&&" 的理解与灵活运

    你肯定见到过这样的代码:a = a||"xxx". 它其实就等价于下面三种形式的代码: a = a || "xxx"; 与: if (!a) { a = &qu ...

  3. javascript中关于继承的理解

    首先,你要理解在javascript中,每当一个新函数创建时,都会生成一个prototype属性,我们管它叫做原型对象.看一个例子: function foo(){ this.name='qiangq ...

  4. 第一篇 对Javascript中原型的深入理解

      理解原型对象 在Javascript中不管什么时候,仅仅要创建一个新的函数,就会依据一组特定的规则为该函数创建一个prototype属性,这个属性指向函数的原型对象(这个对象的用途是包括能够有特定 ...

  5. Javascript中闭包的个人理解

       Javascript的一个特殊点就在于它的闭包和回调特性,这两个特性让初学Javascript的我是云里雾里,至今仍在苦苦摸索与理解.在一番苦思之后,整理了一下资料,将自己的理解思路记录下来,以 ...

  6. 关于JavaScript中prototype机制的理解

    最近几天一直在研究JavaScript中原型的机制,从开始的似懂非懂,到今天终于有所领悟.不敢说彻底理解,但是起码算知道怎么回事了. 为什么一开始似懂非懂 开始了解一遍原型机制后,感觉知其然但不知其所 ...

  7. javascript中变量提升的理解

    网上找了两个经典的例子 var foo = 1; function bar() { if (!foo) { var foo = 10; } alert(foo); } bar(); // 10 var ...

  8. JavaScript中with语句的理解

    with语句的作用是暂时改变作用域链.减少的重复输入. 其语法结构为: with(object){ //statements } 举一个实际例子吧: with(document.forms[0]){ ...

  9. 深入浅析JavaScript中with语句的理解

    JavaScript 有个 with 关键字, with 语句的原本用意是为逐级的对象访问提供命名空间式的速写方式. 也就是在指定的代码区域, 直接通过节点名称调用对象. with语句的作用是暂时改变 ...

  10. 对于JavaScript中this关键字的理解

    这是我第二遍学this了,第一遍学的懵懵的.this指哪里都是凭我一个男人的直觉然后控制台输出看看对不对. 刚查了书.博客.视频.理解差不多了.毕竟菜鸡me: 一.首先介绍下什么是this this是 ...

随机推荐

  1. 学习AngularJs:Directive指令用法(完整版)

    这篇文章主要学习AngularJs:Directive指令用法,内容很全面,感兴趣的小伙伴们可以参考一下   本教程使用AngularJs版本:1.5.3 AngularJs GitHub: http ...

  2. codevs1993草地排水(最大流)

    最近学了最大流,于是去codevs找了几道最大流裸题(这是我第一次写网络流). 题目大意:求一个图的最大流(就是这样的裸题) 第一次A网络流的题,发个博客纪念一下. var n,m,i,j,k,h,t ...

  3. JavaScript字符和数组一些基本算法题

    1.翻转字符串 例子(要求:先把字符串转化成数组,再借助数组的reverse方法翻转数组顺序,最后把数组转化成字符串) function reverseString(str) { str=str.sp ...

  4. 希腊字母、拉丁字母、Markdown、拼写与读音中英对照表

    大写 小写 中文名 英文 大写Markdown 小写Markdown 意义 阿尔法 Alpha A \alpha 角度.系数.角加速度.第一个.电离度.转化率 贝塔/毕塔 Beta B \beta 磁 ...

  5. ManualResetEvent和AutoResetEvent的区别

    在讨论这个问题之前,我们先了解这样一种观点,线程之间的通信是通过发信号来进行沟通的.(这不是废话) 先来讨论ManualResetEvent,讨论过程中我会穿插一些AutoResetEvent的内容, ...

  6. vue+vuex初入门

    Vuex Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式.它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化. 解决问题: 传参的方法对于多层嵌 ...

  7. 使用Jax-rs 开发RESTfull API 入门

    使用Jax-rs 开发RESTfull API 入门 本文使用 Jersey 2开发RESTfull API.Jersey 2 是 JAX-RS 接口的参考实现 使用到的工具 Eclipse Neon ...

  8. linux入侵控制与痕迹清理

    后门 (1)开机自动反弹shell (2)linux后门 Rookit 目前常用的有:t0rn /mafix/enyelkm 等 mafix rootkit Mafix是一款常用的轻量应用级别Root ...

  9. css2和CSS3的background属性简写

    1.css2:background:background-color || url("") || no-repeat || scroll || 0 0;  css3:  backg ...

  10. Spring Security(15)——权限鉴定结构

    目录 1.1      权限 1.2      调用前的处理 1.2.1     AccessDecisionManager 1.2.2     基于投票的AccessDecisionManager实 ...