深入浅出js中的this(一)
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(一)的更多相关文章
- 深入浅出js中的this
Q:this是什么? A:this是Javascript语言的一个关键字,它代表函数运行时,自动生成的一个内部对象,在每个 function 中自动根据作用域(scope) 确定, 指向的是此次调用者 ...
- JS中this关键字详解
本文主要解释在JS里面this关键字的指向问题(在浏览器环境下). 阅读此文章,还需要心平气和的阅读完,相信一定会有所收获,我也会不定期的发布,分享一些文章,共同学习 首先,必须搞清楚在JS里面,函数 ...
- JS 中 this 关键字详解
本文主要解释在JS里面this关键字的指向问题(在浏览器环境下). 首先,必须搞清楚在JS里面,函数的几种调用方式: 普通函数调用 作为方法来调用 作为构造函数来调用 使用apply/call方法来调 ...
- 深入理解js中的apply、call、bind
概述 js中的apply,call都是为了改变某个函数运行时的上下文环境而存在的,即改变函数内部的this指向. apply() apply 方法传入两个参数:一个是作为函数上下文的对象,另外一个是作 ...
- 深入浅出js事件
深入浅出js事件 一.事件流 事件冒泡和事件捕获分别由微软和网景公司提出,这两个概念是为了解决页面中事件流(事件发生顺序)的问题. <div id="outer"> & ...
- 浅入浅出JS中的eval及json
声明: 首先声明一下,本人是JS新手,所以不敢说深入,只是把最近对eval的学习经验拿出来跟大家分享,如果您是高手可略去不看. 适合读者: 对JS中的eval一知半解,不知eval是如何把字符串转换为 ...
- 5.0 JS中引用类型介绍
其实,在前面的"js的六大数据类型"文章中稍微说了一下引用类型.前面我们说到js中有六大数据类型(五种基本数据类型 + 一种引用类型).下面的章节中,我们将详细讲解引用类型. 1. ...
- 【repost】JS中的异常处理方法分享
我们在编写js过程中,难免会遇到一些代码错误问题,需要找出来,有些时候怕因为js问题导致用户体验差,这里给出一些解决方法 js容错语句,就是js出错也不提示错误(防止浏览器右下角有个黄色的三角符号,要 ...
- JS中给正则表达式加变量
前不久同事询问我js里面怎么给正则中添加变量的问题,遂写篇博客记录下. 一.字面量 其实当我们定义一个字符串,一个数组,一个对象等等的时候,我们习惯用字面量来定义,例如: var s = &quo ...
随机推荐
- Timus 1746 Hyperrook
题意:在一个n维坐标系中,坐标的范围是0到m - 1,如果两个点坐标只有一个维度的坐标不同则可以相互移动,给出p个点,问任意两个点之间路径为d的个数是多少,答案与p取模. 解法:只需要考虑两个点之间不 ...
- Codeforces 628E Zbazi in Zeydabad 树状数组
题意:一个n*m的矩阵,要么是 . 要么是 z ,问可以形成几个大z 分析:(直接奉上官方题解,我感觉说的实在是太好了) Let's precalculate the values zlij, zri ...
- 如何添加网站for Linux(绑定域名)
[以下配置的路径以阿里云提供的标准环境路径为准,如果您另行安装,请根据实际安装路径配置]. 1.cd /alidata/server/httpd/conf/vhosts/ 进入绑定域名所在目录, ...
- python 网络编程 (二)---异常
异常 python的socket模块实际上定义了4种可能出现的异常: 1)与一般I/O 和通信问题有关的socket.error; 2)与查询地址信息有关的socket.gaierror; 3)与其他 ...
- OpenStack Swift client开发
如果你搭建好了Swift环境 ,你应该可以通过Swift 命令 来尝试去测试上传下载等功能,这是因为在安装Swift的时候,通常会安装一个python-swiftclient客户端,这个一个pytho ...
- 2016CCPC 中南地区邀请赛 A 矩阵快速幂
A A^n=A^(n%2016)%7; #include <iostream> #include <cstdio> #include <cstring> #incl ...
- 手机模拟器 上安装与卸载apk
一.安装apk 将apk放到sdk安装目录下的platform-tools(不同版本的sdk也可能是tools) 1.adb kill-server2.adb start-server3.adb re ...
- Python读取文件内容的三种方式并比较
本次实验的文件是一个60M的文件,共计392660行内容. 程序一: def one(): start = time.clock() fo = open(file,'r') fc = fo.readl ...
- 转载 GUID介绍
转载 http://www.cnblogs.com/illele/archive/2008/02/25/1080554.html GUID(Global unique identifier)全局唯一标 ...
- position跟display、margin collapse、overflow、float这些特性相互叠加后会怎么样?
这是寒冬大神提出的一个题目,刚开始看到这题的时候完全不知道从什么地方回答起好,题目内容比较广泛,找不到针对点.后来我觉得这个题目应该能拆成几个点来回答:1.'display'.'position' 和 ...