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 相关文章推荐
让Firefox支持event对象实现代码
Nov 07 Javascript
javascript中获取下个月一号,是星期几
Jun 01 Javascript
jQuery简单实现日历的方法
May 04 Javascript
Vue 单文件中的数据传递示例
Mar 21 Javascript
Vue底层实现原理总结
Feb 17 Javascript
Angular 实现输入框中显示文章标签的实例代码
Nov 07 Javascript
layer.open 获取不到表单信息的解决方法
Sep 26 Javascript
mpvue微信小程序的接口请求fly全局拦截代码实例
Nov 13 Javascript
vue之延时刷新实例
Nov 14 Javascript
JS实现点餐自动选择框(案例分析)
Dec 10 Javascript
Vue自定义render统一项目组弹框功能
Jun 07 Javascript
javascript遍历对象的五种方式实例代码
Oct 24 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引用地址改变变量值的问题
2012/03/23 PHP
PHP数组无限分级数据的层级化处理代码
2012/12/29 PHP
PHP自动识别字符集并完成转码详解
2013/08/02 PHP
php中sql注入漏洞示例 sql注入漏洞修复
2014/01/24 PHP
php实现根据IP地址获取其所在省市的方法
2015/04/30 PHP
基于Asp.net与Javascript控制的日期控件
2010/05/22 Javascript
jquery表格内容筛选实现思路及代码
2013/04/16 Javascript
js通过更改按钮的显示样式实现按钮的滑动效果
2014/04/23 Javascript
深入探讨JavaScript、JQuery屏蔽网页鼠标右键菜单及禁止选择复制
2014/06/10 Javascript
jQuery+CSS3实现树叶飘落特效
2015/02/01 Javascript
JavaScript数据类型转换的注意事项
2016/07/31 Javascript
几种二级联动案例(jQuery\Array\Ajax php)
2016/08/13 Javascript
js Canvas绘制圆形时钟教程
2017/02/06 Javascript
Vue-cli proxyTable 解决开发环境的跨域问题详解
2017/05/18 Javascript
Vue2 轮播图slide组件实例代码
2018/05/31 Javascript
在Vue组件中获取全局的点击事件方法
2018/09/06 Javascript
微信小程序实现页面分享onShareAppMessage
2019/08/12 Javascript
浅谈vue中组件绑定事件时是否加.native
2019/11/09 Javascript
es6函数之箭头函数用法实例详解
2020/04/25 Javascript
利用Vue的v-for和v-bind实现列表颜色切换
2020/07/17 Javascript
echarts实现获取datazoom的起始值(包括x轴和y轴)
2020/07/20 Javascript
uniapp微信小程序实现一个页面多个倒计时
2020/11/01 Javascript
Python内置模块turtle绘图详解
2017/12/09 Python
详谈python在windows中的文件路径问题
2018/04/28 Python
Python爬虫框架Scrapy常用命令总结
2018/07/26 Python
Python绘制正余弦函数图像的方法
2018/08/28 Python
python解压TAR文件至指定文件夹的实例
2019/06/10 Python
Flask框架 CSRF 保护实现方法详解
2019/10/30 Python
Python 使用threading+Queue实现线程池示例
2019/12/21 Python
Python qrcode 生成一个二维码的实例详解
2020/02/12 Python
个人房屋转让协议书范本
2014/10/26 职场文书
2014年语文教研组工作总结
2014/12/06 职场文书
小学校本教研总结
2015/08/13 职场文书
Redis持久化与主从复制的实践
2021/04/27 Redis
不要在HTML中滥用div
2021/05/08 HTML / CSS
VUE解决跨域问题Access to XMLHttpRequest at
2022/05/06 Vue.js