Q:this是什么?

A:this是Javascript语言的一个关键字,它代表函数运行时,自动生成的一个内部对象,在每个 function 中自动根据作用域(scope) 确定, 指向的是此次调用者。

Q:this的使用场景?

A:  1.普通函数调用。

  2.作为对象的方法来调用。

  3.作为构造函数调用。

  4.函数被call,apply,bind调用的时候。

栗子:

普通函数调用

function test1(){
  console.log(this);
}
test1(); // window

在非严格模式下,由于this必须是一个对象,所以就默认为指向全局对象window。在严格模式下,上面的代码则会出现不同的结果,如下:

function test1(){
  "use strict";
  console.log(this);
}
test1(); // undefined

再看看下面这段代码:

function test2(){
this.x=2;
}
test2();
console.log(window.x); // 2

由于普通函数的调用,this的值指向window。所以执行this.x的时候相当于执行了window.x,故window.x的值为2。

作为对象的方法来调用

var message = {
content: "I'm a message!",
showContent: function() {
console.log(this.content);
}
}; message.showContent(); // I'm a message!

  上面栗子是将函数保存为对象的属性, 这样就转化为一个方法, 可以通过对象调用这个方法。而当函数被当成对象的方法来调用时, 里面的 this 值就被设置为调用方法的对象。其实,不管被调用函数在声明时是属于方法,还是函数,当最终作为对象的方法来调用时,this都是指向方法的调用者,即母体对象。看看下面的栗子你就明白了。

var obj = {
x: 1,
showX: function() {
console.log(this.x)
}
}
obj.showX(); // 1 var obj1={x:11};
obj1.showX=obj.showX;
obj1.showX(); // 11 show=function(){
console.log('show'+this.x);
} obj1.showX=show;
obj1.showX(); // show11

  上面栗子中,在obj对象中,匿名函数在声明时就作为obj对象的一个属性,this直接指向obj对象。函数show在声明时是一个全局函数,函数里面的this指向window,但当最后作为对象obj1的一个属性时,其this便指向了对象obj1。但是,请注意,并不是所有函数作为对象的方法来调用时,this都会指向调用者,如下:

var obj = {
x : 100,
y : function(){
setTimeout(
function(){ console.log(this.x); }
, 1000);
}
}; obj.y(); // undefined

上面栗子中的this指向的是window对象,并不是我们期待的obj,所以会弹出undefined。所以在书写这类代码时,尽量避免这种写法,当然,你也可以在调用的时候将当时的this所指向的对象存在一个变量里,等到定时器运行时再用所存的变量去调用x,如下:

var obj = {
x : 100,
y : function(){
var that = this;
setTimeout(
function(){ console.log(that.x); }
, 1000);
}
}; obj.y(); //

作为构造函数调用

当一个函数作为构造器使用时(通过new关键字),它的this值绑定到新创建的那个对象。

function Message(content){
this.content = content;
this.showContent = function(){
console.log(this.content);
};
} var message = new Message("I'm a message!");
message.showContent(); // I'm a message!

再看看下面这个栗子。

function obj(){
this.a=666;
return 'abc';
} var obj=new obj();
console.log(obj); // obj{a: 666}

有木有看出什么?当一个带有return返回值的函数作为构造器去new一个新的对象时,return的值是被忽略的。是不是很神奇!

函数被call,apply,bind调用的时候

所有的函数都有apply()和call()这两个方法。我们可以通过这两个方法来改变函数的上下文, 在任何时候都有效, 用来显式地设置this的值。

apply()方法接收两个参数: 第一个是要设置为this的那个对象,第二个参数是可选的,如果要传入参数,则封装为数组作为apply()的第二个参数即可。

call()方法和apply()基本上是一样的,除了后面的参数不是数组,而是分散开一个一个地附加在后面。

function warrior(speed, strength){
console.log(
"Warrior: " + this.kind +
", weapon: " + this.weapon +
", speed: " + speed +
", strength: " + strength
);
} var warrior1 = {
kind: "ninja",
weapon: "shuriken"
}; var warrior2 = {
kind: "samurai",
weapon: "katana"
}; warrior.call(warrior1, 9, 5); // Warrior: ninja, weapon: shuriken, speed: 9, strength: 5
warrior.apply(warrior2, [6, 10]); // Warrior: samurai, weapon: katana, speed: 6, strength: 10

  在上面,我们通过对构造器warrior()传入不同的参数创建不同类型的对象, this将指向我们通过call() 和/或 apply()传入的对象。

  在第一个函数调用中,我们使用call() 方法来将this设置为warrior1对象, 并传入需要的其他参数, 参数间用逗号分隔。在第二个函数调用中, 其实都差不多, 只是传入的是warrior2对象, 并将必要参数封装为一个数组。

  除了call()和apply()以外,ECMAScript 5还增加了bind()方法,在调用一个函数或方法时也可以通过bind方法来绑定this对象。让我们看下面的栗子:

