JavaScript中arguments和this对象用法分析

本文实例讲述了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常用函数技巧汇总》、《JavaScript错误与调试技巧总结》、《JavaScript数据结构与算法技巧总结》、《JavaScript遍历算法与技巧总结》及《JavaScript数学运算用法总结》

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

(0)

相关推荐

  • JS函数内部属性之arguments和this实例解析

    在函数内部,有两个特殊的对象:arguments和this. 1.arguments arguments是一个类数组对象.包含着传入函数中的所有参数.但这个对象还有一个名叫callee的属性,该属性是一个指针,指向拥有这个arguments对象的函数. 经典案例:阶乘函数 function factorial(num){ if(num <= 1){ return 1; }else{ return num * factorial(num-1); } } 定义阶乘函数一般都要用到递归算法,如上所示,

  • js中this的指向问题归纳总结

    前言 js中this指向问题是个老生常谈的问题了,下面这篇文章再来给大家介绍下,大家可以看看,更深入的了解了解,下面话不多说了,来一起看看详细的介绍吧 this this:上下文,会根据执行环境变化而发生指向的改变. 1.单独的this,指向的是window这个对象 alert(this); // this -> window 2.全局函数中的this function demo() { alert(this); // this -> window } demo(); 在严格模式下,this是

  • JavaScript中this用法学习笔记

    JavaScript这门语言中,最令人迷惑的地方有三个,闭包.this.原型.针对大多数人,可以利用词法作用域等避开this的坑,但是我们不能一直生活在舒适区,要敢于打破砂锅问到底,对我们来说也是一种提升. 一.一般对this关键字的误解: 1.this指向函数自身 2.this指向函数词法作用域 我们可以看以下一段代码: function test() { test.a = 1; this.a = 2; console.log(test.a); console.log(this.a); con

  • 解决vue.js this.$router.push无效的问题

    如下所示: login() { if(this.email.length > 0 && this.password.length >0) { this.$http.post('/api/login', { user: this.email, password: this.password }) .then(res => { let userPwd = res.data if(this.password == userPwd) { this.$router.push(&qu

  • JavaScript this绑定过程深入详解

    本文实例形式详细分析了JavaScript this绑定过程.分享给大家供大家参考,具体如下: 在理解this 的绑定过程之前,首先要理解调用位置:调用位置就是函数在代码中被调用的位置(而不是声明的位置).只有仔细分析调用位置才能回答这个问题:这个this 到底引用的是什么?通常来说,寻找调用位置就是寻找"函数被调用的位置",但是做起来并没有这么简单,因为某些编程模式可能会隐藏真正的调用位置.最重要的是要分析调用栈(就是为了到达当前执行位置所调用的所有函数).我们关心的调用位置就在当前

  • JavaScript中this关键字用法实例分析

    本文实例总结了JavaScript中this关键字用法.分享给大家供大家参考,具体如下: 例1: function a(){ var user = "yao"; console.log(this.user);//undefined console.log(this);//window } a(); 等价于: function a(){ var user = "yao"; console.log(this.user);//undefined console.log(t

  • JavaScript中arguments和this对象用法分析

    本文实例讲述了JavaScript中arguments和this对象用法.分享给大家供大家参考,具体如下: 在函数内部有两个特殊的对象 : arguments和this. 1.arguments对象 js函数不介意定义多少参数,也不在乎传递进来多少参数,也就是说,即使定义的函数只接收2个参数,在调用时候也未必传递2个参数,因为js的函数参数在内部使用一个数组表示的,在函数体内可以通过arguments对象访问此参数数组.因此,js函数可以不显式地使用命名参数. 当函数被调用时,传入的参数将保存在

  • Javascript中函数名.length属性用法分析(对比arguments.length)

    本文实例分析了Javascript中函数名.length属性用法.分享给大家供大家参考,具体如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"&g

  • Javascript中数组sort和reverse用法分析

    本文实例讲述了Javascript中数组sort和reverse用法.分享给大家供大家参考.具体分析如下: sort() 方法用于对数组的元素进行排序. reverse()将数组中的元素逆序 首先我们来试试以下这段代码: 复制代码 代码如下: var values = [1, 0, 5, 15, 10]; values.reverse(); console.log(values); 输出结果会是什么呢: [ 10, 15, 5, 0, 1 ] reverse()也就是很简单的把数组倒过来而已,那

  • Javascript中arguments用法实例分析

    本文实例讲述了Javascript中arguments用法.分享给大家供大家参考.具体分析如下: 先来看如下示例: function add(n1,n2){ return n1+n2; } function add(n1,n2,n3) { return n1+n2+n3; } alert(add(1,2)); //NaN,js中调用方法采用就近原则: //而由于该方法没有传入n3,所以结果是NaN js中没有方法重载,怎么解决上面这个问题? //arguments function f1(){

  • javascript中call,apply,callee,caller用法实例分析

    本文实例讲述了javascript中call,apply,callee,caller用法.分享给大家供大家参考,具体如下: 实践一:call,apply 用来让一个对象去调用本不属于自己的方法,两者都可以传递参数,call的参数是列表形式,apply的参数是数组形式 var person = { "name":"Tom", "say":function(){ console.log("person say"); }, &quo

  • javascript中的闭包概念与用法实践分析

    本文实例讲述了javascript中的闭包概念与用法.分享给大家供大家参考,具体如下: 闭包的概念:闭包是指有权访问另一个函数作用域中的变量的函数 (引自<javascript高级程序设计第三版>178页).闭包的优点是不会产生全局变量,避免变量污染问题,但是闭包也有一个缺点就是闭包携带包含它的函数作用域会比其它函数占用更多的内存,过度使用会导致内存占用过多. wiki上关于闭包的概念: In programming languages, closures (also lexical clos

  • javascript中innerText和innerHTML属性用法实例分析

    本文实例讲述了javascript中innerText和innerHTML属性用法.分享给大家供大家参考.具体分析如下: 几乎所有DOM元素都有innerText,innertHTML属性(注意大小写),分别是元素标签内 的文本表示形式和HTML源代码,这两个属性是可读可写的 innerHTML也可以取代createElement,属于简单,粗放型,后果自负的创建 <html xmlns="http://www.w3.org/1999/xhtml"> <head>

  • 详解JavaScript中Arguments对象用途

    目录 前言 Arguments 的基本概念 Arguments 的作用 获取实参和形参的个数 修改实参值 改变实参的个数 检测参数合法性 函数的参数个数不确定时,用于访问调用函数的实参值 遍历或访问实参的值 总结 在实际开发中,Arguments 对象非常有用.灵活使用 Arguments 对象,可以提升使用函数的灵活性,增强函数在抽象编程中的适应能力和纠错能力. JavaScript 中 Arguments 对象的用途总结. 前言 相信我们很多人在代码开发的过程中都使用到过一个特殊的对象 --

  • javascript中2个感叹号的用法实例详解

    在javascript代码中经常会见到!!的情况,本文即以实例形式较为深入的分析javascript中2个感叹号的用法.分享给大家供大家参考之用.具体分析如下: javascript中的!!是逻辑"非非",即是在逻辑"非"的基础上再"非"一次.通过!或!!可以将很多类型转换成bool类型,再做其它判断. 一.应用场景:判断一个对象是否存在 假设有这样一个json对象: { color: "#E3E3E3", "fon

  • JavaScript中set与get方法用法示例

    本文实例分析了JavaScript中set与get方法用法.分享给大家供大家参考,具体如下: 1.get与set是方法,因为是方法,所以可以进行判断. 2.get是得到 一般是要返回的   set 是设置 不用返回 3.如果调用对象内部的属性约定的命名方式是_age 然后就是几个例子来简单说明一下: var person ={ _name : "chen", age:21, set name(name) {this._name = name;},get name() {return t

随机推荐