javascript忍者秘籍-第四章 理解函数调用

栏目: JavaScript · 发布时间: 7年前

内容简介:调用函数时,隐式的函数参数 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 调用构造函数时,触发以下几个动作

  1. 创建一个新的空对象
  2. 该对象作为 this 参数传递给构造函数,从而成为构造函数的函数上下文
  3. 新构造的对象作为 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
复制代码
javascript忍者秘籍-第四章 理解函数调用

强制指定回调函数的函数上下文

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 方法传入的参数上。被绑定的函数与原始函数具有一致的行为。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Chinese Authoritarianism in the Information Age

Chinese Authoritarianism in the Information Age

Routledge / 2018-2-13 / GBP 115.00

This book examines information and public opinion control by the authoritarian state in response to popular access to information and upgraded political communication channels among the citizens in co......一起来看看 《Chinese Authoritarianism in the Information Age》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换