this关键字:

  JavaScript的this关键字,总是指向一个对象,具体指向哪个对象,是根据运行时函数指向环境动态绑定的。简单来说,this就是谁调用指向谁。具体使用中,this的指向,大致可以分为以下这几种情况:

  1、作为对象的方法调用,this指向该对象

        var obj = {
a:1,
getA: function(){
alert(this === obj); //true
alert(this.a); //
}
};
obj.getA();

  2、作为普通函数调用,this指向全局对象。在浏览器的JavaScript里,全局对象就是window对象。

        var name = 'globalName';
var getName = function(){
alert(this.name);
};
getName();//globalName

  或者:

        window.name = "globalName";
var myObj = {
name:"sven",
getName:function(){
alert(this.name);
}
};
myObj.getName(); //sven
var getName = myObj.getName;
getName(); //globalName

  上面这个小栗子myObj.getName()和getName()的结果不一样,是因为调用他们的对象不一样,myObj.getName()中的this指向的就是myObj对象,这个对象的name值是"sven",而getName()的this指向的是我们新声明的变量getName,myObj对象的getName()的方法,应用在了变量getName上,这时候this指向的就是全局变量name = "globalName"了。

  由于调用this的对象不同,它的指向也不一样,有时候会有一些困扰,如下代码:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div id="div1">我是div1</div>
<script>
document.getElementById("div1").onclick = function () {
alert(this.id);//div1
var getId = function(){
alert(this.id);
};
getId();//undefined
};
</script>
</body>
</html>

  上面的代码中,我们想让getId()的这个回调函数的this.id是div的节点,但是它给我们的是undefined,对于这种情况,我们怎么解决呢?有一个简单的方案,就是把当前的this对象赋值给一个变量,这个被赋值的变量指向的就是当前的this对象,就不会变喽,具体使用如下:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div id="div1">我是div1</div>
<script>
document.getElementById("div1").onclick = function () {
var that = this;
alert(this.id);//div1
var getId = function(){
alert(that.id);
};
getId();//div1
};
</script>
</body>
</html>

  是不是一个很实用的小技巧?在this作为普通函数调用的时候,我们还需要注意一点就是,在ES5的严格模式下,thi是undefined。

  3、作为构造器调用,这种调用方式,其实就是用new操作符生成一个对象,而this指向的就是这个新的对象。下面的示例帮我们理解一下this的这种调用方式:

        var myClass = function(){
this.name = 'sven';
};
var obj = new myClass();
alert(obj.name);

  但构造器的这种方式,我们需要注意一个问题,如果构造器显示地返回了一个object对象(只能是对象类型,如果是基础数据类型,则不会影响this的输出),那最终返回的回事这个对象,而不是我们之前定义的this:

        var myClass = function(){
this.name = 'sven';
return {
name:'anne'
}
};
var obj = new myClass();
alert(obj.name);

  call和apply:

  ES3中,给Function的原型定义了两个方法,他们是Function.prototype.callheFunction.prototype.apply。

  相同点:功能一样,都可以用来代替另一个对象调用一个方法,将一个函数的对象上下文从初始的上下文改变为由thisObj指定的新对象。

  区别:传入参数形式不同

    apply接受两个参数,第一个参数指定了函数体内this对象的指向,第二个参数为一个数组,B.apply(A, arguments);即A对象应用B对象的方法。

    call可以接受多个参数,第一个参数与apply一样,后面则是一串参数列表,B.call(A, args1,args2);即A对象调用B对象的方法。

  等价写法:foo.call(this,arg1,arg2,arg3) == foo.apply(this, arguments)==this.foo(arg1, arg2, arg3)

  call和apply的用途:

  1、改变this指向,call和apply最常见的用法就是改变函数内部this的指向,如:

        var obj1 = {
name:'sven'
};
var obj2 = {
name:'anne'
};
window.name = 'window';
var getName = function(){
console.log(this.name);
};
getName();//window
getName.call(obj1);//sven
getName.call(obj2);//anne

  在前面this的小栗子里,有一个将当前this对象保持下来以方便在回调函数中使用当前的this对象,避免this重新指向的问题,从而可以操作div节点,这的问题,我们使用call或者apply也可以解决,具体代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div id="div1">我是div1</div>
