js中call()、apply()、bind()的使用及实现

news/2024/7/19 14:35:05 标签: js, javascript

使用

call()、apply()、bind()都是用来改变this的指向的。
一、A.a.call(B, x, y)
A是一个对象,a是对象A里的方法函数,x和y是a函数的参数,B也是一个对象,但对象B想调用对象A的a方法,那么call()的作用就是改变函数a的this指向,让函数a的this指向B,对象B就能调用a方法

javascript">let A = {
  num: 1,
  a: function(x, y){
      console.log('我是A对象的a方法,参数:', x, y, 'num:', this.num)
  }
}
let x = 2
let y = 3
let B = {
  num: 4,
}

console.log(A.a(x, y)) // 我是A对象的a方法,参数: 2 3 num: 1
console.log(A.a.call(B, x, y)) // 我是A对象的a方法,参数: 2 3 num: 4

二、A.a.apply(B, [x, y])
可以看到call和apply的用法和作用基本一致,只是接受参数的方式不太一样,即call 需要把参数按顺序传递进去,而 apply 则是把参数放在数组里

javascript">let A = {
  num: 1,
  a: function(x, y){
      console.log('我是A对象的a方法,参数:', x, y, 'num:', this.num)
  }
}
let x = 2
let y = 3
let B = {
  num: 4,
}

console.log(A.a(x, y)) // 我是A对象的a方法,参数: 2 3 num: 1
console.log(A.a.apply(B, [x, y])) // 我是A对象的a方法,参数: 2 3 num: 4

三、A.a.bind(B, x, y)()
bind()除了返回是函数以外,它的参数和call()一样。bind()会创建一个函数,函数体内的this对象的值会被绑定到传入bind()中的第一个参数的值,例如:f.bind(obj),实际上可以理解为obj.f(),这时f函数体内的this自然指向的是obj

javascript">let A = {
  num: 1,
  a: function(x, y){
      console.log('我是A对象的a方法,参数:', x, y, 'num:', this.num)
  }
}
let x = 2
let y = 3
let B = {
  num: 4,
}

console.log(A.a(x, y)) // 我是A对象的a方法,参数: 2 3 num: 1
console.log(A.a.bind(B, x, y)()) // 我是A对象的a方法,参数: 2 3 num: 4

// 关于bind()的一些题目

function f(y,z){
   return this.x+y+z;
}
var m = f.bind({x:1},2);
console.log(m(3)); // 6
// 分析:这里的bind方法会把它的第一个实参绑定给f函数体内的this,所以里的this即指向{x:1}对象;
// 从第二个参数起,会依次传递给原始函数,这里的第二个参数2即是f函数的y参数;
// 最后调用m(3)的时候,这里的3便是最后一个参数z了,所以执行结果为1+2+3=6
// 分步处理参数的过程其实是一个典型的函数柯里化的过程(Curry)

var a = document.write;
a('hello'); // error
a.bind(document)('hello'); // hello
a.call(document,'hello'); // hello
// 分析:直接调用a的话,this指向的是global或window对象,所以会报错;
// 通过bind或者call方式绑定this至document对象即可正常调用

常见用法

javascript">// 数组之间追加
var arr1 = [1 , 2 , 3];
var arr2 = [4 ,5];
console.log(Array.prototype.push.apply(arr1, arr2))

// 获取数组中的最大值和最小值
let list = [1, 2, 3, -4]
console.log(Math.max.apply(Math, list))   // 3
console.log(Math.min.apply(Math, list))   // -4

// 判断数据类型
var  whichDataType = {
 isObj:function(o){
     if (Object.prototype.toString.call(o)==="[object Object]")
     return true;
     else 
     return false
 },
 isArray:function(o){
     if(Object.prototype.toString.call(o)==="[object Array]")
     return true;
     else 
     return false
 },
 isNULL:function(o){
     if (Object.prototype.toString.call(o)==="[object Null]")
     {return true;}
     else 
     return false
 },
 isNumber:function(o){
     if (Object.prototype.toString.call(o)==="[object Number]")
     {return true;}
     else 
     return false
 },
 isFunction:function(o){
     if (Object.prototype.toString.call(o)==="[object Function]")
     {return true;}
     else 
     return false
 },
 isUndefine:function(o){
     if (Object.prototype.toString.call(o)==="[object Undefine]")
     {return true;}
     else 
     return false
 },
 isString:function(o){
     if (Object.prototype.toString.call(o)==="[object String]")
     {return true;}
     else 
     return false
 },
 isBoolen:function(o){
     if (Object.prototype.toString.call(o)==="[object Boolen]")
     {return true;}
     else 
     return false
 },
 isSymbol:function(o){
     if (Object.prototype.toString.call(o)==="[object Symbol]")
     {return true;}
     else 
     return false
 },
}
console.log(whichDataType.isObj({a:1}))

// 伪数组转真数组
var domNodes = Array.prototype.slice.call(document.getElementsByTagName("*"))
console.log(domNodes)

