bind(),call(),apply()
三种方都可以用来改变函数this指向,第一个参数都是目标对象,后面的参数不同,返回值野不同。
- call(obj, arg1, arg2…):参数依次放入,返回值是调用的方法的返回值。
- apply(obj, [arg1, sarg2…]):出第一个参数都需要放入一个数组当中,返回值是调用的方法的返回值。
- bind(obj, arg1, arg2…)():参数一次放入,返回值是一个新的函数,需要去执行。
var obj = {
name : 'xiaoLi',
age : 20
}
var person = {
name : 'xiaozhang',
age : 16,
showFun : function( hometown, score ){
return ("name : " + this.name + ",age : " + this.age + ',hometown : ' + hometown + ',score : ' + score);
}
}
person.showFun();
console.log(person.showFun.apply(obj, ['beijing', 99]));
console.log(person.showFun.call(obj, 'shanghai', 100));
console.log(person.showFun.bind(obj, 'nanjing', 98));
在封装之前,再写一段关于this的代码,这个是在别人博客上看到的东西。
原文:https://blog.csdn.net/yangwei234/article/details/84451165
var a = 1;
var obj = {
a: 2,
fn: function(){
console.log(this.a);
}
}
var fn1 = obj.fn;
fn1();/1
我的理解是,这里fn1接收的这个函数体,但是fn1本身是全局声明的,所以调用fn1时,this指向为window,函数中的this.a自然是1。
先给一段基础代码
var person = {
name : 'zhangsan',
age : 12
}
var newPerson = {
name : 'lisi',
age : 20,
showFun : function(hometown, score){
console.log(this.name + ',' + this.age + ',' + hometown + ',' + score)
return this.name + ',' + this.age + ',' + hometown + ',' + score
}
}
封装call
Function.prototype.myCall = function(){
var that = typeof arguments[0] === 'object' ? arguments[0] : window;
var newArg = [];
for( var i = 1, len = arguments.length; i < len; i ++){
newArg.push(arguments[i])
}
that.newFunction = this;
var result = that.newFunction(...newArg)
delete that.newFunction;
return result;
}
newPerson.showFun.myCall(person,'beijing',100)
这里首先要考虑到使用that接收传进来的对象,同时也要判断一下是否是一个对象,如果不是,则that=window。因为方法中会使用一些传入对象的参数,因此需要给这个对象新增方法去执行一次,执行完毕后记得要删除。
封装apply
判断arguments[0]时,typeof和instanceof Object都无法进行准确判断,因此我使用了原型的constructor属性来判断,而第二个参数的判断是做了一个是否传参以及是否是数组的判断。其他的内容与call()没什么区别。
Function.prototype.myApply = function(){
var that = typeof arguments[0] === 'object' ? arguments[0] : window;
var newArg = [];
if(arguments[1] instanceof Array){
for( var i = 1, len = arguments[1].length; i < len; i ++){
newArg.push(arguments[i])
}
}else{
arguments[1] = []
}
that.newFunction = this;
var result = that.newFunction(...arguments[1]);
delete that.newFunction;
return result;
}
newPerson.showFun.myApply([1,1])
封装bind
前半部分与封装call()相同,不过因为bind返回的是一个函数,所以,要return出一个函数,之前我尝试直接用that来执行方法,但是return出去后无法删除新增的那个方法,影响目标对象,因此使用Object.assign()复制目标对象,这样不会改变目标对象。
Function.prototype.myBind = function(){
var that = typeof arguments[0] === 'object' ? arguments[0] : window;
var newArg = [];
for(var i = 1,len = arguments.length; i < len; i ++){
newArg.push(arguments[i])
}
var self = {};
Object.assign(self,that);
self.newFunction = this;
function returnFunc(){
return self.newFunction(...newArg);
}
return returnFunc;
}
newPerson.showFun.myBind()();
newPerson.showFun.bind()();