javascript忍者秘籍-第四章 理解函数调用
栏目: JavaScript · 发布时间: 5年前
内容简介:调用函数时,隐式的函数参数 this 和 arguments 会被静默的传递给函数
调用函数时,隐式的函数参数 this 和 arguments 会被静默的传递给函数
this
表示调用函数的上下文对象
arguments
表示函数调用过程中传递的所有参数。通过 arguments 参数可以访问 函数调用过程中传递的实际参数。
函数调用的方式 对 函数的隐式参数有很大的影响
4.1 隐式的函数参数
arguments 和 this
arguments 参数
arguments 参数是 传递给函数的所有参数的集合
//arguments 是一个类数组对象 //length 属性 表示实参的确切个数 arguments[2] function whatever(a,b,c){ arguments.length //实际传入的参数个数 } //arguments 对象是函数参数的别名 所以改变了 arguments 对象的值,同时也会影响到对应的函数参数 复制代码
在严格模式下,不能改变 arguments[index] 的值。
"use strict" function infiltrate(person){ arguments[0] = 'ninja'; //严格模式下 报错 } 复制代码
this 参数:函数上下文
调用函数时,除了显示提供的参数外,this 参数也会默认的传递给函数。 => 函数上下文
this
参数的指向 不仅是由 定义函数的方式 和 位置决定的,还受到 函数调用方式的影响。
4.2 函数调用
函数调用的4种方式
//1.作为一个函数直接调用 function skulk(name){} shulk('Hattori'); //2.作为一个方法,关联到对象上调用 var ninja = { shulk: function(){} }; ninja.shulk('Hattori'); //3.作为构造函数调用 function Ninja(name){} ninja = new Ninja('Hattori'); //4.通过apply 和 call调用 skulk.apply(ninja,['Hattori']); skulk.call(ninja,'Hattori'); 复制代码
作为函数直接调用
函数上下文 this 有两种可能性:
1.在非严格模式下,this是全局上下文(window对象)
2.在严格模式下,this是undefined
//函数定义 作为函数调用 function ninja(){}; ninja(); //函数表达式 作为函数调用 var samurai = function(){}; samurai(); (function(){})(); //立即调用的函数表达式,作为函数被调用 复制代码
//非严格模式下的函数调用 function ninja(){ return this; //window } //严格模式下的函数调用 function ninja(){ "use strict"; return this; //undefined } 复制代码
作为方法被调用
当一个函数被赋值给一个对象的属性,并且通过对象属性引用的方式调用函数,函数会被作为 对象的方法 调用
当函数作为某个对象的方法被调用时,该对象会成为函数的上下文,并且在函数内部可以通过参数(this)访问到
var ninja = {}; ninja.skulk = function(){}; ninja.skulk(); 复制代码
function whatsMyContext(){ return this; } whatsMyContext(); //当作函数调用 this == window var getMyThis = whatsMyContext(); getMyThis(); //创建原函数的引用 当作函数调用 this == window var ninja1 = { getMyThis: whatsMyContext } ninja1.getMyThis == ninja1 //this 返回函数上下文 == 该方法所在的对象 复制代码
作为构造函数调用
//通过构造函数的方式调用,需要在函数调用之前使用关键字new new MyObject(); function Ninja(){ this.skulk = function(){ return this; } } var ninja1 = new Ninja(); ninja1.skulk() === ninjia1 //true 复制代码
当用 new
调用构造函数时,触发以下几个动作
- 创建一个新的空对象
- 该对象作为 this 参数传递给构造函数,从而成为构造函数的函数上下文
- 新构造的对象作为 new 运算符的返回值
构造函数的目的:创建一个新对象,并进行初始化设置,然后将其作为构造函数的返回值。
构造函数的返回值
function Ninja(){ this.skulk = function(){ return true; }; return 1; //返回一个基本数据类型 } Ninja() //返回值为1 //返回值1被忽略了,一个新的初始化对象返回 var ninja = new Ninja(); typeof ninja === "object" //true typeof ninja.skulk === "function" //true var puppet = {rules:false}; function Ninja(){ this.skulk = function(){ return true; } return puppet; //返回一个新对象 } 复制代码
- 如果构造函数返回了一个对象,那么该对象作为整个表达式的值返回,传入构造函数的 this 被丢弃
- 如果构造函数返回了 非对象类型,则忽略返回值,返回新创建的对象
apply/call方法调用
不同类型函数调用之间的区别:最终作为 函数上下文(this) 传递给 执行函数的对象不同。
直接函数:window undefined
方法:方法所在的对象
构造函数:新创建的对象实例
==每个函数都存在这两个方法==
改变函数的上下文,显示指定函数的上下文对象
事件回调函数的上下文 是 触发事件的对象 => 调用的位置
function Button(){ this.clicked = false; this.click = function(){ this.clicked = true; assert(button.clicked,"The button has been clicked"); } } var button = new Button(); var elem = document.getElementById("test"); elem.addEventListener("click",button.click); 复制代码
//apply和call方法来设置函数上下文 function juggle(){ var result = 0; for (var n=0;n<arguments.length;n++){ result += arguments[n]; } this.result = result; } var ninja1 = {}; var ninja2 = {}; juggle.apply(ninja1,[1,2,3,4]); juggle.call(ninja2,5,6,7,8); ninja1.result == 10 ninja2.result == 26 复制代码
强制指定回调函数的函数上下文
forEach 遍历函数将每个元素传给回调函数,将当前元素作为回调函数的上下文
function forEach(list,callback){ for(var n=0;n<list.length;n++){ callback.call(list[n],n); //当前元素作为函数上下文,循环索引作为回调函数的参数 } } var weapons = [{type:'abc'},{type:'bcd'},{type:'efg'}]; forEach(weapons,function(index){ this === weapons[index] //list[n] }) 复制代码
4.3 解决函数上下文的问题
上下文不一致可以考虑以下几种办法:
1.call 和 apply 显示指定 this 上下文
2.箭头函数
3.bind 方法
箭头函数绕过函数上下文
箭头函数没有单独的this值.
箭头函数的 this 与声明所在的上下文相同
//箭头函数自身不含上下文,从定义时所在的函数继承上下文 //调用箭头函数时,不会隐式传入this参数,而是从定义时的函数继承上下文 function Button(){ this.clicked = false; this.click = () => { this.clicked = true; button.clicked == true; //button == this } } var button = new Button(); var elem = document.getElementById("test"); elem.addEventListener("click",button.click); 复制代码
箭头函数与对象字面量
只有一个按钮,不需要使用构造函数。直接使用对象字面量。单例模式
//箭头函数与对象字面量 //对象字面量在全局代码中定义,所以this与全局代码的this相同 var button = { clicked: false, click: () => { //箭头函数在创建时确定了this的指向 this.clicked = true; button.clicked; //false this === window; //true window.clicked; //true } } var elem = document.getElementById("test"); elem.addEventListener("click",button.click); 复制代码
bind 方法
函数可以访问 bind 方法创建新函数,创建的的新函数与 **原始函数的函数体 **相同,新函数被绑定到指定的对象上,this 被设置为对象本身
调用 bind 方法不会修改 原始函数,而是创建了一个全新的函数
var button = { clicked : false, click : function(){ this.clicked = true; button.clicked; //true } } var elem = document.getElementById("test"); elem.addEventListener("click",button.click.bind(button)); //bind方法会新创建一个全新的函数 var boundFunction = button.click.bind(button); boundFunction != button.click //true 复制代码
4.4 总结
-
当调用函数时,除了传入在函数定义中显式声明的参数之外,同时还传入两个隐式参数:arguments 与 this。
-
arguments 参数是传入函数的所有参数的集合。具有 length 属性,表示传入参数的个数,通过 arguments 参数还可获取那些与函数形参不匹配的参数。 在非严格模式下,arguments 对象是函数参数的别名,修改 arguments 对象 会修改函数实参,可以通过严格模式避免修改函数实参。
-
this 表示函数上下文,即与函数调用相关联的对象。函数的定义方式和调用 方式决定了 this 的取值。
-
-
函数的调用方式有 4 种。
-
作为函数调用:skulk()。
-
作为方法调用:ninja.skulk()。
-
作为构造函数调用:new Ninja()。
-
通过 apply 与 call 方法调用:skulk.apply(ninja)或 skulk.call(ninja)。
-
-
函数的调用方式影响 this 的取值。
-
如果作为函数调用,在非严格模式下,this 指向全局 window 对象;在严格 模式下,this 指向 undefined。
-
作为方法调用,this 通常指向调用的对像。
-
作为构造函数调用,this 指向新创建的对象。
-
通过 call 或 apply 调用,this 指向 call 或 apply 的第一个参数。
-
-
箭头函数没有单独的 this 值,this 在箭头函数创建时确定。
-
所有函数均可使用 bind 方法,创建新函数,并绑定到 bind 方法传入的参数上。被绑定的函数与原始函数具有一致的行为。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。