克服 JS 的奇怪部分:call()、bind()、apply()

这次一样来分享来自"克服 JS 的奇怪部分"的学习笔记,这次要来介绍的是控制函数的方法。
先前我们须知道函数就是一个特殊形态的物件,他有可有可无的名称属性,还有可以被呼叫的程序属性。
而所有函数都拥有call()、bind()、apply()这些方法。

首先,在person的部分,我们知道this会指向当前的层级的位址,也就是person这个物件,而在logName我们会指向全域物件,发现找不到getFullName这个方法,故会报错。

var person = {
    firstname: 'John',
    lastname: 'Doe',
    getFullName: function() { 
        var fullname = this.firstname + ' ' + this.lastname;
        return fullname;
    }
}
var logName = function(lang1, lang2) {
    console.log('Logged: ' + this.getFullName());
}
logName();

那如果我们可以控制this指向谁不是很好吗?

bind() : Function.prototype.bind(),利用bind来控制this指向谁,可传入物件、函数,他会建立一个新函式并返回。该新函式被呼叫时,会将 this 关键字设为给定的参数Product.bind(color);,color就会是this指向的东西。

所以,我们以logName使用bind方法,去复制拥有getFullName函式的person物件,由於他会回传一个新的函数,所以我们创建一个新的变数logPersonName存取新的函数,并且呼叫他

var person = {
    firstname: 'John',
    lastname: 'Doe',
    getFullName: function() {
        
        var fullname = this.firstname + ' ' + this.lastname;
        return fullname;
        
    }
}

var logName = function(lang1, lang2) {

    console.log('Logged: ' + this.getFullName());
    console.log('Arguments: ' + lang1 + ' ' + lang2);
    console.log('-----------');
    
}

var logPersonName = logName.bind(person);
logPersonName('en');

Logged: John Doe
Arguments: en undefined
-----------

call() : Function.prototype.call,Product.call(this, name, price);第一个参数是this要指向的东西,而後为我们传入的参数,与bind不同,他并不会创建一个新的函数,call会直接执行,直接决定this指向谁。

可以发现,使用call他会直接执行,并且是可以传入参数的。

var person = {
    firstname: 'John',
    lastname: 'Doe',
    getFullName: function() {    
        var fullname = this.firstname + ' ' + this.lastname;
        return fullname;   
    }
}

var logName = function(lang1, lang2) {
    console.log('Logged: ' + this.getFullName());
    console.log('Arguments: ' + lang1 + ' ' + lang2);
    console.log('-----------');
}
logName.call(person, 'en', 'es');

Logged: John Doe
Arguments: en es
-----------

apply() : 与call()所有语法大致上与apply()相同,他们基本上不同处只有 call() 接受一连串的参数,而 apply() 接受单一的array作为参数,如Product.apply(color,['big','slim'])。

很明显跟call是非常相似,差别在於传入的参数型态。

var person = {
    firstname: 'John',
    lastname: 'Doe',
    getFullName: function() {    
        var fullname = this.firstname + ' ' + this.lastname;
        return fullname;   
    }
}

var logName = function(lang1, lang2) {
    console.log('Logged: ' + this.getFullName());
    console.log('Arguments: ' + lang1 + ' ' + lang2);
    console.log('-----------');
}
logName.apply(person, ['en', 'es']);

但我们在实际应用用的到apply吗?

函数借用(function borrowing),可以借用其他物件的方法,如同我们真的有它本身的属性。

也就是我们可以使用其他物件方法,就好像我们本身有它的属性一样。

var person = {
    firstname: 'John',
    lastname: 'Doe',
    getFullName: function() {    
        var fullname = this.firstname + ' ' + this.lastname;
        return fullname;   
    }
}
var person2 = {
    firstname: 'Jane',
    lastname: 'Doe'
}

console.log(person.getFullName.apply(person2));

Jane Doe

function currying,利用bind建立一个新复制的函数,并设定预设参数。

我们所给予的参数,会设定为复制函数的永久参数,multipleByTwo第一个参数设为2,那我们我的a永远就等於2,如同在 multiply函数中return a * b 前面新增var a = 2,而当我们设置两个参数,在呼叫时也传入参数,那麽我们呼叫时,传入的参数将会失效,一样是取我们原本设置的两个参数。

function multiply(a, b) {
    return a*b;   
}

var multipleByTwo = multiply.bind(this, 2);
console.log(multipleByTwo(4)); // 8

var multipleByThree = multiply.bind(this, 3, 2);
console.log(multipleByThree(4)); // 6

<<:  [Cmoney 菁英软件工程师战斗营] IOS APP 菜鸟开发笔记(5)----关於导入Google Maps API 遇到的问题

>>:  Dial 1866-549-8444 to Fix Norton Scan Related Issues

[Day29]今天想来分享一些网路上的学习资源~以及学习历程

没有错,最近发生了一些事情,让我想要跟我的读者讲讲这些事情,这些我觉得很重要的事情XD((虽然好像...

30天程序语言研究

今天是30天程序语言研究的第六天,研究的语言一样是python,今天主要学习的是建立一个计算机和字典...

.NET Core第15天_MVC的TagHeper使用_微软Web应用框架中前端部分的演进

微软Web应用框架中前端部分的演进 微软於Web应用框架中前端部分 做的三次大变革 .net Web...

多层次纵深防御下失守案例的有效改善对策

游戏大厂EA被骇,被盗的资料在暗网贩售。 破解层层防护的方法是,弄到被盗的cookie获得EA使用的...

Swift纯Code之旅 Day12. 「TableView(番外篇) - TableViewCell Accessory」

前言 现在我们已经很像IPhone的内建闹钟了,但是还是有一点不一样(下图红框圈起处) 因此今天就要...