前言

在《javascript 之执行环境-08》文中说到,当JavaScript代码执行一段可执行代码时,会创建对应的执行上下文(execution context)。对于每个执行上下文,都有三个重要属性:

  • 变量对象(Variable object,VO)
  • 作用域链(Scope chain)
  • this

  JavaScript中的this跟其他语言有些不一样,比如Java .net语言中的this是在代码的执行阶段是不可变的,而JavaScript的this是在调用阶段进行绑定。也因为这一性质给了this很大的灵活性,即当函数在不同的调用方式下都可能会导致this的值不同;

定义

  this 对象是在运行时基于函数的执行环境绑定的,跟函数的调用位置有关而不是声明的位置;可以理解为this是在函数调用阶段绑定,也就是执行上下文创建的阶段进行赋值,保存在变量对象中;

四种绑定规则

new 构造函数绑定,this指向新创建的对象

 function createPerson(){
return new person();
}
function person() {
this.name = "Joel";
this.say=function(){
console.log(p)
console.log('hello' + this.name)
}
}
var p = new person();
p.say();
console.log(p.name);//Joel
console.log('开始')
var t=createPerson();
t.say();

不管是直接new 还是通过function createPerson 函数返回的对象,this 都是指向了新创建出来的对象;

显示绑定,this指向传进去的对象

     //call() apply() bind() 显示绑定
window.color = "red";
var Obj = { color: "blue" };
function sayColor() {
console.log(this.color);
}
sayColor();// red this window
sayColor.call(this);//red
sayColor.call(window);//red
sayColor.call(Obj);// blue 把this指针改为对象Obj
sayColor.apply(Obj);//blue 把this指针改为对象Obj
sayColor.bind(Obj)();//blue 把this指针改为对象Obj

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

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

隐士绑定

以对象的方法形式调用,this指向当前这个对象

    function foo(){
console.log(this)//{a: 2, name: "Joel", foo: ƒ}
console.log(this.a)//
}
var obj={
a:2,
name:'Joel',
foo:foo
};
obj.foo();

这时this指向当前obj对象,但是如果换种写法会造成this 丢失问题。

     function foo(){
console.log(this)//{a: 2, name: "Joel", foo: ƒ}
console.log(this.a)//
}
var obj={
a:2,
name:'Joel',
foo:foo
};
obj.foo();
//this 丢失的问题
var t= obj.foo;
t(); //window undefined

变量t此时保存的是函数的引用跟obj已经没有关系,所以此时this指向window。

默认绑定 严格模式下this 绑定到undefined,否则绑定到全局对象 window

   function foo(){
console.log(this)//window
console.log(this.a)//Joel
}
var a='Joel';
foo(); //严格模式
function fo(){
'use strict' //严格模式
console.log(this)//undefined
console.log(this.b)//报错 Cannot read property 'b' of undefined
}
var b='Joel';
fo();

以上是基本的this绑定规则,其中new、显示绑定很容易判断,其中比较容易错的是容易把默认绑定误认为是隐士绑定 如匿名函数、闭包、函数当做参数等;

独立调用:this 指向window

   var name='Joel',age=12;
function say(){
function say1(){
console.log(this.name);//window
function say2(){
name+='-l'
console.log(this.name);//window
}
say2()
}
say1();
}
say(); //匿名函数
(function(){
console.log(this.name)
})()

function 当做参数传递其实跟独立调用一样的原理

 function foo() {
console.log(this)//window
console.log(this.a)//oops global
}
function doFoo(fn) {
console.log(this);//window
fn();//类似与 foo()
}
var obj = {
a: 2,
foo: foo
}
var a = 'oops global';
doFoo(obj.foo);

同理setTimeout 也是一样

  var obj = {
a: 2,
foo: function() {
console.log(this);
},
foo2: function() {
console.log(this); //this 指向 obj
setTimeout(this.foo, 1000); // this 指向 window
}
}
var a = 'oops global';
obj.foo2();

闭包中的this

     var name = "Joel";
var obj = {
name: "My object",
getName: function() {
// var that = this; // 将getNameFunc()的this保存在that变量中
return function() {
return this.name;
};
}
}
console.log(obj.getName()()); // "Joel"

这里的虽然是对象的方法形式调用obj.getName(),在getName中的this是指向obj,但是返回的匿名函数中的this 为什么是window呢?

把最后的一句拆成两个步骤执行:

 var t=obj.getName();
t();

是不是有点像在独立调用呢?如果需要访问obj中的name,只需要把this对象缓存起来,在匿名函数中访问即可,把var that=this;去掉注释即可;

总结

  • this 是变量对象的一个属性,是在调用时被绑定的,跟函数的调用位置有关而不是声明的位置;
  • 找到调用位置,根据绑定规则来分析this 绑定;
  • 默认绑定严格模式下this 绑定到undefined,否则绑定到全局对象 window;

思考题

     var length = 5;
var obj = {
foo: function (fn) {
console.log(this.length); // this => obj
fn(); // this => window
arguments[0](); // this => arguments
var bar = arguments[0];
bar(); // this => window
},
length: 10
}
var fn = function () {
console.log(this.length);
}
obj.foo(fn);
//10, 5, 1, 5

