理解call和apply

我们都知道call、apply、bind()都是用来改变this指向的,这个概念 我看了好多遍每次看完总是似懂非懂,下面做个记录,首先我们在MDN上重新了解这几个概念:

apply()

apply() 方法调用一个具有给定this值的函数,以及作为一个数组(或类似数组对象)提供的参数。

语法介绍:
func.apply(thisArg, [argments])

thisArg: this要指向的对象,想指定的上下文
arguments: 想要传递的参数(数据或类数组对象)

call()

call() 方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数。

语法介绍:
func.call(thisArg, arg1, arg2 …)
thiArg: this要指向的对象,想指定的上下文
arg1, arg2 …: 指定的参数列表

我们可以看到:

call和apply的作用是相同的,他们都是用来改变函数上下文,并且第一个参数 都是要指定的上下文,区别就是call()方法接受的是一个参数列表,apply()接受的是一个参数数组

var female = {
	name: '女生',
	age: 18,
	likeWear: function() {
		console.log(this.name)
		console.log(arguments)
	}
}
var male = {
	name: '男生',
	age: '20'
}
female.likeWear.apply(male, ['polo','球鞋'])
female.likeWear.call(male, 'polo','球鞋')

male 拥有了likeWear()方法并立即执行了返回了 name 以及传入的参数

我们看一下mdn上的例子

var numbers = [5, 6, 2, 3, 7];

var max = Math.max.apply(null, numbers);

console.log(max);
// expected output: 7

var min = Math.min.apply(null, numbers);

console.log(min);
// expected output: 2

第一个参数为 null或者undefined时,会自动替换为指向全局对象,在html中为window对象,在window对象上调用 math.max方法,输出数组中的最大值

var array = ['a', 'b'];
var elements = [0, 1, 2];
array.push.apply(array, elements);
console.log(array); // ["a", "b", 0, 1, 2]

array.push.apply(array,elements) 可以将elements作为一个参数合集 (不是一个参数)依次添加近array中

var animals = [
  { species: 'Lion', name: 'King' },
  { species: 'Whale', name: 'Fail' }
];

for (var i = 0; i < animals.length; i++) {
  (function(i) {
    this.print = function() {
      console.log('#' + i + ' ' + this.species
                  + ': ' + this.name);
    }
    this.print();
  }).call(animals[i], i);
}

call() 允许为不同的对象分配和调用属于一个对象的函数/方法。
上述代码中 animals[i] 调用 分配并调用了这个匿名函数 并把 i作为参数穿了进去 当i=0时
对象 {species: ‘Lion’, name: 'King} 分配了
我的理解是

obj = {
	species: 'line',
	name: 'King',
	print: function() {
		console.log('#0' +t his.species
                  + ': ' + this.name )
	}
}

运用call()立即执行方法print
在下面的例子中,当调用 greet 方法的时候,该方法的this值会绑定到 obj 对象

function greet() {
  var reply = [this.animal, 'typically sleep between', this.sleepDuration].join(' ');
  console.log(reply);
}

var obj = {
  animal: 'cats', sleepDuration: '12 and 16 hours'
};

greet.call(obj);  // 

bind()

bind()方法创建一个新的函数,在bind()被调用时,这个新函数的this被bind的第一个参数指定,其余的参数将作为新函数的参数供调用时使用。

语法介绍:
function.bind(thisArg[,arg1[,arg2[, …]]]) 生成一个新的方法

thisArg: 调用绑定函数时作为this参数传递给目标函数的值, 1.如果使用new运算符构造绑定函数,则忽略该值。当使用2.bind在setTimeout中创建一个函数(作为回调提供)时,作为thisArg传递的任何原始值都将转换为object3.如果bind函数的参数列表为空,执行作用域的this将被视为新函数的thisArg。

arg1, arg2, …
当目标函数被调用时,预先添加到绑定函数的参数列表中的参数。

var module = {
  x: 42,
  getX: function() {
    return this.x;
  }
}

var unboundGetX = module.getX;
console.log(unboundGetX()); // The function gets invoked at the global scope
// expected output: undefined

var boundGetX = unboundGetX.bind(module);
console.log(boundGetX());

console(unboundGetX())时 unboundGetX在全局变量window上 window上没有x属性 所以返回undefined ,console.log(boundGetX())时,this指向 module module.x = 42, 返回42

1. bind() 最简单的用法是创建一个函数,不论怎么调用,这个函数都有同样的 this 值
2 bind()的另一个最简单的用法是使一个函数拥有预设的初始参数。(传参)

function list() {
  return Array.prototype.slice.call(arguments);
}

function addArguments(arg1, arg2) {
    return arg1 + arg2
}

var list1 = list(1, 2, 3); // [1, 2, 3]

var result1 = addArguments(1, 2); // 3

// 创建一个函数,它拥有预设参数列表。
var leadingThirtysevenList = list.bind(null, 37);

// 创建一个函数,它拥有预设的第一个参数
var addThirtySeven = addArguments.bind(null, 37); //执行作用域的this将被视为新函数的thisArg。

var list2 = leadingThirtysevenList(); 
// [37]
var list4 = addThirtySeven()
// NAN

var list3 = leadingThirtysevenList(1, 2, 3); 
// [37, 1, 2, 3]

var result2 = addThirtySeven(5); 
// 37 + 5 = 42 

var result3 = addThirtySeven(5, 10);
// 37 + 5 = 42 ,第二个参数被忽略

优先使用bind时传入的参数进行计算,参数不够的情况下返回NAN, 参数太多会忽略多余参数

在默认情况下,使用 window.setTimeout() 时,this 关键字会指向 window (或global)对象。当类的方法中需要 this 指向类的实例时,你可能需要显式地把 this 绑定到回调函数,就不会丢失该实例的引用。

function LateBloomer() {
  this.petalCount = Math.ceil(Math.random() * 12) + 1;
}

// 在 1 秒钟后声明 bloom
LateBloomer.prototype.bloom = function() {
  window.setTimeout(this.declare.bind(this), 1000);
};

LateBloomer.prototype.declare = function() {
  console.log(this)  // LateBloomer {petalCount: 12}
  console.log('I am a beautiful flower with ' +
    this.petalCount + ' petals!');
};

var flower = new LateBloomer();
flower.bloom();  // 一秒钟后, 调用'declare'方法
function LateBloomer() {
  this.petalCount = Math.ceil(Math.random() * 12) + 1;
}

// 在 1 秒钟后声明 bloom
LateBloomer.prototype.bloom = function() {
  window.setTimeout(this.declare, 1000);
};

LateBloomer.prototype.declare = function() {
  console.log(this) // window 对象
  console.log('I am a beautiful flower with ' +
    this.petalCount + ' petals!');//I am a beautiful flower with undefined petals!
};

var flower = new LateBloomer();
flower.bloom();  // 一秒钟后, 调用'declare'方法
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值