最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • JavaScript中的this与它的三个函数

    正文概述 掘金(李唐敏名)   2021-03-26   486

    this

    this 机制是 JavaScript 特有的,它是为了解决在对象内部的方法中使用对象内部的属性的需求。

    如果不使用 this 来实现对对象内部的属性 JavaScript 可以使用对象.属性访问到:

    let people = {
    	name: 'litangmm',
        logName: function(){
            console.log(people.name)
        }
    }
    

    这种方法,方法与对象强耦合。对象变量变化,方法必须接着改变。如果有一个匿名对象数组,那么对象位置改变,方法就得改。

    let peoples = [
        {name:'litangmm',logName: function(){console.log(peoples[0].name)}},
        {name:'litangmm1',logName: function(){console.log(peoples[1].name)}},
        {name:'litangmm2',logName: function(){console.log(peoples[2].name)}},
    ]
    

    于是,this 出现了。

    this 是和执行上下文绑定的。this,是运行时确定的。

    1. 在全局环境下,this 指向全局的 window。
    2. 作为函数执行时,如果是作为对象的函数执行,则指向该对象本身,否则指向全局的window。
    3. 1 2都是非严格模式下的,全局模式下,this 拿不到全局 window 而是 undefined

    还有 bind apply call new,它们和this紧密相关。

    bind apply call 都是属于函数的原型方法,可以改变函数执行的 this 的指向。它们的原理都是:

    只不过在一些细节上实现不同。下面,通过手写它们的实现来理解它们的异同。

    call 和 apply

    执行效果

    1. 改变 thisarg
    2. 接收函数入参
    3. 执行函数

    说明

    1. 对于 thisarg ,在非严格模式下,如果 thisarg 为 null 或 undefined ,thisarg 会为 全局 window。
    2. 对于函数入参,call 接收 的是多个参数值,apply接收的是一个参数列表。
    // mycall.js
    Function.prototype.mycall = function(thisarg,...args){
        let context = thisarg || window
        context.fn = this 
        const res = context.fn(...args)
        delete context.fn
        return res
    }
    function logNameAndAge(age, sex){
        console.log(this.name,age,sex)
    }
    logNameAndAge.mycall({name:"litangmm"},21,'man') // litangmm 21 man
    

    context.fn = this 这里做了一件事,就是在 context 上定义了一个属性fn,赋值为 this 。**this是调用mycall的函数A。**这样,在下一行,函数A就作为 context 对象的对象函数被调用,函数A执行的this自然指向context了。

    当然,这代码还是有优化空间的:

    1. 判断 this 是否为 函数。
    2. 如果传入的 thisarg 上有 fn 属性,那么该属性会被覆盖。

    我们考虑这些情况,实现apply

    // myapply.js
    Function.prototype.myapply = function(thisarg,args){
        if(typeof this !== 'function'){
            throw new TypeError('error')
        }
        let context = thisarg || window
        const fn = Symbol()
        context.fn = this 
        const res = context.fn(...args)
        delete context.fn
        return res
    }
    function logNameAndAge(age, sex){
        console.log(this.name,age,sex)
    }
    logNameAndAge.myapply({name:"litangmm"},[21,'man'])  // litangmm 21 man
    

    说明:

    1. 通过 typeof 判断调用的是否是一个函数。
    2. 通过 Symbol 来解决属性冲突。

    bind

    执行效果

    1. 改变 thisarg。
    2. 接收函数入参。
    3. 返回函数。

    对于返回函数

    1. 可以接收入参。
    2. 可以作为构造函数使用。
    3. 作为构造函数使用时,bind 绑定的 this 会被忽略。

    bind 实现的难点在于

    1. bind 执行时接收可以接收参数(类似call接收多个参数),返回的函数还可以接收参数。
    2. 判断返回函数是作为构造函数被使用。
    // mybind.js
    Function.prototype.mybind = function(thisarg,...args1){
        if(typeof this !== 'function'){
            throw new TypeError('error');
        }
    	const that = this;
        let fBound = function(...args2){
            return that.apply(this instanceof fBound ? this: thisarg,args1.concat(args2));
        }
        let fNop = function(){};
        fNop.prototype = that.prototype;
        fBound.prototype = new fNop();  
        return fBound;
    }
    

    说明

    之所以可以通过this instanceof F 来判断是被当作构造函数被使用的,可以参考new 的原理:

    1. 创建一个空对象。

    2. 指定空对象的__proto__为构造函数的prototype

    3. 绑定该空对象到构造函数。

    4. 执行绑定后的构造函数。

    5. 如果构造函数有返回值,则返回返回值,否则返回对象。

    !注意2步,因为返回的构造函数 是 fBound,而,我们希望得到的that上的原型,所以,有代码

    fBound.prototype = that.prototype;	
    

    这代码是存在问题的,因为fBound.prototype=== that.prototype === 原型对象地址,所以操作fBound.prototype 修改会改变 that.prototype。所以,我们可以使用原型链来实现fBoundthat 的连接。

    let fNop = function(){};
    fNop.prototype = that.prototype;
    fBound.prototype = new fNop();   
    

    这样,fBound.prototype 就是一个对象,对象的__proto__指向that.prototype。可以参考这篇文章。

    !注意3、4步,构造函数执行的时候,空对象的__proto__已经指向了构造函数的prototype。所以,绑定后的构造函数的this 是可以在原型链上找到构造函数的。


    起源地下载网 » JavaScript中的this与它的三个函数

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元