function warrior(kind){
console.log(
"Warrior: " + kind +
". Favorite weapon: " + this.weapon +
". Main mission: " + this.mission
);
} var attributes = {
weapon: "shuriken",
mission: "espionage"
}; var ninja = warrior.bind(attributes, "ninja"); ninja(); // Warrior: ninja. Favorite weapon: shuriken. Main mission: espionage

在这个栗子中, bind()方法的使用方式还是类似的, 但warrior.bind()创建了一个新的函数(方法体和作用域跟warrior()一样),并没有改动原来的warrior()函数。新函数的功能和老的一样, 只是绑定到了attributes对象。

注:bind方法和call,apply的区别在于,bind() 之后函数并没有执行,可以传给其他函数,在某个适当的时机再调用。

深入浅出js中的this(一)的更多相关文章

  1. 深入浅出js中的this

    Q:this是什么? A:this是Javascript语言的一个关键字,它代表函数运行时,自动生成的一个内部对象,在每个 function 中自动根据作用域(scope) 确定, 指向的是此次调用者 ...

  2. JS中this关键字详解

    本文主要解释在JS里面this关键字的指向问题(在浏览器环境下). 阅读此文章,还需要心平气和的阅读完,相信一定会有所收获,我也会不定期的发布,分享一些文章,共同学习 首先,必须搞清楚在JS里面,函数 ...

  3. JS 中 this 关键字详解

    本文主要解释在JS里面this关键字的指向问题(在浏览器环境下). 首先,必须搞清楚在JS里面,函数的几种调用方式: 普通函数调用 作为方法来调用 作为构造函数来调用 使用apply/call方法来调 ...

  4. 深入理解js中的apply、call、bind

    概述 js中的apply,call都是为了改变某个函数运行时的上下文环境而存在的,即改变函数内部的this指向. apply() apply 方法传入两个参数:一个是作为函数上下文的对象,另外一个是作 ...

  5. 深入浅出js事件

    深入浅出js事件 一.事件流 事件冒泡和事件捕获分别由微软和网景公司提出,这两个概念是为了解决页面中事件流(事件发生顺序)的问题. <div id="outer"> & ...

  6. 浅入浅出JS中的eval及json

    声明: 首先声明一下,本人是JS新手,所以不敢说深入,只是把最近对eval的学习经验拿出来跟大家分享,如果您是高手可略去不看. 适合读者: 对JS中的eval一知半解,不知eval是如何把字符串转换为 ...

  7. 5.0 JS中引用类型介绍

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

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

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

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

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

随机推荐

  1. java.lang.NoClassDefFoundError: javax/transaction/Synchronization (jUnit测试报错)

      测试hibernate   报错原因项目缺少包   在 hibernate 解压目录下找到 jta.jar 文件     往项目中添加该 jar 包,即可解决   添加方法:[右击项目]--> ...

  2. xmbc 资源

    http://raspberrypi.diandian.com/post/2013-02-25/40048470423 http://blog.csdn.net/lincyang/article/de ...

  3. 使用linq 对 DataTable 中的数据进行 查询 与 分类求合

    A:linq 的查询方式写得可以非常简洁如下所示: DataTable dt = null;        private void XtraForm1_Load(object sender, Eve ...

  4. Go 学习笔记(一)

    随着Go的应用越来越火热,自己也终于开始学习了.平时经常用C,看着Go还是比较亲切的.好了,开始. 今天主要是按照书上的内容自己简单的实践了下最基本的输出,以及网页功能,上代码: package ma ...

  5. Windows内核编程之:分页内存与非分页内存 #define PAGEDCODE code_seg("PAGE") (转)

    原文链接:http://blog.chinaunix.net/uid-24504987-id-161192.html Windows规定有些虚拟内存可以交换到文件中,这类内存被称为分页内存 有些虚拟内 ...

  6. STM32 串口DMA方式接收(转)

    STM32 是一款基于ARM Cortex-M3内核的32位MCU,主频最高可达72M.最近因为要在车机上集成TPMS功能, 便开始着手STM32的开发工作,STM32F10x系列共有5个串口(USA ...

  7. Ubuntu 14.04 设置静态IP

    使用Network Manager UI界面中指定 手动时,无法保存. 通过修改配置文件解决来此问题.记录以下. 如果输入过密码后,就会出现在这个目录下面, 以如下chinaNet为例 gaojing ...

  8. Java中finalize方法用途何在?

    package thinking.in.java.demo; /* * finalize的用途何在? * *本例的终止条件是L所有的Book对象在被当做垃圾回收前都应该被签入.但是在main方法中 * ...

  9. Java之Property-统获取一个应用程序运行的次数

    package FileDemo; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStre ...

  10. A Tour of Go Methods continued

    In fact, you can define a method on any type you define in your package, not just structs. You canno ...