JavaScript中arguments和this对象用法分析


Posted in Javascript onAugust 08, 2018

本文实例讲述了JavaScript中arguments和this对象用法。分享给大家供大家参考,具体如下:

在函数内部有两个特殊的对象 : arguments和this。

1、arguments对象

js函数不介意定义多少参数,也不在乎传递进来多少参数,也就是说,即使定义的函数只接收2个参数,在调用时候也未必传递2个参数,因为js的函数参数在内部使用一个数组表示的,在函数体内可以通过arguments对象访问此参数数组。因此,js函数可以不显式地使用命名参数。

当函数被调用时,传入的参数将保存在arguments类数组对象中,通过arguments可以访问所有该函数被调用时传递给它的参数列表。

arguments是一个类数组对象,因为arguments可以通过方括号语法访问每一个元素,且拥有一个length属性,但它缺少所有的数组方法,因此并不是一个真正的数组。

使用arguments可以实现一个求和函数:

function add() {
 var sum = 0;
 for (var i = 0, len = arguments.length; i < len; i++)
  sum += arguments[i];
 return sum;
}

虽然arguments的主要用途是保存函数参数,但这个对象还有一个callee属性,该属性是一个指针,指向拥有这个arguments对象的函数。

使用arguments.callee属性可以实现一个阶乘函数:

function factorial(num) {
  if (num <= 1)
  return 1;
  else
  return num * arguments.callee(num - 1);
}

注意:

在严格模式下,不能使用arguments.callee属性,也不能对arguments对象赋值,更不能用arguments对象跟踪参数的变化。

可以使用命名函数表达式来达成同样的效果:

var factorial = (function func(num) {
 if (num <= 1)
  return 1;
 else
  return num * func(num - 1);
));

由于js函数没有签名(定义接受的参数的类型和数量),js函数没有重载,对于同名函数,后定义的函数会覆盖先定义的函数。当然,通过检查传入的参数的类型和数量并做出不同的反应,可以模仿方法的重载。

2、this对象

与别的语言不同,JavaScript的this总是指向一个对象,而具体指向哪个对象是在运行时基于函数的执行环境动态绑定的,而非函数被声明时的环境。

  • this是执行上下文的一个属性,其值在进入上下文时确定,且在上下文运行期间永久不变。
  • this 是动态绑定的,即在运行期绑定。
  • this可以是全局对象,当前对象或任意对象,取决于函数的调用方式。函数的调用方式有以下几种:作为普通函数调用,作为对象方法调用,作为构造函数调用,使用call()apply()调用。

(1)作为普通函数调用

当函数不作为对象的属性被调用,即直接被调用时,this会被绑定到全局对象。在浏览器的JavaScript里,该全局对象是window对象。

var name = "Alice";
function getName (name) {
 return this.name;
}
alert(getName()); // 输出:Alice
var name = "Alice";
var obj = {
 name: 'Bruce',
 getName: function(name) {
  return this.name;
 }
};
var getName = obj.getName();
alert(getName()); // 输出:Alice

以上两个实例中,this都被绑定到了全局对象。

var firstname = "A";
var lastname = "B";
var person = {
 firstname : "Alice",
 lastname : "Bruce",
 setName : function(firstname, lastname) {
  var setFirstName = function(firstname) {
   this.firstname = firstname;
  };
  var setLastName = function(lastname) {
   this.lastname = lastname;
  };
  setFirstName(firstname);
  setLastName(lastname);
 }
};
person.setName("Cindy", "David");
alert(firstname);//Cindy
alert(lastname);//David
alert(person.firstname);//Alice
alert(person.lastname);//Bruce

问题:在函数内部定义的函数,this也可能会指向全局,而希望的是内部函数的this绑定到外部函数对应的对象上。

原因:内部函数永远不可能直接访问外部函数中的this变量。

解决:在外部函数体中,要进入内部函数时,将this保存到一个变量中,再运用该变量。

var firstname = "A";
var lastname = "B";
var person = {
 firstname: "Alice",
 lastname: "Bruce",
 setName: function(firstname, lastname) {
  var that = this;
  var setFirstName = function(firstname) {
   that.firstname= firstname;
  };
  var setLastName = function(lastname) {
   that.lastname= lastname;
  };
  setFirstName(firstname);
  setLastName(lastname);
 }
};
person.setName("Cindy", "David");
alert(firstname);//A
alert(lastname);//B
alert(person.firstname);//Cindy
alert(person.lastname);//David