javascript 之this指针-11的更多相关文章

  1. 图说js中的this——深入理解javascript中this指针

    没搞错吧!js写了那么多年,this还是会搞错!没搞错,javascript就是回搞错! ………… 文章来源自——周陆军的个人网站:http://zhoulujun.cn/zhoulujun/html ...

  2. javascript中this指针

    看完此片文章豁然开朗,非常感谢.javascript技术难点(三)之this.new.apply和call详解 下面说一说自己的理解: this指针总是指向调用他的对象,其实我更愿意理解为:this指 ...

  3. javascript中this指针探讨

    javascript是一门类java语言有很多跟java相类似的特点,但也仅是类似而已,真正使用中还是有很大的差别.this指针常常让很多初学者抓狂,本人也曾为此困惑不解,查找过很多资料,今天在这里总 ...

  4. 原生JavaScript技巧大收集(11~20)-(终于又被我找到这篇文章了)

    11.原生JavaScript加入收藏夹 function AddFavorite(sURL, sTitle) { try { window.external.addFavorite(sURL, sT ...

  5. JavaScript——对this指针的新理解

    一直以来对this的理解只在可以用,会用,却没有去深究其本质.这次,借着<JavaScript The Good Parts>,作了一次深刻的理解.(所有调试都可以在控制台中看到,浏览器F ...

  6. javascript 误用this指针 的情况

    理解了this指针后,我们再来看看一些很容易误用this指针的情况. 示例1——内联式绑定Dom元素的事件处理函数 <script type="text/javascript" ...

  7. javascript中this指针的认识

    javascript中上下文环境就是this指针,即被调用函数所处的环境.这个上下文环境在大多数情况下指的是函数运行时封装这个函数的那个对象:当不通过任何对象单独调用一个函数时,上下文环境指的就是全局 ...

  8. Javascript图片预加载详解 分类: JavaScript HTML+CSS 2015-05-29 11:01 768人阅读 评论(0) 收藏

    预加载图片是提高用户体验的一个很好方法.图片预先加载到浏览器中,访问者便可顺利地在你的网站上冲浪,并享受到极快的加载速度.这对图片画廊及图片占据很大比例的网站来说十分有利,它保证了图片快速.无缝地发布 ...

  9. JavaScript的this指针到底指向哪?

    编程过程中,着实十分困扰this的指向性,经过查阅一番资料,终于搞清楚了,在这里总结一下,全文分为以下三个部分: 什么是this指针? this指针指向哪里? 何时使用this? 一 什么是this指 ...

随机推荐

  1. tiny210(s5pv210)移植u-boot(基于 2014.4 版本号)——NAND 8位硬件ECC

    这节我们实现nand的ecc,保存环境变量到nand flash 中.然后把我们之前的led灯烧写到nand flash 中.开机启动.在 tiny210.h 中定义宏 CONFIG_S5PV210_ ...

  2. nginx、fastCGI、php-fpm关系梳理

    前言: Linux下搭建nginx+php+memached(LPMN)的时候,nginx.conf中配需要配置fastCGI,php需要安装php-fpm扩展并启动php-fpm守护进程,nginx ...

  3. MQTT 设计原则

    MQTT 设计原则 简单. 没有杂七杂八的花俏功能,作为一个基础组件构建实用的系统,易于实现. "发布/订阅"消息传递方式. 随时接入随时发布.接收消息,无需太多其他"事 ...

  4. 原生js版分页插件

    之前我在自己的博客里发表了一篇用angularJs自定义指令实现的分页插件,今天简单改造了一下,改成了原生JavaScript版本的分页插件,可以自定义一些简单配置,特此记录下来.如有不足之处,欢迎指 ...

  5. 理解spread运算符与rest参数

    理解spread运算符与rest参数 spread运算符与rest参数 是ES6的新语法.它们的作用是什么?能做什么事情? 1. rest运算符用于获取函数调用时传入的参数. function tes ...

  6. 晒下我在2017年所阅读的JavaScript书单

    前言 学习是一个持续不断的过程,在互联网技术里畅游的程序猿们,对学习的渴望更是难以穷尽.2017即将逝去,2018已经漏出曙光,回顾这一年,在学习的路上收获还是颇丰的,下面就晒一晒2017年我所学习的 ...

  7. Visual Studio 实用技能

    1快捷键使用 1. Ctrl K F 代码对齐

  8. 那些容易遗忘的web前端问题

    背景: 年底将至,本人这只才出门的前端菜鸟,终于有空闲的时间来整理一下最近投简历时出现的问题.有的是经常使用但是没有仔细留意造成的:有的是个人认为根本没人使用而忽略的.为了下次不出现这种错误,进行一下 ...

  9. 二叉树Bynary_Tree(2):二叉树的递归遍历

    7/18/2017 正在码,理解完就写博 7/21/2017 终于码完,借助链表实现的队列撸一个二叉树对于我来说有难度,撸了两天没有成果,我最后选用的是数组实现的循环队列去撸一个二叉树 正文如下: 以 ...

  10. iOS动态性 运行时runtime初探(强制获取并修改私有变量,强制增加及修改私有方法等)

    借助前辈的力量综合一下资料. OC是运行时语言,只有在程序运行时,才会去确定对象的类型,并调用类与对象相应的方法.利用runtime机制让我们可以在程序运行时动态修改类.对象中的所有属性.方法,就算是 ...