这是一个最近遇到的笔试题,出于尊重,不会说出该公司的名字,源于自身比较少,笔试题是将bind方法用ES3重写,使用bind这个方法,导致一时半会懵了,只记得bind可以改变this的作用域。
作为查漏补缺,这里来研究并做笔记。
this:
- 在方法中,this 表示该方法所属的对象。
- 如果单独使用,this 表示全局对象。
- 在函数中,this 表示全局对象。
- 在函数中,在严格模式下,this 是未定义的(undefined)。
- 在事件中,this 表示接收事件的元素。
- 类似 call() 和 apply() 方法可以将 this 引用到任何对象。
这东西有点绕,所以用实际例子来测试一下。
由于javaSrcipt在函数中的this指向的是全局作用域,所以下面返回undefined
1 var log = { 2 sayname () { 3 var func = function () { 4 console.log(this.name) 5 } 6 func(); 7 } 8 name: 'li' 9 } 10 11 log.sayName() // undefined
修改一下:
使用that临时储存this的作用域,此时指向对象本身
1 var log = { 2 sayname : function () { 3 // 由于是在对象中,this指向该对象本身,即log 4 var that = this 5 var func = function () { 6 console.log(that.name) 7 } 8 func(); 9 } 10 name: 'li' 11 } 12 13 log.sayname() // li
当前其他情况大部分都是指向全局this,浏览器是window,node是Golbal
1 console.log(this) // window
关于this暂时到这。
bind()
用法:
Function.bind(this [,arg1,arg2,...])
第一个参数是绑定的作用域
第二个及以后的参数则作为函数的参数调用
call()、apply()、bind() 都是用来重定义 this 这个对象的!其他两个再研究
上面那段代码,可以用bind解决作用域的问题
1 var log = { 2 sayname : function () { 3 var func = function () { 4 console.log(this.name) 5 }.bind(this) 6 func(); 7 } 8 name: 'li' 9 } 10 11 log.sayname() // li
bind还有一种用法,即传参的情况
如:
1 var name = '小明' 2 var log = { 3 name: '小红', 4 sayname : function (age, loc) { 5 var func = function () { 6 console.log(this.name + "年龄:" + age + "住在:" + loc) 7 } 8 func(); 9 } 10 } 11 12 var db = { 13 name: '汤姆' 14 } 15 16 log.sayname.bind(db, 20, '广州')() // 汤姆年龄:20 住在:广州 17 log.sayname.bind(db, 20, [‘广州’, '深圳'])() // 汤姆年龄:20 住在:广州,深圳 18 // bind会将数组当做一个参数传输,而apply则会将数组拆分为参数。
bind()的一个参数,是绑定的对象,this将指向该对象,后面则为方法中需要的参数。
bind()的返回值是一个函数。即可能是下面这种情况。
log1 = log.sayname.bind(db, 20); log1('广州'); // 结果上同 // 汤姆年龄:20 住在:广州
关于apply,用久了ES6的扩展运算符,容易忘了这个东西(哭,我的错)
好了,下面是重点,上面只是bind的用法,这个遇到的是,Polyfill这个方法。一时懵了。
先分析一下Polyfill这个问题
一、能够改变this的指针
二、能够传参
先解决第一个问题:
1 Function.prototype.bind = function (context) { 2 // this此时为调用该bind的对象 3 var self = this; 4 // 由于bind返回方法,这里直接返回方法 5 return function () { 6 // 改变this指针,将上下文传入 7 return self.apply(context) 8 } 9 } 10 11 function test() { 12 return this.name; 13 } 14 15 var testname = { 16 name: 'lihua' 17 } 18 19 test.bind(testname)(); // lihua
1.1述代码仍然有问题,只能绑定作用域,返回后的函数,无法传入参数
即: test.bind(testname) (1,2,3,4,5) 传入多少个参数都是获取不到的
1 Function.prototype.bind = function (context) { 2 // this此时为调用该bind的对象 3 var self = this; 4 // 由于bind返回方法,这里直接返回方法 5 return function () { 6 // 改变this指针,将上下文传入 7 return self.apply(context, arguments) // 增加了arguments,apply会将其作为参数传入 8 } 9 } 10 11 function test(age, loc) { 12 return this.name + ‘’ + 'age' + age + 'loc' + loc; 13 } 14 15 var testname = { 16 name: 'lihua' 17 } 18 19 test.bind(testname)(20, '深圳'); // lihua age:20 loc: 深圳
这样还有问题,即绑定的时候是可以传入默认值的,上述context传入的只是testname这个对象,所以bind(testname, 20)('深圳') 是无法获取到20这个值的
再改:
1 Function.prototype.bind = function (context) { 2 // 将类数组转为真数组 3 var arg = Array.prototype.slice.call(argument, 1) 4 // arg [20] 5 var self = this; 6 return function () { 7 // 由于apply的第二个参数只能是一个数组,所以需要将两个数组进行合并 8 var insideArgs = Array.prototype.slice.call(arguments); 9 // insideArgs ['深圳'] 10 var fullArgs = arg.concat(insideArgs); 11 return self.apply(context, fullArgs) 12 } 13 } 14 15 function test(age, loc) { 16 return this.name + '' + 'age: ' + age + 'location:' + loc; 17 } 18 19 var testname = { name: 'Liang'} 20 21 test.bind(testname, 20)(深圳);
知耻而后勇,每次发现都能够知道自己的不足之处,才能对自己有提升。
开心的是自己又知道了自己的不足之处,不开心的事,笔试在我看来不理想(哭)