zoukankan      html  css  js  c++  java
  • 第4章 函数进阶:理解函数调用

    1. 隐式函数参数

    arguments

    • 所有参数集合
    function foo() {
        console.log(arguments);
        console.log(arguments[0]);
        console.log(arguments.length);
    }
    
    foo(1, 2, 3);
    // Arguments(3) [1, 2, 3, callee: ƒ, Symbol(Symbol.iterator): ƒ]
    // 1
    // 3
    

    arguments不是数组,无法调用数组方法。

    大多数情况下可以使用剩余参数(...)来代替arguments。

    • arguments的值和参数的值指向同一个数据,修改后会相互影响,严格模式下不会影响
    // 非严格模式下
    function setInfo(name, age) {
        console.log(name + " " + age);  // Wango 24
        arguments[0] = "Lily";
        console.log(name + " " + age);  // Lily 24
    }
    
    setInfo("Wango", 24);
    
    // 严格模式下
    function setInfo(name, age) {
        "use strict";
        console.log(name + " " + age);  // Wango 24
        arguments[0] = "Lily";
        console.log(name + " " + age);  // Wango 24
    }
    
    setInfo("Wango", 24);
    

    this

    • 代表函数调用相关联的对象,通常被称为函数上下文
    • this的指向与函数的调用方式相关

    2. 函数调用

    2.1 作为函数直接调用

    // 函数定义作为函数被调用
    function foo() {};
    foo();
    
    // 函数表达式作为函数被调用
    var fn = function() {};
    fn();
    
    // 作为立即调用函数被调用
    (function() {})();
    

    在作为函数直接调用时,函数内部this在非严格模式下指向全局上下文(window/global对象),在严格模式下为undefined。

    // 非严格模式下
    (function() {
        console.log(this);
        // Window {window: Window, self: Window, document: document, name: "", location: Location, …} 
    })();
    
    // 严格模式下
    (function() {
        "use strict";
        console.log(this);      // undefined
    })();
    

    2.2 作为对象方法调用

    var tools = {};
    // 函数被赋值给一个对象的属性
    tools.sort = function() {};
    tools.sort();
    
    • 作为方法调用时,this指向调用此方法的对象
    var tools = {};
    tools.sort = function() {
        console.log(this === tools); // true
    };
    tools.sort();
    

    2.3 作为构造函数调用

    function Student(){
        this.study = function() {
            return this;
        };
    }
    
    var stu1 = new Student();
    var stu2 = new Student();
    
    console.log(stu1.study() === stu1);     // true
    console.log(stu2.study() === stu2);     // true
    
    • 调用构造函数时的操作:
      • 使用关键字new来调用函数,从而创建一个新的空对象
      • 新的空对象被设置为该函数的上下文(this)
      • 为该对象增加函数中定义的方法和属性
      • 新构造的对象作为new操作符的返回值返回

    使用new操作符时,若这个构造函数本身有返回值,则分为两种情况:

    若返回值是原始类型值(数字、字符串、布尔值等),则new操作符返回新创建的对象。

    若返回值不是原始类型值(对象、函数、数组等),则new操作符返回构造函数的返回值。

    function Obj1() {
        this.value = 200;
        return 1;       // 构造函数返回原始类型值
    }
    
    var o1 = new Obj1();        // new操作符返回新创建的对象
    console.log(o1.value);      // 200
    
    function Obj2() {
        this.value = 200;
        return {        // 构造函数返回一个对象
            value: 100,
        };
    }
    
    var o2 = new Obj2();        // new操作符返回构造函数返回的对象
    console.log(o2.value);      // 100
    
    
    

    2.4 通过apply或call方法调用

    • 为什么使用apply或call
    function Button() {
        this.clicked = false;
        this.click = function() {
            this.clicked = true;    // this指向elem
            /** 绑定事件时,浏览器的事件处理系统把this指向了触发事件
            * 的元素,在这里就是elem,所以this.clicked = elem.clicked
            * 将属性设置到错误的对象上了
            */
            console.log(this.clicked);      // true
            console.log(btn.clicked);       // false
            console.log(elem.clicked);      // true
        }
    }
    
    var btn = new Button();
    var elem = document.getElementById("test");
    elem.addEventListener("click", btn.click);
    
    • 使用apply或call方法显式地指明this指向
    function sum(...nums) {
        var result = 0;
        for (var i = 0; i < nums.length; i++){
            result += nums[i];
        }
        this.result = result;
    }
    
    var obj01 = {};
    var obj02 = {};
    
    // 用apply或call方法调用函数,并指明this指向
    // sum函数中this指向第一个参数传入的对象
    sum.apply(obj01, [1, 2, 3, 4, 5]);  
    sum.call(obj02, 6, 7, 8, 9, 0);
    
    console.log(obj01.result);      // 15
    console.log(obj02.result);      // 30
    
    // 直接调用函数,this指向默认上下文,这里为window
    sum(1, 2, 3, 4, 5);
    
    console.log(window.result);     // 15
    

    apply个call方法唯一的不同在于apply传递参数时使用数组,

    call方法直接以参数的形式传递

    • 强制指定回调函数的函数上下文
    function forEach(list, callback) {
        for (var i = 0; i < list.length; i++) {
            // 使用call方法指定回调函数中this的指向
            callback.call(list[i]);
        }
    }
    var pers = [
        {name: "Wango"},
        {name: "Lily"},
        {name: "Jack"},
    ];
    
    forEach(pers, function() {
        // 在这里thisu依次指向数组中的对象
        console.log(this.name);
    });
    // Wango
    // Lily
    // Jack
    

    3. 解决上下文问题

    3.1 用箭头函数绕过上下文

    • 箭头函数作为回调函数没有单独的this值,箭头函数的this与声明所在的上下文相同,即在函数创建时确定
    function Button() {
        this.clicked = false;
        // 这里使用箭头函数创建函数
        this.click = () => {
            this.clicked = true;            // this指向btn
            console.log(this.clicked);      // true
            console.log(btn.clicked);       // true
            console.log(elem.clicked);      // undefined
        }
    }
    
    var btn = new Button();
    var elem = document.getElementById("test");
    elem.addEventListener("click", btn.click);
    
    /**
    * 当对象使用new操作符构建时(如上),this指向new返回的对象
    * 但当对象是以字面量的形式定义时,当前的上下文为外部对象(window),
    * this也就指向的window
    */
    // 用字面量方式定义对象
    var btn = {
        clicked: false,
        // 同样以箭头函数创建函数
        click: () => {
            this.clicked = true;            // this指向btn的上下文(window)
            console.log(this.clicked);      // true
            console.log(btn.clicked);       // false
            console.log(elem.clicked);      // undefined
            console.log(window.clicked);    // true
        }
    }
    
    var elem = document.getElementById("test");
    elem.addEventListener("click", btn.click);
    

    3.2 使用bind方法

    • 使用bind方法可以将函数绑定到指定对象上
    function Button() {
        this.clicked = false;
        this.click = function() {
            this.clicked = true;        // this指向btn
            console.log(this.clicked);  // true
            console.log(btn.clicked);   // true
            console.log(elem.clicked);  // undefined
        }
    }
    
    var btn = new Button();
    var elem = document.getElementById("test");
    // 使用bind方法指定函数绑定的对象
    elem.addEventListener("click", btn.click.bind(btn));
    

    调用bind方法并不会修改原始函数,而是创建了一个全新的函数

    这个函数与原始函数行为一致,函数体一致

  • 相关阅读:
    TCP心跳包
    interesting site
    TestNG环境搭建以及框架初识
    lambda表达式
    subprocess学习
    使用psutil模块获取电脑运行信息
    使用ssh和putty操控远程的linux server
    ubuntu系统源的更新
    将python的程序包装成windows下的service
    使用python进行re拆分网页内容
  • 原文地址:https://www.cnblogs.com/hycstar/p/14002540.html
Copyright © 2011-2022 走看看