nodejs中call和apply的学习

接触了不少nodejs的知识点,一直没有作自我整理和概括,再次用到的时候仍是不清晰,这是病,得治。在此但愿经过记录的方式加深本身的理解。

1.引子:做用域与上下文


总的来讲:做用域与调用函数访问变量的能力有关,上下文和this关键字有关,是当前可执行代码的引用。javascript

1.1做用域

做用域分为局部做用域和全局做用域,做用域每每和变量存在关系。处在局部做用域里面能够访问全局做用域的变量,而处在局部做用域外面不能访问局部做用域里面的变量。看代码:html

var globalVariable = 'this is global variable';

function globalFunction(){
    var localVariable = 'this is local variable';
    console.log(globalVariable);   //this is global variable
    console.log(localVariable);   //this is local variable

    globalVariable = 'globalVariable has changed';

    function innerFunction(){
        var innerLocalVariable = 'this is inner local variable';
  
        console.log(globalVariable);   //globalVariable has changed
        console.log(localVariable);   //this is local variable
        console.log(innerLocalVariable);   //this is inner local variable
    }
    innerFunction();
}

globalFunction();
1.2上下文

上下文经常表明this变量的值以及它的指向,它决定一个函数怎么被调用,当一个函数被做为一个对象的方法调用时,this老是指向调用方法的对象。java

var pet = {
    words: '...',
    speak: function(){
        console.log(this.words);     //'...'
        console.log(this === pet);   // true
    }
}
pet.speak();

'==='表示不只值相等,类型也相同,this指向调用speak方法的pet对象,对比下面代码:node

function pet(words){
    this.words = words;
    console.log(words);   //'...'
    console.log(this === pet)   //false
    console.log(this === global)   //true
}
pet('...');

此处的this指向运行环境的顶层的global对象,这里能够直接使用console.log(this)查看。继续看一段代码:数组

function Pet(words){
    this.words = words;
    this.speak = function(){
        console.log(this.words);   //miao
        console.log(this);    //打印出当前对象{words:'miao',speak:[Function]}
    }
}

var cat = new Pet('miao');
cat.speak();

*注:引入箭头函数=>后,this不是指向函数调用的对象, 而是其父级对象app

var words= 'global';
var pet = {
    words: '...',
    speak: () => {
        console.log(this.words);     //'global'
        console.log(this === pet);   // false
    }
}
pet.speak();  // pet的父级对象Window

2.call和apply

使用call和apply能够改变上下文执行对象,能够在自定义上下文中执行函数,二者做用相同,仅仅是方法的第二个参数不一样,call直接使用参数列表,apply使用参数数组。具体做用是调用一个对象的方法,以另外一个对象替换当前对象,实际上市改变this指向的对象内容。看代码:ide

var pet = {
    words: '...',
    speak: function(say){
        console.log(say + ' ' + this.words);
    }
}
pet.speak('Speck');   // Speck ...

没毛病!,修改代码,再看一下:函数

var pet = {
    words: '...',
    speak: function(say){
        console.log(say + ' ' + this.words);
    }
}

var dog = {
    words:'wang'
}

pet.speak.call(dog,'Speak');   // Speak wang

dog对象原本没有speak方法,经过call的方法,偷梁换柱地将本来指向pet的this变量指向了dog,所以在运行时,this.words='wang',因此打印出Speak wang。经过这种方式,咱们可使一个对象去使用另外一个对象的方法,一个容易想到的应用场景就是继承。this

function Pet(words){
    this.words = words;
    this.speak = function(){
        console.log(this.words);
    }
}

function Dog(words){
    //Pet.call(this,words);  // Pet中的this指向当前的Dog,使Dog拥有Pet的方法
    Pet.apply(this,[words]);  // apply中的第二个参数是一个数组
}

var dog = new Dog('wang');
dog.speak();

咱们能够看到,使用call和apply实现的效果是同样的,仅仅是参数的差别,一个直接使用words,一个要使用数组形式的[words]。再看一个例子:code

function print(a, b, c, d){
    alert(a + b + c + d);
}
function example(a, b , c , d){
    //用call方式借用print,参数显式打散传递
    print.call(this, a, b, c, d);

    //用apply方式借用print, 参数做为一个数组传递,

    //能够直接用JavaScript方法内自己有的arguments数组
    print.apply(this, arguments);

    //或者封装成数组
    print.apply(this, [a, b, c, d]);
}

至于何时使用call,何时使用apply,通常当参数比较明确的时候,二者均可以,当参数不明确时,推荐使用apply+arguments的方式。

3.结束语

本篇文章主要参考了慕课网,进击nodejs基础(一)中http源码解读部份内容,以及博客文章关于javascript中apply()和call()方法的区别,加上本身的理解整理所得,若有错误之处,欢迎指出。

相关文章
相关标签/搜索