(2)作为对象方法调用

当函数作为对象方法调用时,this会被绑定到当前对象。

var firstname = "A";
var lastname = "B";
var person = {
 firstname : "Alice",
 lastname : "Bruce",
 setName : function(firstname, lastname) {
  this.firstname = this.firstname + firstname;
  this.lastname = this.lastname + lastname;
 }
};
person.setName("Cindy", "David");
alert(firstname);//A
alert(lastname);//B
alert(person.firstname);//AliceCindy
alert(person.lastname);//BruceDavid

this被绑定到了当前对象,即person对象。

(3)作为构造函数调用

JavaScript中没有类,但可以从构造器中创建对象,同时也提供了new运算符,使得构造器看起来更像一个类。

利用构造函数创建新对象时,可以将this来指向新创建的对象,避免函数中的this指向全局。

var name = "Alice";
function Person(name) {
 this.name = name;
}
var person = new Person("Bruce");
alert(name);//Alice
alert(person.name);//Bruce

利用构造函数创建新对象person,this指向了person。

用new调用构造器时。还要注意一个问题,若构造器显式返回了一个object类型的对象,构造器返回的结果将是这个对象,而不是this。

function Person() {
 this.name = "Alice"
 return {
  name: "Bruce"
 }
}
var person = new Person();
alert(person.name);//Bruce

(4)call()和apply()调用

call()apply()切换函数执行的上下文环境,即this绑定的对象;this指向的是apply()call()中的第一个参数。

function Person(name) {
 this.name = name;
 this.setName = function(name) {
  this.name = name;
 }
}
var person1 = new Person("Alice");
var person2 = {"name": "Bruce"};
alert("person1: " + person1.name); // person1: Alice
person1.setName("David");
alert("person1: " + person1.name); // person1: David
alert("person2: " + person2.name); // person2: Bruce
person1.setName.apply(person2, ["Cindy"]);
alert("person2: " + person2.name); // person2: Cindy

apply()将person1的方法应用到person2上,this也被绑定到person2上。

3、this优先级

(1)函数是否在new中调用,是的话this绑定到新创建的对象。

(2)函数是否通过call、apply调用,是的话this绑定到指定对象。

(3)函数是否在某个上下文对象中调用,是的话this绑定到该上下文对象。

(4)若都不是,使用默认绑定,若在严格模式下,绑定到undefined,否则绑定到全局对象。

4、this丢失的问题

eg1:

var person = {
 name: "Alice",
 getName: function() {
  return this.name;
 }
};
alert(person.getName()); // Alice
var getName = person.getName;
alert(getName()); // undefined

当调用person.getName()时,getName()方法是作为person对象的属性被调用的,因此this指向person对象;

当用另一个变量getName来引用person.getName,并调用getName()时,是作为普通函数被调用,因此this指向全局window。

eg2:

<div id="div">正确的方式</div>
<script>
 var getId = function(id) {
  return document.getElementById(id);
 };
 alert(getId('div').innerText);
</script>
<div id="div">错误的方式</div>
<script>
 var getId = document.getElementById;
 alert(getId('div').innerText); // 抛出异常
</script>

问题:第一段调用正常,但第二段调用会抛出异常。

原因:许多引擎的document.getElementById()方法的内部实现中需要用到this,this本来期望指向的是document,当第一段代码在getElementById()方法作为document对象的属性被调用时,方法内部的this确实是指向document的,而第二段代码中,用getId来引用document.getElementById之后,再调用getId,此时就成了普通函数调用,函数内部的this指向了window,而不是原来的document。

解决:利用apply把document当作this传入getId函数,修正this。

<div id="div">修正的方式</div>
<script>
 document.getElementById = (function(func) {
  return function() {
   return func.apply(document, arguments);
  };
 })(document.getElementById);
 var getId = document.getElementById;
 alert(getId('div').innerText); // 抛出异常
</script>

希望本文所述对大家JavaScript程序设计有所帮助。

