zoukankan      html  css  js  c++  java
  • Javascript中this作用域以及bind方法的重写

    这是一个最近遇到的笔试题,出于尊重,不会说出该公司的名字,源于自身比较少,笔试题是将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)(深圳);

    知耻而后勇,每次发现都能够知道自己的不足之处,才能对自己有提升。

    开心的是自己又知道了自己的不足之处,不开心的事,笔试在我看来不理想(哭)

    以梦为马
  • 相关阅读:
    Viusal Studio 2022 正式版安装秘钥
    关于云计算,云存储,和自己开发的云存储的小工具
    网盘工具比较,以及自己开发的网盘工具
    VARIANT及相关类
    关于 BSTR, CComBSTR and _bstr_t
    如何真正发挥Google Docs的威力
    ORM框架EntitysCodeGenerate自定义分页查询及快捷执行SQL(CreateSQL)示例
    关于Java Servlet的中文乱码
    ORM框架VB/C#.Net实体代码生成工具(EntitysCodeGenerate) 【ECG】4.3 介绍
    通用JS验证框架(ChkInputs)概述
  • 原文地址:https://www.cnblogs.com/lsAxy/p/12839816.html
Copyright © 2011-2022 走看看