<script>
document.getElementById("div1").onclick = function () {
alert(this.id);//div1
var getId = function(){
alert(this.id);
};
getId.call(this);//div1
};
</script>
</body>
</html>

  我们也可以使用call和apply来修正this的场景,这样说不是很清楚,我们通过这个例子来理解一下:对于js获取元素ID的方法,大家都知道,是document.getElementById,这个方法名很长,所以我们想用一个短的函数来代替它:

        var getId = function(id){
return document.getElementById(id);
};
getId("div1");

  将上面的方法再简化:

        var getId = document.getElementById;
getId("div1");

  但是这个简化过的方法,我们在浏览器里测一下,会报错,用不了,为什么呢?这是因为浏览器引擎的document.getElementById()这个方法,在内部实现的时候,有用到this,当我们直接使用的时候,this是指向调用他的div对象的,但是当我们把这个方法赋给getId这个变量的时候,this指向的其实就是window对象了,而不是我们期望的div节点,现在我们用call或者apply来修正一下this的指向:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div id="div1">我是div1</div>
<script>
document.getElementById = (function(func){
return function(){
return func.apply(document, arguments);
}
})(document.getElementById);
var getId = document.getElementById;
var div = getId('div1');
console.log(div);
</script>
</body>
</html>

  这样我们就修正了在document.getElementById中丢了的this。

  2.Function.prototype.bind:

  大部分浏览器都实现了内置的Function.prototype.bind,用来指定函数内部的this指向,即使没有原生的Function.prototype.bind,我们也可以模拟一个,代码如下:

        Function.prototype.bind = function(context){
var self = this; //保存原函数
return function(){ //返回一个新的函数
return self.apply(context,arguments); //执行新函数的时候,会把之前传入的context当作新函数体内的this
}
};
var obj = {
name: 'sven'
};
var func = function(){
alert(this.name); //sven
}.bind(obj);
func();

  这是一个简化版的bind方法,我们还可以把它变得更复杂一点,以方便我们向func里传入一些参数:

Function.prototype.bind = function(context) {
console.log(context);
console.log(arguments);
var self = this, //保存原函数
//context = [].shift.call(arguments), //需要绑定的this上下文
args = [].slice.call(arguments); //剩余的参数转成数组
console.log(context);
console.log(args);
return function() { //返回一个新的函数
return self.apply(context, [].concat.call(args, [].slice.call(arguments))); //执行新函数的时候,会把之前传入的context当作新函数体内的this 并且组合两次分别传入的参数 作为新函数的参数
}
};
var obj = {
name: 'sven'
};
var func = function(a, b, c, d) {
console.log(this.name); //sven
console.log([a, b, c, d]);
}.bind(obj, 1, 2);
func(3);

  3.借用其他对象的方法

  借用方法的第一种使用场景是“借用构造函数”,通过这种方法,可以实现类似继承的效果:

var A = function(name){
this.name = name;
}; var B = function(){
A.apply(this, arguments);
}; B.prototype.getName = function(){
return this.name;
}; var b = new B('sven');
console.log(b.getName());

  借用方法的第二个场景,主要是借用数组对象的方法,借用数组的方法,在使用的过程中,需要注意这两点:

    a.操作的对象本身要可以存取属性;

    b.操作对象的length属性可读写;

  例子如下:

var a = {};
Array.prototype.push.call(a, 'first'); console.log(a);
console.log(a.length);
console.log(a[0]);

  如果上面例子中,a不是对象类型,而是基础数据类型,如Number等,这种借用方法是不可行的。