Javascript 相关文章推荐
JavaScript RegExp方法获取地址栏参数(面向对象)
Mar 10 Javascript
jQuery使用一个按钮控制图片的伸缩实现思路
Apr 19 Javascript
什么是cookie?js手动创建和存储cookie
May 27 Javascript
node.js中的Socket.IO使用实例
Nov 04 Javascript
jquery实现可点击伸缩与展开的菜单效果代码
Aug 31 Javascript
全面了解addEventListener和on的区别
Jul 14 Javascript
JS判断输入的字符串是否是数字的方法(正则表达式)
Nov 29 Javascript
微信小程序 tabs选项卡效果的实现
Jan 05 Javascript
详解小程序中h5页面onShow实现及跨页面通信方案
May 30 Javascript
vue 解决异步数据更新问题
Oct 29 Javascript
JavaScript 俄罗斯方块游戏实现方法与代码解释
Apr 08 Javascript
Vue实现可移动水平时间轴
Jun 29 Javascript
利用js将ajax获取到的后台数据动态加载至网页中的方法
Aug 08 #Javascript
微信小程序开发背景图显示功能
Aug 08 #Javascript
JavaScript实现的DOM绘制柱状图效果示例
Aug 08 #Javascript
基于Bootstrap下拉框插件bootstrap-select使用方法详解
Aug 07 #Javascript
快速解决处理后台返回json数据格式的问题
Aug 07 #Javascript
详解如何在vue-cli中使用vuex
Aug 07 #Javascript
React styled-components设置组件属性的方法
Aug 07 #Javascript
You might like
PHP.MVC的模板标签系统(三)
2006/09/05 PHP
ZF等常用php框架中存在的问题
2008/01/10 PHP
php去除换行符的方法小结(PHP_EOL变量的使用)
2013/02/16 PHP
Yii2.0实现生成二维码功能实例
2017/10/24 PHP
JS处理VBArray的函数使用说明
2008/05/11 Javascript
基于jquery可配置循环左右滚动例子
2011/09/09 Javascript
百度地图api如何使用
2015/08/03 Javascript
深入剖析JavaScript编程中的对象概念
2015/10/21 Javascript
javascript常用经典算法实例详解
2015/11/25 Javascript
jQuery 3.0十大新特性最终版发布
2016/07/14 Javascript
js判断所有表单项不为空则提交表单的实现方法
2016/09/09 Javascript
jquery 删除节点 添加节点 找兄弟节点的简单实现
2016/12/07 Javascript
jQuery.form.js的使用详解
2017/06/14 jQuery
Windows下Node.js安装及环境配置方法
2017/09/18 Javascript
AngularJS select加载数据选中默认值的方法
2018/02/28 Javascript
微信{"errcode":48001,"errmsg":"api unauthorized, hints: [ req_id: 1QoCla0699ns81 ]"}
2018/10/12 Javascript
如何将百度地图包装成Vue的组件的方法步骤
2019/02/12 Javascript
利用Python的Flask框架来构建一个简单的数字商品支付解决方案
2015/03/31 Python
Python编程实战之Oracle数据库操作示例
2017/06/21 Python
tensorflow 恢复指定层与不同层指定不同学习率的方法
2018/07/26 Python
Linux下多个Python版本安装教程
2018/08/15 Python
pyqt5 从本地选择图片 并显示在label上的实例
2019/06/13 Python
pyqt5 QProgressBar清空进度条的实例
2019/06/21 Python
python实现将文件夹内的每张图片批量分割成多张
2019/07/22 Python
浅析python中的del用法
2020/09/02 Python
Python eval函数原理及用法解析
2020/11/14 Python
matplotlib常见函数之plt.rcParams、matshow的使用(坐标轴设置)
2021/01/05 Python
工程造价自荐信
2013/10/09 职场文书
中英双版中文教师求职信
2013/10/27 职场文书
经典婚礼主持词
2014/03/13 职场文书
多媒体教室标语
2014/06/26 职场文书
2014年禁毒工作总结
2014/11/24 职场文书
道歉情书大全
2015/05/12 职场文书
幼儿园教学反思范文
2016/03/02 职场文书
Python使用PyYAML库读写yaml文件的方法
2022/04/06 Python
python基础之//、/与%的区别详解
2022/06/10 Python