详解JavaScript中this关键字的用法


Posted in Javascript onMay 26, 2016

this是函数内部的一个特殊对象,this引用的是函数据以执行的环境对象(关于环境对象我们会在文章最后作补充说明),在调用函数前this的值并不确定,不同的调用方式会导致this值的改变。

window.num = 22;
var o = {num: 11};
function sayNum(){
  alert(this.num)
}
sayNum();//22
o.sayNum = sayNum;
o.sayNum();//11

记住:函数名仅仅是一个包含指针的变量而已。因此即使是在不同的环境中执行,全局的sayNum()函数与o.sayNum()指向的仍然是同一个函数。

1.全局作用域中调用函数时
全局作用域中调用,this对象引用的是window
匿名函数的执行具有全局性,因此其this对象通常也指向window

function fn1(){
  console.log(this);
}

fn1();

2.通过new操作符调用
this引用的是实例对象

function Person(name){
  this.name = name;
}
Person.prototype.printName = function(){
  alert(this.name);//Byron
};

var p1 = new Person('Byron');

3.作为对象的方法调用
this引用的是该对象

var obj1 = {
  name: 'Byron',
  fn : function(){
    console.log(this);
  }
};

obj1.fn();

4.间接调用
call和apply
每个函数都包含两个非继承而来的方法:call()和apply()。这两个方法的用途都是在特定的作用域中调用函数,实际上等于设置函数体内this对象的值。也就是说,直接调用函数,调用时指定执行环境是谁

window.color = 'red';
var o = {color: 'blue'};
function sayColor(){
  alert(this.color);
}
sayColor.call(this);//red
sayColor.call(window);//red
sayColor.call(o);//blue

(1)apply方法
接收两个参数,一个是在函数中运行函数的作用域,另一个是参数数组。

(2)call方法
call方法与apply方法相同,区别在于接收参数的方式不同,对于call方法而言,第一个参数是this值没有变化,变化的是其余参数都直接传递给函数。

function fn(){
   console.log(this)//windwow
   function InnerFn(){
     console.log(this)
   }
   InnerFn.call(this)//window
}
fn();
 function fn0(){
   console.log(this)//window
}
function fn1(){
   fn0.call(this);
   console.log(this);//window
}
fn1();
function fn0(){
 console.log(this)//object
}
var o = {
  fn1: function fn1(){
    fn0.call(this);
    console.log(this);//object
  }
}
o.fn1();

5.bind方法
这个方法会创建一个函数的实例,其this值会被绑定到传给bind()函数的值。也就是说会返回一个新函数,并且使函数内部的this为传入的第一个参数

window.color = 'red';
var o = {color : 'blue'};
function sayColor(){
  alert(this.color)
}
var objectSayColor = sayColor.bind(o);
objectSayColor();//blue

补充说明:执行环境定义
定义了变量或者函数有权访问的其他数据,每个执行环境都有一个与之相关联的变量对象,环境中定义的所有变量和函数都保存在这个对象中。我们编写的代码无法访问这个对象,但解析器会在处理数据时在后台使用它。
一、执行环境的创建:

1.全局执行环境
在web浏览器中,全局执行环境被认为是window对象,因此所有全局变量和函数都是作为window对象的属性和方法创建的。代码载入浏览器时,全局执行环境被创建(当我们关闭网页或者浏览器时全局执行环境才被销毁)。

2.局部执行环境
每个函数都有自己的执行环境,因此局部执行环境为函数对象。当函数被调用时函数的局部环境被创建(函数内的代码执行完毕后,该环境被销毁,同时保存在其中的所有变量和函数定义也随之被销毁)。

这个执行环境以及相关的变量对象是个抽象的概念,解释如下

var a = 1;
function fn(num1,num2){
  var b = 2;
  function fnInner(){
    var c = 3;
    alert(a + b + c);
  }
  fnInner();//fnInner调用时局部执行环境创建
}
fn(4,5);//fn调用时局部执行环境创建

详解JavaScript中this关键字的用法

二、作用域链
javascript函数的执行用到了作用域链,这个作用域链是函数定义的时候创建的,当定义一个函数时,它实际保存一个作用域链。当调用这个函数时,它创建一个新的对象来存储它的局部变量,并将这个对象添加至保存的作用域链。作用域链的前端始终都是当前执行的代码所在环境的变量对象。作用域链的末端始终都是全局执行环境的变量对象。作用域链的用途,是保证对执行环境有权访问的所有变量和函数的有权访问

var scope = 'global scope';
function checkscope(){
  var scope = 'local scope';
  function f(){return scope};
  return f;
}
checkscope()();//local scope

理解:当调用checkscope时,函数f被定义并作为局部变量绑定到了checkscope作用域链上,因此函数f无论在哪里调用,这种绑定依然有效,因此返回值为local scope。

var num1 = 1;
function Outer(){
  var num2 = 2;
  console.log(num1 + num2);//3
  function Inner(){
    //这里可以访问num3,num2,num1
    var num3 = 3;
    console.log(num1 + num2 + num3);//6
    }
  //这里可以访问num2,Inner(),num1但不能访问num3
  Inner();
}
Outer();
console.log(num1);//1,执行环境
//这里只能访问num1

作用域链(向上搜索):内部环境可以通过作用域链访问所有的外部环境,但外部环境不能访问内部环境中的任何变量和函数。

var name = 'Byron';
  function fn(){
    var name = 'Csper';
    console.log(name);//Casper
  }
  fn();

   
