前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >js设计模式补白之 this/call和apply

js设计模式补白之 this/call和apply

作者头像
一粒小麦
发布2019-07-18 17:03:01
3260
发布2019-07-18 17:03:01
举报
文章被收录于专栏:一Li小麦一Li小麦

this

this指向一个动态的函数执行环境。

在一个普通的对象中,this的作用次域当然是对象本身

在前端最常用的浏览器中,alert(this)的结果是window。

var name='dangjingtao'

        var obj={
            name:'djtao',
            getName:function(){
                return this.name
            }
        }

        console.log(obj.getName()) //djtao
        var a=obj.getName; //抽离了使用环境
        console.log(a()) //dangjingtao

现在来研究一个业务中常见的问题。

<a id="hit-me" href="javascript:;">hit me</a>

    <script>
        document.getElementById('hit-me').onclick=function(){
            alert(this.id);//hit-me

            var callback=function(){
                alert(this.id)//undefined
            }

            callback();
        }
    </script>

处理方法是用一个变量存下 this

document.getElementById('hit-me').onclick=function(){
            alert(this.id);//hit-me

            var _this=this;

            var callback=function(_){
                alert(_this.id)//undefined
            }

            callback();
        }

call用于绑定当前作用于

var name='dangjingtao';

        var obj={
            name:'djtao',
            getName:function(){
                return this.name
            }
        }

        alert(obj.getName.call(this)); //dangjingtao

这里call(this)显然是把当前的作用域(window)绑定给了getName方法。

遗失的this

写一个简单的js选择器吧,比如 document.getElementById('div1'),实在太长了。

var getId=document.getElementById
    console.log(getId('div1'))

运行报错。因为用getId引用了之后,getElementById失去了this。

如何既能调用方法,又不丢失this?干货在于

document.getElementById=(function(func){
        return function(){
            return func.apply(document,arguments)
        }
    })(document.getElementById)

    var getId=document.getElementById
    console.log(getId('div1'))

call和apply

这两个方法非常重要。

调用apply方法的时候,第一个参数是this的指向 , 第二个参数是一个数组或类数组集合 。apply把这个集合作为参数传递给被apply的函数。

var func=function(a,b,c){
    alert([a,b,c]) //输出[1,2,3]
}

func.apply(null,[1,2,3])

call是apply的高级实现。当你知道参数数量时,也可以用call来写。比如 func.call(obj,'a','b','c')

非严格模式下,如果第一个参数为null,this还是指向默认的宿主。比如在浏览器中就是window。严格模式下则为null。

应用

如果认为,call和apply作用只局限于改变this的指向,那就错了。你还可以获取别的属性方法,绑定

来看看其它用法

访问一类对象的内部数据

大部分高级浏览器都实现了 Function.protoype.bind方法,用以绑定 this。学习上述知识,能否手写模拟一个bind方法?

Function.prototype.bind=function(ctx){
    var _this=this;//保存原函数

    return function(){
        return _this.apply(ctx,arguments)
    }
}

// 接下来试验一下
var name='dangjingtao'
var obj={
    name:'djtao'
}
var func=function(){
    return this.name
}.bind(obj)

console.log(obj) //控制台打印{name:'djtao'}
func() //弹出djtao

简单地说,我们在不为这个对象注册方法的前提下,为了一个对象实现了对内部私有变量的访问。

再丰富一点点

bind的简单实现并不足以满足功能。我想扩展bind方法并允许传入多个参数,并且还可以追加这个方法的参数。

可以这么做。

Function.prototype.bind=function(){
    var _this=this;//保存原函数
    var ctx=[].shift.call(arguments)//拿到第一个参数(也就要是绑定的this)
    var args=[].slice.call(arguments)//其他参数转化为数组
    //下面返回一个新函数
    return function(){
        //执行这个新函数的时候,会把ctx作为this
        //并且组合两次分别传入的参数,作为该函数的参数
        return _this.apply(ctx,[].concat.call(args,[].slice.call(arguments)))
    }
}

测试结果

var obj={
    name:'djtao'
}

var func=function(a,b,c,d){
    alert(this.name) //djtao
    alert([a,b,c,d]) //输出1,2,3,4
}.bind(obj,1,2)

// 执行
func(3,4)
借用其他构造对象的方法

读书人的事,靠偷是不对的,应该是借。以下A是一个构造函数,拥有给某个人添加"是天才"后缀的处理过程。我要拿到A的属性。

var A=function(name){
    this.name=name+'是天才'
}

可以构造一个B对象来借

var B=function(){
    A.apply(this,arguments)
}

//然后写一个方法。
B.prototype.getName=function(){
    return this.name
}

var b=new B('djtao');
console.log(b.getName)//结果是 djtao是天才
再比如

arguments对象不是数组。但是我想把它们作为数组来处理,比如push。我想借用Array对象的push方法,怎么做?

(function(){
    Array.prototype.push.call(arguments,3);
    console.log(arguments)
})(0,1,2)
// 执行结果打印出1,2,3

更骚的操作是给对象也加个push方法

var a={}

    Array.prototype.push.call(a,'0')

    Array.prototype.push.call(a,'第一个元素');
    Array.prototype.push.call(a,'第二个元素')

    console.log(a)

只要对象的属性可读写,length属性可读写,那就可以把push方法用到上面去。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-05-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 一Li小麦 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • this
  • 遗失的this
  • call和apply
  • 应用
    • 访问一类对象的内部数据
      • 再丰富一点点
        • 借用其他构造对象的方法
          • 再比如
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档