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 相关文章推荐
再次更新!MSClass (Class Of Marquee Scroll通用不间断滚动JS封装类 Ver 1.6)
Feb 05 Javascript
dtree 网页树状菜单及传递对象集合到js内,动态生成节点
Apr 14 Javascript
jQuery中html()方法用法实例
Dec 25 Javascript
js+css实现导航效果实例
Feb 10 Javascript
Js实现自定义右键行为
Mar 26 Javascript
window.onload与$(document).ready()的区别分析
May 30 Javascript
javascript日期验证之输入日期大于等于当前日期
Dec 13 Javascript
JS模仿手机端九宫格登录功能实现代码
Apr 28 Javascript
不间断循环滚动效果的实例代码(必看篇)
Oct 08 Javascript
video.js使用改变ui过程
Mar 05 Javascript
javascript实现QQ空间相册展示源码
Dec 12 Javascript
使用vue重构资讯页面的实例代码解析
Nov 26 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
How do I change MySQL timezone?
2008/03/26 PHP
Zend Framework教程之视图组件Zend_View用法详解
2016/03/05 PHP
微信随机生成红包金额算法php版
2016/07/21 PHP
mysql查找删除重复数据并只保留一条实例详解
2016/09/24 PHP
jquery滚动条插件jScrollPane的使用介绍
2013/11/08 Javascript
使用JS实现jQuery的addClass, removeClass, hasClass函数功能
2014/10/31 Javascript
使用pjax实现无刷新更改页面url
2015/02/05 Javascript
jqueryUI里拖拽排序示例分析
2015/02/26 Javascript
纯JS实现旋转图片3D展示效果
2015/04/12 Javascript
jquery实现的树形目录实例
2015/06/26 Javascript
Vue.js每天必学之内部响应式原理探究
2016/09/07 Javascript
jQuery模拟Marquee实现无缝滚动效果完整实例
2016/09/29 Javascript
详解js的六大数据类型
2016/12/27 Javascript
Jquery+Ajax+xml实现中国地区选择三级联动菜单效果(推荐)
2017/06/09 jQuery
详解vue-cli中的ESlint配置文件eslintrc.js
2017/09/25 Javascript
浅谈node模块与npm包管理工具
2018/01/03 Javascript
js中arguments对象的深入理解
2019/05/14 Javascript
JS轮播图的实现方法2
2020/08/25 Javascript
跟老齐学Python之玩转字符串(1)
2014/09/14 Python
python基于itchat实现微信群消息同步机器人
2017/02/27 Python
浅析Python中的赋值和深浅拷贝
2017/08/15 Python
pandas对指定列进行填充的方法
2018/04/11 Python
Python3中正则模块re.compile、re.match及re.search函数用法详解
2018/06/11 Python
python中数组和矩阵乘法及使用总结(推荐)
2019/05/18 Python
Python使用scipy模块实现一维卷积运算示例
2019/09/05 Python
python 使用while写猜年龄小游戏过程解析
2019/10/07 Python
使用Filters滤镜弥补CSS3的跨浏览器问题以及兼容低版本IE
2013/01/23 HTML / CSS
用HTML5制作一个简单的桌球游戏的教程
2015/05/12 HTML / CSS
HTML5新标签兼容——&gt; 的两种方法
2018/09/12 HTML / CSS
伦敦剧院门票:From The Box Office
2018/06/30 全球购物
土木工程应届生求职信
2013/10/31 职场文书
报关员个人职业生涯规划书
2014/03/12 职场文书
勤奋学习演讲稿
2014/05/10 职场文书
安全员岗位职责范本
2015/04/11 职场文书
实习证明模板
2015/06/16 职场文书
Win10/Win11 任务栏替换成经典样式
2022/04/19 数码科技