资讯专栏INFORMATION COLUMN

js函数调用模式和常用的几个方法

zhigoo / 3250人阅读

摘要:一函数调用的种模式方法调用模式当一个函数被保存为对象的一个属性时,我们称它为一个方法。二函数常用的三个方法在指定值和参数参数以数组或类数组对象的形式存在的情况下调用某个函数。当绑定函数被调用时,该参数会作为原函数运行时的指向。

一、函数调用的4种模式 (1) 方法调用模式

当一个函数被保存为对象的一个属性时,我们称它为一个方法。当一个方法被调用时,this 被绑定到该对象。如果调用表达式包含一个提取属性的动作(即包含一个.点表达式或[subscript]下标表达式),那么它就是被当做一个方法来调用。

var myObj = {
    value: 0,
    increment: function (inc) {
        this.value += typeof inc === "number" ? inc : 1;
    }
};

myObj.increment();
console.log(myObj.value); // 1
myObj.increment(2);
console.log(myObj.value); // 3
(2) 函数调用模式
var add = function (a,b) {
    return a + b;
};
var sum = add(3,4); // sum的值为7

以此模式调用函数时,this 被绑定到全局对象

延伸:调用内部函数时,如何把 this 绑定到外部函数的 this 变量上

// 承接上面代码

// 给 myObj 增加一个 double 方法
myObj.double = function() {
    var that = this; // 解决方法
    var helper = function () {
        console.log(this); // this指向全局对象,如果写成this.value = add(this.value, this.value); 就获取不到正确的结果了
        that.value = add(that.value, that.value);
    };
    helper(); // 以函数的形式调用 helper
};

myObj.double(); // 以方法的形式调用 double
console.log(myObj.value); // 6
(3) 构造器调用模式
var Quo = function (string) {
    this.status = string;
}
var myQuo = new Quo("confused"); // 构造一个 Quo 实例
console.log(myQuo.status); // "confused"

一个函数,如果创建的目的就是希望结合new前缀来调用,那它就被称为构造(器)函数,函数内部的this 指向新创建的实例

(4) apply、call调用模式

js 是一门函数式的面向对象编程语言,函数也是一个对象,所以函数可以拥有自己的方法,apply、call就是其中的两种方法。

此种调用模式允许我们可以显式地设置 this 的指向,具体使用见下文。

二、函数常用的三个方法 1. fun.apply(thisArg[, argsArray])

在指定 this 值和参数(参数以数组类数组对象的形式存在)的情况下调用某个函数。
thisArg:在 fun 函数运行时指定的 this 值,如果这个函数处于非严格模式下,则指定为 null 或 undefined 时会自动指向全局对象(浏览器中就是window对象)
argsArray:一个数组或者类数组对象,其中的数组元素将作为多带带的参数传给 fun 函数。如果该参数的值为null 或 undefined,则表示不需要传入任何参数。也可以使用 arguments 对象作为 argsArray 参数,用arguments把所有的参数传递给被调用对象。

/* 求一个数组中的最大最小值 */
var numbers = [5, 6, 2, 3, 7];

/* simple loop based algorithm */
max = -Infinity, min = +Infinity;

for (var i = 0; i < numbers.length; i++) {
  if (numbers[i] > max)
    max = numbers[i];
  if (numbers[i] < min) 
    min = numbers[i];
}

/* vs. using Math.min/Math.max apply */
var max = Math.max.apply(null, numbers); /* This about equal to Math.max(numbers[0], ...) or Math.max(5, 6, ..) */
var min = Math.min.apply(null, numbers);

从上面的例子可以看到:本来需要写成遍历数组变量的任务,apply使用内建的函数就完成了。据此,可以简化某些对数组的操作

var arr1 = [1,2,3];
var arr2 = [4,5,6];

/* 如果我们要把 arr2 展开,然后一个一个追加到 arr1 中去,最后让 arr1=[1,2,3,4,5,6]
 * arr1.push(arr2)是不行的,因为这样做会得到[1,2,3,[4,5,6]] 
 * 可以循环arr2,然后一个一个的push,但是这样比较麻烦,使用apply,就so easy了
 */
Array.prototype.push.apply(arr1,arr2); 
console.log(arr1); // [1,2,3,4,5,6]

/* 也可以用arr1.concat(arr2),但是concat方法返回的是一个新数组,并不改变arr1本身 */
2. fun.call(thisArg[, arg1[, arg2[, ...]]])

该方法的作用和 apply() 方法类似,只有一个区别,就是 call() 方法接受的是一个参数列表,而apply()方法接受的是一个包含多个参数的数组。

Math.max.apply(null, [1,2,3,4]);
Math.max.call(null, 1, 2, 3, 4);

/* eg. 使用call方法调用父构造函数 */
function Animal(name){      
    this.name = name;      
    this.showName = function(){      
        console.log(this.name);      
    }      
}      
    
function Cat(name){    
    Animal.call(this, name); // 此行代码中的this指向Cat的实例   
}      
    
var cat = new Cat("Black Cat");     
cat.showName(); // "Black Cat"
3. fun.bind(thisArg[, arg1[, arg2[, ...]]])