越往内部的环境,变量权重越高。

注意:没有带var关键字直接声明的变量属于全局变量如直接声明a = 1,此时的a为全局变量。

javscript引擎在进入作用域时,会对代码分两轮处理。第一轮,初始化变量。第二轮,执行代码

var a = 1;
function prison (a) {
  console.log(a);//1
  var a;
  console.log(a);//1
}
prison(1);

三、函数执行
函数调用进入执行环境时,首先处理arguments,初始化形参(默认值为undefined),然后初始化函数内的函数声明,当代码一步一步执行时再初始化函数内的变量声明(进入环境未开始执行代码时,值为undefined)。所以函数内的初始化顺序为形参,函数声明,变量声明。可以从上图图一看出。下面我来举个例子(整个全局环境也是函数)。

alert(typeof fn);//function,函数声明提前
alert(typeof fn0);//undefined,变量声明提前但未赋值
function fn(){
//函数表达式
}
var fn0 = function(){
//函数定义式
}
alert(typeof fn0);//function,此时变量已被赋值
Javascript 相关文章推荐
用Div仿showModalDialog模式菜单的效果的代码
Mar 05 Javascript
jquery实现图片等比例缩放以及max-width在ie中不兼容解决
Mar 21 Javascript
JS二维数组的定义说明
Mar 03 Javascript
Angularjs注入拦截器实现Loading效果
Dec 28 Javascript
三种带箭头提示框总结实例
Jun 14 Javascript
js简单获取表单中单选按钮值的方法
Aug 23 Javascript
JavaScript字符集编码与解码详谈
Feb 02 Javascript
详谈Node.js之操作文件系统
Aug 29 Javascript
基于vue开发的在线付费课程应用过程
Jan 25 Javascript
微信小程序封装自定义弹窗的实现代码
May 08 Javascript
JavaScript遍历查找数组中最大值与最小值的方法示例
May 24 Javascript
JavaScript find()方法及返回数据实例
Apr 30 Javascript
ashx文件获取$.ajax()方法发送的数据
May 26 #Javascript
js操作数据库实现注册和登陆的简单实例
May 26 #Javascript
js判断主流浏览器类型和版本号的简单实现代码
May 26 #Javascript
轻松掌握JavaScript中的Math object数学对象
May 26 #Javascript
JS表格组件神器bootstrap table详解(强化版)
May 26 #Javascript
JS在一定时间内跳转页面及各种刷新页面的实现方法
May 26 #Javascript
JavaScript的String字符串对象常用操作总结
May 26 #Javascript
You might like
php写的带缓存数据功能的mysqli类
2012/09/06 PHP
C# WinForm中实现快捷键自定义设置实例
2015/01/23 PHP
php通过ksort()函数给关联数组按照键排序的方法
2015/03/18 PHP
php版微信公众平台入门教程之开发者认证的方法
2016/09/26 PHP
php实现通过stomp协议连接ActiveMQ操作示例
2020/02/23 PHP
PHP获取php,mysql,apche的版本信息及更多服务器信息
2021/03/09 PHP
页面中body onload 和 window.onload 冲突的问题的解决
2009/07/01 Javascript
基于jQuery的遍历同id元素 并响应事件的代码
2012/06/14 Javascript
Javascript拓展String方法小结
2013/07/08 Javascript
Jquery的each里用return true或false代替break或continue
2014/05/21 Javascript
jQuery 过滤方法filter()选择具有特殊属性的元素
2014/06/15 Javascript
AngularJS实现表单验证
2015/01/28 Javascript
jQuery实现限制textarea文本框输入字符数量的方法
2015/05/28 Javascript
如何制作幻灯片(代码分享)
2017/01/06 Javascript
JQuery ZTree使用方法详解
2017/01/07 Javascript
JavaScript DOM节点操作实例小结(新建,删除HTML元素)
2017/01/19 Javascript
Bootstrap表单控件学习使用
2017/03/07 Javascript
利用jQuery实现一个简单的表格上下翻页效果
2017/03/14 Javascript
Node.js中使用mongoose操作mongodb数据库的方法
2017/09/12 Javascript
node+express+ejs使用模版引擎做的一个示例demo
2017/09/18 Javascript
Angular2.0实现modal对话框的方法示例
2018/02/18 Javascript
laypage.js分页插件使用方法详解
2019/07/27 Javascript
layer弹窗在键盘按回车将反复刷新的实现方法
2019/09/25 Javascript
python为tornado添加recaptcha验证码功能
2014/02/26 Python
介绍Python中几个常用的类方法
2015/04/08 Python
初步理解Python进程的信号通讯
2015/04/09 Python
python 查找文件名包含指定字符串的方法
2018/06/05 Python
Python实现基于POS算法的区块链
2018/08/07 Python
python正则表达式的懒惰匹配和贪婪匹配说明
2020/07/13 Python
css3绘制百度的小度熊
2018/10/29 HTML / CSS
html5 video标签屏蔽右键视频另存为的js代码
2013/11/12 HTML / CSS
HTML5 Notification(桌面提醒)功能使用实例
2014/03/17 HTML / CSS
个人简历的自荐信
2013/10/23 职场文书
财政局长自荐信范文
2013/12/22 职场文书
国际贸易专业个人职业生涯规划
2014/02/15 职场文书
2015年大学组织委员个人工作总结
2015/10/23 职场文书