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 相关文章推荐
Prototype使用指南之enumerable.js
Jan 10 Javascript
用正则获取指定路径文件的名称
Feb 27 Javascript
JavaScript入门教程(2) JS基础知识
Jan 31 Javascript
非html5实现js版弹球游戏示例代码
Sep 22 Javascript
js判断数据类型如判断是否为数组是否为字符串等等
Jan 15 Javascript
基于javascript实现图片切换效果
Apr 17 Javascript
使用jquery datatable和bootsrap创建表格实例代码
Mar 17 Javascript
ES6模块化的import和export用法方法总结
Aug 08 Javascript
详解mpvue小程序中怎么引入iconfont字体图标
Oct 01 Javascript
layui 上传图片 返回图片地址的方法
Sep 26 Javascript
vue实现购物车选择功能
Jan 10 Javascript
vue项目查看vue版本及cli版本的实现方式
Oct 24 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
PHP使用mysqldump命令导出数据库
2015/04/14 PHP
用js实现控制内容的向上向下滚动效果
2007/06/26 Javascript
Js 弹出框口并返回值的两种常用方法
2010/12/30 Javascript
js实现单一html页面两套css切换代码
2013/04/11 Javascript
JS实现超过长度限制后自动跳转下一款文本框的方法
2015/02/23 Javascript
javascript实现简单计算器效果【推荐】
2016/04/19 Javascript
JS简单获取客户端IP地址的方法【调用搜狐接口】
2016/09/05 Javascript
性能优化之代码优化页面加载速度
2017/03/01 Javascript
利用node.js写一个爬取知乎妹纸图的小爬虫
2017/05/03 Javascript
使用vs code开发Nodejs程序的使用方法
2017/09/21 NodeJs
微信小程序实现YDUI的ScrollNav组件
2018/02/02 Javascript
用js限制网页只在微信浏览器中打开(或者只能手机端访问)
2020/12/24 Javascript
JS加载解析Markdown文档过程详解
2020/05/19 Javascript
[01:41]DOTA2 2015国际邀请赛中国区预选赛第三日战报
2015/05/28 DOTA
Python操作json数据的一个简单例子
2014/04/17 Python
python同时给两个收件人发送邮件的方法
2015/04/30 Python
Python中文竖排显示的方法
2015/07/28 Python
wxPython之解决闪烁的问题
2018/01/15 Python
PyQt5每天必学之日历控件QCalendarWidget
2018/04/19 Python
Python numpy实现二维数组和一维数组拼接的方法
2018/06/05 Python
pandas 对series和dataframe进行排序的实例
2018/06/09 Python
如何基于Python批量下载音乐
2019/11/11 Python
Django 解决开发自定义抛出异常的问题
2020/05/21 Python
Python faker生成器生成虚拟数据代码实例
2020/07/20 Python
Python改变对象的字符串显示的方法
2020/08/01 Python
PurCotton全棉时代官网:100%天然棉花生产的生活护理用品
2016/11/18 全球购物
美国豪华的多品牌精品店:The Webster
2019/07/31 全球购物
linux面试相关问题
2012/08/11 面试题
项目合作意向书范本
2014/04/01 职场文书
学习雷锋倡议书
2014/04/15 职场文书
买卖车协议书
2014/04/21 职场文书
运动会标语
2014/06/21 职场文书
2014年财务部工作总结
2014/11/11 职场文书
高三语文教学反思
2016/02/16 职场文书
写作技巧:优秀文案必备的3种结构
2019/08/19 职场文书
浅谈react useEffect闭包的坑
2021/06/08 Javascript