关于js中的this

this是javascript中一个很特别的关键字,也是一种很复杂的机制,学习this的第一步就是要明白this既不指向函数自身也不指向函数的词法作用域,this实际上是函数被调用时发生的绑定,它指向什么完全取决于函数在哪里被调用

1. 调用位置

现在来说一下调用位置:调用位置就是函数在代码中被调用的位置(而不是声明的位置)。
那么怎么找到它的调用位置呢?最重要的是要分析“调用栈”(就是为了到达当前执行位置所调用的所有函数)


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的调用位置`

分析调用栈,可以将调用栈想象成一个函数调用链(比如:foo函数里面注释的这一句‘当前调用栈是:baz->bar->foo’)在这条函数调用链的所在的函数的前一个函数,就是所在函数的调用位置(foo函数中baz->bar->foo)

还有另外一种查看调用栈的方法,就是使用浏览器的调试工具(我所使用的是chrome浏览器)
你可以在工具中给每个函数的里面的第一行(不是注释,其他行也可以)设置一个断点,然后运行(刷新一下)


在工具中展示的调用列表,找到栈中的第二个元素(从栈顶往下第二个),这就是该函数的真正的调用位置。

2. 绑定规则

现在我们已经找到了调用位置,那调用位置如何决定this的绑定对象呢?
this的绑定规则有四条,而且应用多条规则时还要注意它们的优先级(这里没讲)

1. 默认绑定

可以把这条规则看作无法应用其他规则时的默认规则,最常用的函数调用类型:独立函数调用

function foo(){
console.log(this.a);
}
var a=2;
foo();//2

首先要明白,在全局作用域中声明上的变量就是全局对象中一个同名属性
接下来,我们在调用foo()时,this.a被解析成了全局对象a。因为在本例中函数调用的时候应用了this的默认绑定(在代码中,foo()是直接使用不带任何修饰的函数引用进行调用的),因此this指向全局对象。
但是要注意:以上的情况实在非严格模式下,但是在严格模式下,全局对象无法使用默认绑定,因此this会绑定到undefined。

2.隐式绑定

function foo(){
console.log(this.a);
}
var obj={
a:2,
foo:foo};
obj.foo();//2


在这个例子中,函数foo被当作引用属性添加到obj中,但严格的说它并不属于obj对象,然后,调用位置会使用obj上下文来引用函数,可以说
函数被调用时obj对象“包含”它。当函数引用有上下文对象时,隐式绑定规则会把函数调用中的this绑定到这个上下文对象,因为调用foo()时this被绑定到obj,因此this.a和obj.a是一样的。
但是,对象属性引用链中个只有最顶层或者说最后一层会影响调用位置。

function foo(){
console.log(this.a);
}
var obj2={
a:42,
foo:foo
};
var obj1={
a:2,
obj2:obj2
};
obj1.obj2.foo();//42


但是存在一个问题,被隐式绑定的函数有可能会丢失绑定对象,然后应用默认绑定规则,这里就不细讲了(比如在传入回调函数时.......)。

3.显示绑定

隐式绑定时,我们必须在一个对象内部包含一个指向函数的属性,并通过这个属性间接引用函数,从而把this隐式绑定到这个对象上。但是我们想粗暴一点怎么办的?
javascript提供的大多数函数(除了一些非常特殊的函数)都有一些有用的特性,在这里我们可以使用函数的call(...)和apply(...)方法,这两个方法的区别在于参数的传递。
它们的第一个参数是一个对象,它们会把这个对象绑定到this,接着在调用的时候指向这个this,因为你可以直接指定this的绑定对象,因此我们称之为显示绑定。

function foo(){
console.log(this.a);
}
var obj={a:2};
foo.call(obj);//2

通过foo.call(...)我们可以在调用foo时强制把它的this绑定到obj上。但是显示绑定还是无法解决丢失绑定问题,但是显示绑定的一个变种可以解决这个问题,这里不讲了)

4.new绑定

javascript中的new操作符和那些面向类的语言的机制完全不同,在javascript中,那所谓的“构造函数”只不过是使用new操作符时被调用的函数,但它并不属于这个类,也不会实例化一个类,就是被new操作符调用的普通函数而已。
使用new来调用汗书时,会执行下列操作
1.创建一个全新的对象。
2.这个对象会执行[[原型]]连接
3.这个新对象会绑定到函数调用的this
4.如果函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个新对象

function foo(a)
{ this.a=a;}
var bar=new foo(2);
console.log(bar.a);//2

我们会构造一个新的对象并将它绑定到foo(..)调用中的this上。
以上就是this的四种绑定规则。

参考书籍《你不知道的JavaScript(上卷)》

关于js中的this的更多相关文章

  1. 5.0 JS中引用类型介绍

    其实,在前面的"js的六大数据类型"文章中稍微说了一下引用类型.前面我们说到js中有六大数据类型(五种基本数据类型 + 一种引用类型).下面的章节中,我们将详细讲解引用类型. 1. ...

  2. 【repost】JS中的异常处理方法分享

    我们在编写js过程中,难免会遇到一些代码错误问题,需要找出来,有些时候怕因为js问题导致用户体验差,这里给出一些解决方法 js容错语句,就是js出错也不提示错误(防止浏览器右下角有个黄色的三角符号,要 ...

  3. JS中给正则表达式加变量

    前不久同事询问我js里面怎么给正则中添加变量的问题,遂写篇博客记录下.   一.字面量 其实当我们定义一个字符串,一个数组,一个对象等等的时候,我们习惯用字面量来定义,例如: var s = &quo ...

  4. js中几种实用的跨域方法原理详解(转)

    今天研究js跨域问题的时候发现一篇好博,非常详细地讲解了js几种跨域方法的原理,特分享一下. 原博地址:http://www.cnblogs.com/2050/p/3191744.html 下面正文开 ...

  5. 表值函数与JS中split()的联系

    在公司用云平台做开发就是麻烦 ,做了很多功能或者有些收获,都没办法写博客,结果回家了自己要把大脑里面记住的写出来. split()这个函数我们并不陌生,但是当前台有许多字段然后随意勾选后的这些参数传递 ...

  6. JS中 call() 与apply 方法

    1.方法定义 call方法: 语法:call([thisObj[,arg1[, arg2[,   [,.argN]]]]]) 定义:调用一个对象的一个方法,以另一个对象替换当前对象. 说明: call ...

  7. 在node.js中,使用基于ORM架构的Sequelize,操作mysql数据库之增删改查

    Sequelize是一个基于promise的关系型数据库ORM框架,这个库完全采用JavaScript开发并且能够用在Node.JS环境中,易于使用,支持多SQL方言(dialect),.它当前支持M ...

  8. 分析js中的constructor 和prototype

    在javascript的使用过程中,constructor 和prototype这两个概念是相当重要的,深入的理解这两个概念对理解js的一些核心概念非常的重要. 我们在定义函数的时候,函数定义的时候函 ...

  9. 如何在Node.js中合并两个复杂对象

    通常情况下,在Node.js中我们可以通过underscore的extend或者lodash的merge来合并两个对象,但是对于像下面这种复杂的对象,要如何来应对呢? 例如我有以下两个object: ...

随机推荐

  1. 从备考PMP到与项目经理同呼吸

    前言 PMP是什么梗? 项目管理专业人士资格认证.它是由美国项目管理协会(Project Management Institute(PMI)发起的,严格评估项目管理人员知识技能是否具有高品质的资格认证 ...

  2. javascript之Object.defineProperty的奥妙

    直切主题 今天遇到一个这样的功能: 写一个函数,该函数传递两个参数,第一个参数为返回对象的总数据量,第二个参数为初始化对象的数据.如: var o = obj (4, {name: 'xu', age ...

  3. UWP开发之Template10实践二:拍照功能你合理使用了吗?(TempState临时目录问题)

    最近在忙Asp.Net MVC开发一直没空更新UWP这块,不过有时间的话还是需要将自己的经验和大家分享下,以求共同进步. 在上章[UWP开发之Template10实践:本地文件与照相机文件操作的MVV ...

  4. 【Machine Learning】决策树案例:基于python的商品购买能力预测系统

    决策树在商品购买能力预测案例中的算法实现 作者:白宁超 2016年12月24日22:05:42 摘要:随着机器学习和深度学习的热潮,各种图书层出不穷.然而多数是基础理论知识介绍,缺乏实现的深入理解.本 ...

  5. 深入理解javascript的getTime方法

    1.理解getTime getTime() 方法返回一个时间的格林威治时间数值. 可以使用这个方法把一个日期时间赋值给另一个Date 对象. 语法: dateObj.getTime() 参数: 无. ...

  6. Block解析(iOS)

    1. 操作系统中的栈和堆 我们先来看看一个由C/C++/OBJC编译的程序占用内存分布的结构: 栈区(stack):由系统自动分配,一般存放函数参数值.局部变量的值等.由编译器自动创建与释放.其操作方 ...

  7. 如何区别exists与not exists?

    1.exists:sql返回结果集为真:not exists:sql不返回结果集为真.详解过程如图: exists not exists

  8. Python3中的字符串函数学习总结

    这篇文章主要介绍了Python3中的字符串函数学习总结,本文讲解了格式化类方法.查找 & 替换类方法.拆分 & 组合类方法等内容,需要的朋友可以参考下. Sequence Types ...

  9. Storm介绍(二)

    作者:Jack47 转载请保留作者和原文出处 欢迎关注我的微信公众账号程序员杰克,两边的文章会同步,也可以添加我的RSS订阅源. 本文是Storm系列之一,主要介绍Storm的架构设计,推荐读者在阅读 ...

  10. (转)linux下和云端通讯的例程, ubuntu和openwrt实验成功(一)

    一.  HTTP请求的数据流总结#上传数据, yeelink的数据流如下POST /v1.0/device/4420/sensor/9089/datapoints HTTP/1.1Host: api. ...