当在函数fun上调用bind( )方法并传入一个对象thisArg作为参数,这个方法将返回一个新函数。调用新的函数将会把原始的函数fun当做thisArg的方法来调用。
thisArg:当绑定函数被调用时,该参数会作为原函数运行时的 this 指向。当使用new 操作符调用绑定函数时,该参数无效
arg1, arg2, ...:当绑定函数被调用时,这些参数加上绑定函数本身的参数会按照顺序作为原函数运行时的参数

// eg.1
var sum = function (x,y) { return x + y; };
var succ = sum.bind(null, 1);
succ(2); // => 3: x绑定到1,并传入2作为实参y

// eg.2
function f(y,z) { return this.x + y + z; };
var g = f.bind({x:1}, 2); // 绑定this和y
g(3); // =>6: this.x绑定到1,y绑定到2,z绑定到3

// eg.3 创建绑定函数
this.x = 9; 
var module = {
  x: 81,
  getX: function() { return this.x; }
};

module.getX(); // 81

var retrieveX = module.getX;
retrieveX(); // 9, because in this case, "this" refers to the global object

// Create a new function with "this" bound to module
var boundGetX = retrieveX.bind(module);
boundGetX(); // 81

bind 函数在ES5版本中才被加入,ES3版本的bind( )方法实现如下(js权威指南p191):

if (!Function.prototype.bind) {
    Function.prototype.bind = function(o[, args]) {
        var self = this, boundArgs = arguments;
        
        // bind()方法的返回值是一个函数
        return function() {
            // 创建一个实参列表,将传入bind()的第二个及后续的实参都传入这个函数
            var args = [], i;
            for(i = 1; i < boundArgs.length; i++) args.push(boundArgs[i]);
            for(i = 0; i < arguments.length; i++) args.push(arguments[i]);
            // 现在将self作为o的方法来调用,传入这些实参
            return self.apply(o, args);
        }
    }
}
/* 关键点有二:一是改变this的指向,二是改变传入参数的个数 
 *
 * 上述代码并未实现ES5中bind方法的全部特性,但思路比较清晰明了,且满足大部分需求了
 */

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/79683.html

相关文章

  • JS常用的几种异步流程控制

    摘要:虽然这个模式运行效果很不错,但是如果嵌套了太多的回调函数,就会陷入回调地狱。当需要跟踪多个回调函数的时候,回调函数的局限性就体现出来了,非常好的改进了这些情况。 JavaScript引擎是基于单线程 (Single-threaded) 事件循环的概念构建的,同一时刻只允许一个代码块在执行,所以需要跟踪即将运行的代码,那些代码被放在一个任务队列 (job queue) 中,每当一段代码准...

    Barry_Ng 评论0 收藏0
  • 前端面经整理之JSCSS

    摘要:作为对象原型链的终点。调用函数时,应该提供的参数没有提供,该参数等于。它可以用于引用该函数的函数体内当前正在执行的函数。 一 JS 二 CSS 一 JS ==和===的区别 ===叫做严格运算符 ==叫做相等运算符严格运算符比较时不仅仅比较数值还要比较数据类型是否一样相等运算符在比较相同类型的数据时,与严格相等运算符完全一样。 在比较不同类型的数据时,相等运算符会先将数据进行类型转换,...

    stonezhu 评论0 收藏0
  • 前端面经整理之JSCSS

    摘要:作为对象原型链的终点。调用函数时,应该提供的参数没有提供,该参数等于。它可以用于引用该函数的函数体内当前正在执行的函数。 一 JS 二 CSS 一 JS ==和===的区别 ===叫做严格运算符 ==叫做相等运算符严格运算符比较时不仅仅比较数值还要比较数据类型是否一样相等运算符在比较相同类型的数据时,与严格相等运算符完全一样。 在比较不同类型的数据时,相等运算符会先将数据进行类型转换,...

    lvzishen 评论0 收藏0
  • 影响JavaScript中this指向的几函数调用方法

    摘要:前言初学总会对指向感到疑惑,想要深入学习,必须先理清楚和相关的几个概念。中总是指向一个对象,但具体指向谁是在运行时根据函数执行环境动态绑定的,而并非函数被声明时的环境。除去不常用的和的情况,具体到实际应用中,指向大致可以分为以下种。 前言 初学javascript总会对this指向感到疑惑,想要深入学习javascript,必须先理清楚和this相关的几个概念。javascript中t...

    Drinkey 评论0 收藏0
  • 前端面试知识点目录整理

    摘要:写在前面金三银四又到了一年一度的跳槽季相信大家都在准备自己面试笔记我也针对自己工作中所掌握或了解的一些东西做了一个目录总结方便自己复习详细内容会在之后一一对应地补充上去有些在我的个人主页笔记中也有相关记录这里暂且放一个我的面试知识点目录大家 写在前面: 金三银四, 又到了一年一度的跳槽季, 相信大家都在准备自己面试笔记, 我也针对自己工作中所掌握或了解的一些东西做了一个目录总结,方便自...

    xzavier 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<