JS中this的指向以及call、apply的作用


Posted in Javascript onMay 06, 2018

在具体的实际应用中,this 的指向无法在函数定义时确定,而是在函数执行的时候才确定的,根据执行时的环境大致可以分为以下3种:

1、当函数作为普通函数调用时,this 指向全局对象

2、当函数作为对象的方法调用时,this 指向该对象

3、当函数作为构造器调用时,this 指向新创建的对象

示例一:

window.name = 'myname';
function getName() {
  console.log(this.name);
}
getName(); //输出myname

示例二:

var boy = {
  name: 'Bob',
  getName: function() {
    console.log(this.name);
  }
}
boy.getName(); //输出Bob

示例三:

function Boy(name) {
  this.name = name;
}
var boy1 = new Boy('Bob');
console.log(boy1.name); //输出Bob

对于示例三,还有一种特殊情况,就是当构造函数通过 "return" 返回的是一个对象的时候,此次运算的最终结果返回的就是这个对象,而不是新创建的对象,因此 this 在这种情况下并没有什么用。

示例四:

function Boy(name) {
  this.name = name;
  return { //返回一个对象
    name: 'Jack'
  }
}
var boy1 = new Boy('Bob');
console.log(boy1.name); //输出Jack

示例五:

function Boy(name) {
  this.name = name;
  return 1; //返回非对象
}
var boy1 = new Boy('Bob');
console.log(boy1.name); //输出Bob

call 和 apply 的作用

apply 接受两个参数,第一个参数指定了函数体内 this 的指向,第二个参数是一个数组或类数组,用于传递被调用函数的参数列表。

示例一:

function getInfo() {
  console.log(this.name+' like '+arguments[0]+' and '+arguments[1]);
}
var boy1 = {
  name: 'Bob',
  age: 12
}
getInfo.apply(boy1,['sing','swimming']); //输出Bob like sing and swimming

call 传入参数的数量是不固定的,跟 apply 相同的是,第一个参数也是用于指定函数体内 this 的指向,从第二个参数开始往后,每个参数被依次传入被调用函数。

示例二:

function getInfo() {
  console.log(this.name+' like '+arguments[0]+' and '+arguments[1]);
}
var boy1 = {
  name: 'Bob',
  age: 12
}
getInfo.call(boy1,'sing','shopping'); //输出Bob like sing and shopping

此外,大部分高级浏览器还实现了 bind 方法,它与 call 和 apply 的区别在于 bind 只是改变函数内部 this 的指向,但不会立即执行,你需要显示调用它。

示例三:模拟浏览器的 bind 方法

Function.prototype.bind = function(obj){
  var self = this;
  return function(){
    return self.apply(obj,arguments);
  }
};
var obj = {
  name: 'Bob',
  age: 12
};
var func = function(){
  console.log(this.name+' like '+arguments[0]+' and '+arguments[1]);
}.bind(obj);
func('sing','shopping');

丢失的 this

在某些情况下会丢失 this 的指向,此时,我们就需要借助 call、apply 和 bind 来改变 this 的指向问题。

示例一:当 "getName" 方法作为 "boy" 对象的属性调用时,this 指向 "boy" 对象,当另外一个变量引用 "getName" 方法时,因为它是作为普通函数调用,所以 this 指向全局对象window

var boy = {
  name: 'Bob',
  getName: function() {
    console.log(this.name);
  }
}
boy.getName(); //输出Bob
var getBoyName = boy.getName;
getBoyName(); //输出undefined

示例二:即使在函数内部定义的函数,如果它作为普通对象调用,this 同样指向 window 对象

var boy1 = {
  name: 'Bob',
  age: 12,
  getInfo: function() {
    console.log(this.name);
    function getAge() {
      console.log(this.age);
    }
    getAge();
  }
}
boy1.getInfo(); //Bob
        //undefined
