这次一样来分享来自"克服 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 DoeArguments: 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 DoeArguments: 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)); // 8var multipleByThree = multiply.bind(this, 3, 2);console.log(multipleByThree(4)); // 6