// 绑定函数
let A = {
   num: 1,
    a: function(){
        console.log(this.num)
    }
}
this.num = 2
let a = A.a
A.a() // 1
a() // 2
a.bind(A) // 1

// 闭包经典题目
for(var i = 1; i <= 5; i++) {
  setTimeout(console.log.bind(console, i), i * 1000);
}
// 顺便贴一下其他方法
for(var i = 1; i <= 5; i++) {
  !function(i) {
    setTimeout(function() {
      console.log(i);
    }, i * 1000);
  }(i);
}
for(let i = 1; i <= 5; i++) {
  setTimeout(function() {
    console.log(i);
  }, i * 1000);
}
// 没有对比没有伤害啊

实现

一、call()

javascript">// 思路:将要改变this指向的方法挂到目标this上执行并返回
Function.prototype.mycall = function (context) {
  if (typeof this !== 'function') {
    throw new TypeError('not funciton')
  }
  context = context || window
  context.fn = this
  let arg = [...arguments].slice(1)
  let result = context.fn(...arg)
  delete context.fn
  return result
} 

二、apply()

javascript">// 思路:将要改变this指向的方法挂到目标this上执行并返回
Function.prototype.myapply = function (context) {
  if (typeof this !== 'function') {
    throw new TypeError('not funciton')
  }
  context = context || window
  context.fn = this
  let result
  if (arguments[1]) {
    result = context.fn(...arguments[1])
  } else {
    result = context.fn()
  }
  delete context.fn
  return result
}

三、bind()

javascript">// 思路:类似call,但返回的是函数
Function.prototype.mybind = function (context) {
  if (typeof this !== 'function') {
    throw new TypeError('Error')
  }
  let _this = this
  let arg = [...arguments].slice(1)
  return function F() {
    // 处理函数使用new的情况
    if (this instanceof F) {
      return new _this(...arg, ...arguments)
    } else {
      return _this.apply(context, arg.concat(...arguments))
    }
  }
}

http://www.niftyadmin.cn/n/1769480.html

相关文章

三角形最大和问题

题目描述 给一个数组至少三个数&#xff0c;任意选出数组中三个数&#xff0c;求满足三角形的三个数的最大和 例如&#xff1a; 1 2 3 不满足三角形&#xff0c;返回0 1 2 3 4 满足三角形最大和为2349&#xff0c;返回9 package test_26; import java.lang.reflect.Array…

浅克隆与深克隆

浅克隆 一般实现数组克隆的方法都是浅克隆&#xff0c;直接将存储在栈中的值赋值给对应变量&#xff0c;如果是基本数据类型&#xff0c;则直接赋值对应的值&#xff0c;如果是引用类型&#xff0c;则赋值的是地址 方法 slice&#xff1a; let arr2 arr1.slice(0); concat…

Java多线程(切换输入)

多线程 数组1 {1&#xff0c;2&#xff0c;3} 数组2{A&#xff0c;B&#xff0c;C} 要求切换输出结果&#xff1a;1A2B3C package test_26;import java.util.concurrent.locks.LockSupport;class S1 {static Thread t1null,t2null;public static void main(String[] args) {…

Vue的ESLint配置

Vue的ESLint配置 常用规则 // “off”或0&#xff1a;不启用该规则。 // “warn”或1&#xff1a;违反时警告。 // “error”或2&#xff1a;违反时报错。 rules: {"comma-dangle": ["error", "never"], //是否允许对象中出现结尾逗号"no…

如何快速的Github下载超具体操作

How to be quick ——git clone 前言 相信有时会奇怪为什么git clone总是那么的慢呢&#xff1f;主要原因是因为……敲黑板了&#xff0c;保持安静 因为github.global.ssl.fastly.net域名被限制了&#xff0c;不要问三连 那么如何处理这种情况呢&#xff1f;The only thing …

ThreadPoolExecutor的4种拒绝策略(TODO未完成)

ThreadPoolExecutor的4种拒绝策略 问题场景 当加入的任务数量超过一定数目&#xff08;maximumPoolSize BlockingQueue 队列长度&#xff09;&#xff0c;默认情况下会抛出异常。这种情况会造成某些采集、转换错误、遗漏&#xff0c;不符合预期。 期望的结果是&#xff0c;分…

学习途中的故事——Halo下载记——Goodbye hallo

Halo下载记——Goodbye hallo 这段时间一直都在研究如何导入hallo这个开源的项目&#xff0c;一直想&#xff0c;却遇到了无数的困难&#xff0c;想起来已经流泪。这中间首先电脑网速有些问题&#xff0c;一直不能git clone&#xff0c;我学习了git clone -depth1的方式&#x…

PreparedStatement and Statement (TODO)

PreparedStatement and Statement 前言 public interface PreparedStatement extends Statement 看到这个恐怕就要揭晓大致的主题了&#xff0c;聪明的你肯定猜到了就要研究一下代码&#xff0c;虽然这么说&#xff0c;重点还是放在两者的区别&#xff0c;基本上看名字都能猜…