Javascript 相关文章推荐
写了一个layout,拖动条连贯,内容区可为iframe
Aug 19 Javascript
firefox事件处理之自动查找event的函数(用于onclick=foo())
Aug 05 Javascript
JQuery插件Marquee.js实现无缝滚动效果
Apr 26 Javascript
js生成随机数(指定范围)的实例代码
Jul 10 Javascript
AngularJS基础 ng-src 指令简单示例
Aug 03 Javascript
JS自定义函数对web前端上传的文件进行类型大小判断
Oct 19 Javascript
JavaScript实现的select点菜功能示例
Jan 16 Javascript
微信小程序开发之实现自定义Toast弹框
Jun 08 Javascript
基于AngularJs select绑定数字类型的问题
Oct 08 Javascript
vue拖拽排序插件vuedraggable使用方法详解
Aug 21 Javascript
微信小程序实现音频文件播放进度的实例代码
Mar 02 Javascript
为react组件库添加typescript类型提示的方法
Jun 15 Javascript
如何利用@angular/cli V6.0直接开发PWA应用详解
May 06 #Javascript
Less 安装及基本用法
May 05 #Javascript
es6新特性之 class 基本用法解析
May 05 #Javascript
JS同步、异步、延迟加载的方法
May 05 #Javascript
JavaScript生成指定范围随机数和随机序列的方法
May 05 #Javascript
JS文件中加载jquery.js的实例代码
May 05 #jQuery
关于js的三种使用方式(行内js、内部js、外部js)的程序代码
May 05 #Javascript
You might like
MySql 按时间段查询数据方法(实例说明)
2008/11/02 PHP
php设计模式 Template (模板模式)
2011/06/26 PHP
PHP 绘制网站登录首页图片验证码
2016/04/12 PHP
php高性能日志系统 seaslog 的安装与使用方法分析
2020/02/29 PHP
jquery 插件开发方法小结
2009/10/23 Javascript
Jquery进度条插件 Progress Bar小问题解决
2011/07/12 Javascript
批量实现面向对象的实例代码
2013/07/01 Javascript
Javascript实现滚动图片新闻的实例代码
2013/11/27 Javascript
Jquery原生态实现表格header头随滚动条滚动而滚动
2014/03/18 Javascript
$(document).ready(function() {})不执行初始化脚本
2014/06/19 Javascript
Bootstrap入门书籍之(五)导航条、分页导航
2016/02/17 Javascript
火狐和ie下获取javascript 获取event的方法(推荐)
2016/11/26 Javascript
headjs实现网站并行加载但顺序执行JS
2016/11/29 Javascript
原生实现一个react-redux的代码示例
2018/06/08 Javascript
简述pm2常用命令集合及配置文件说明
2019/05/30 Javascript
Vue实现微信支付功能遇到的坑
2019/06/05 Javascript
Vue的编码技巧与规范使用详解
2019/08/28 Javascript
原生js实现随机点名
2020/07/05 Javascript
vue 函数调用加括号与不加括号的区别
2020/10/29 Javascript
[04:52]第二届DOTA2亚洲邀请赛主赛事第一天比赛集锦:OG娜迦海妖放大配合谜团大中3人
2017/04/02 DOTA
[00:10]DOTA2全国高校联赛速递
2018/05/30 DOTA
[01:02:55]CHAOS vs Mineski 2019国际邀请赛小组赛 BO2 第二场 8.16
2019/08/18 DOTA
[01:03:18]DOTA2-DPC中国联赛 正赛 RNG vs Dynasty BO3 第一场 1月29日
2021/03/11 DOTA
比较详细Python正则表达式操作指南(re使用)
2008/09/06 Python
python+django快速实现文件上传
2016/10/24 Python
python实现KNN分类算法
2019/10/16 Python
Python xlwt模块使用代码实例
2020/06/10 Python
Keras模型转成tensorflow的.pb操作
2020/07/06 Python
分解成质因数(如435234=251*17*17*3*2,据说是华为笔试题)
2014/07/16 面试题
排序都有哪几种方法?请列举。用JAVA实现一个快速排序
2014/02/16 面试题
初中美术教学反思
2014/01/29 职场文书
医学专业应届生的自我评价
2014/02/28 职场文书
会计试用期自我评价怎么写
2014/09/18 职场文书
《丑小鸭》教学反思
2016/02/19 职场文书
Python 把两层列表展开平铺成一层(5种实现方式)
2021/04/07 Python
选购到合适的激光打印机
2022/04/21 数码科技