this、call和apply、bind的更多相关文章

  1. call,apply,bind的用法

    关于call,apply,bind这三个函数的用法,是学习javascript这门语言无法越过的知识点.下边我就来好好总结一下它们三者各自的用法,及常见的应用场景. 首先看call这个函数,可以理解成 ...

  2. JavaScript中call,apply,bind方法的总结。

    why?call,apply,bind干什么的?为什么要学这个? 一般用来指定this的环境,在没有学之前,通常会有这些问题. var a = { user:"追梦子", fn:f ...

  3. call(),apply(),bind()与回调

    1.call(),apply(),bind()方法 JavaScript 中通过call或者apply用来代替另一个对象调用一个方法,将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定 ...

  4. JS 的 call apply bind 方法

    js的call apply bind 方法都很常见,目的都是为了改变某个方法的执行环境(context) call call([thisObj[,arg1[, arg2[,   [,.argN]]]] ...

  5. javascript-this,call,apply,bind简述2

    上节我们一起研究了this这个小兄弟,得出一个结论,this指向调用this所在函数(或作用域)的那个对象或作用域.不太理解的朋友可以看看上节的内容,这次我们主要探讨一下call(),apply(), ...

  6. javascript-this,call,apply,bind简述1

    最近在系统的学习面向对象方面的知识,遇到的最大拦路虎就数this的指向,call,apply,bind函数的使用,单独抽出一天时间把这几个烦人的家伙搞定,去学习更深入的内容. 首先介绍一下this的一 ...

  7. call,apply,bind方法的总结

    why?call,apply,bind干什么的?为什么要学这个? 一般用来指定this的环境,在没有学之前,通常会有这些问题. var a = { user:"追梦子", fn:f ...

  8. JavaScript中call,apply,bind方法的总结

    原文链接:http://www.cnblogs.com/pssp/p/5215621.html why?call,apply,bind干什么的?为什么要学这个? 一般用来指定this的环境,在没有学之 ...

  9. call, apply,bind 方法解析

    call(), apply(),bind() 三者皆为Function的方法 call(),apply()的作用是调用方法,并改变函数运行时的context(作用上下文) bind() 的作用是引用方 ...

  10. JS中call,apply,bind方法的总结

    why?call,apply,bind干什么的?为什么要学这个? 一般用来指定this的环境,在没有学之前,通常会有这些问题. var a = { user: "小马扎", fn: ...

随机推荐

  1. BNUOJ 6727 Bone Collector

    Bone Collector Time Limit: 1000ms Memory Limit: 32768KB   This problem will be judged on HDU. Origin ...

  2. 【C#】C#数据类型和VB的区别

    导读:看完了C#,需要总结的有很多东西.开始没有怎么在意,根本没有意识到,那些视频是教给了我一种新的编程语言,我就真的是像看电视剧一样的看完了.猛然想起了学过的VB,这是目前为止,我接触到的仅有的语言 ...

  3. POJ 2403 Hay Points

    Hay Points Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 5735   Accepted: 3695 Descri ...

  4. BZOJ 1007 [HNOI2008]水平可见直线 ——计算几何

    用了trinkle的方法,半平面交转凸包. 写了一发,既没有精度误差,也很好写. #include <map> #include <ctime> #include <cm ...

  5. [BZOJ2118] 墨墨的等式(最短路)

    传送门 好神啊.. 需要用非负数个a1,a2,a3...an来凑出B 可以知道,如果一个数x能被凑出来,那么x+a1,x+a2.......x+an也都能被凑出来 那么我们只需要选择a1~an中任意一 ...

  6. 刷题总结——赛车(bzoj3190)

    题目: 题目背景 JLOI2013 T1 题目描述 这里有一辆赛车比赛正在进行,赛场上一共有 N 辆车,分别称为 g1,g2,……,gn.赛道是一条无限长的直线.最初,gi 位于距离起跑线前进 ki  ...

  7. ajax同步导致ajax上面的代码不执行?

    js代码:环境:IE11要求:点击一个按钮后,页面xxx的地方立即显示"开始处理...",直到ajax处理结束后,xxx内容才更新为新的处理结果:点击事件执行代码如下:xxx.in ...

  8. N*N数码问题

    奇数码问题 时间限制: 1 Sec  内存限制: 128 MB 题目描述 你一定玩过八数码游戏,它实际上是在一个3*3的网格中进行的,1个空格和1~8这8个数字恰好不重不漏地分布在这3*3的网格中. ...

  9. HTML中字体单位px pt em之间的转换

    在实现打印功能时,遇到一个问题,使用px作为单位在不同的机器或者打印机上打印出的字体大小不一样,所以经过查询,发现使用pt为单位能够进行物流适配,下面是各单位之间的转换: 定义字体大小有常见三种单位, ...

  10. http状态码的分类

    状态码分类 转自http://www.cnblogs.com/TankXiao/archive/2013/01/08/2818542.html HTTP状态码被分为五大类, 目前我们使用的HTTP协议 ...