JavaScript的apply、call、bind方法
概述
简述这三个方法存在一定的迷惑性 ,而且对于刚看ES6的人来说,十分难理解,这里为了以后我可能会复习到这个知识点,做出详解。总的来说,这三个方法都是将某某某(某01)绑定在某某某(某02)上,然后执行这个被绑定的某某某(某01),或者单纯就是绑定不执行。
详解
从前端必备网站 MDN 上我们可以得知以上三种方法的完全体。
Function.prototype.apply(thisArg , argsArray); //apply方法
Function.prototype.call(thisArg , ...args); //call方法
Function.prototype.bind(thisArg , ...args); //bind方法
然后我们来分别看看这三个方法的例子,首先是call,我把它放在第一个讲,因为我觉得它很有代表性。
Call方法
function Product(name, price) {
this.name = name;
this.price = price;
}
function Food(name, price) {
//这里调用了call方法
Product.call(this, name, price);
this.category = 'food';
}
console.log(new Food('cheese', 5).name);
// Expected output: "cheese"
第一眼看上去,这个方法到底是啥?怎么这么难理解?它到底做了什么?
解析
我们不考虑MDN对这个方法参数的专业解释,来用我们自己的语言描述这个方法。
下面给出我们在上面代码块中调用call方法的部分。
Product.call(this, name, price);
这句代码到底做了什么事情,首先我们从它的this入手,有这样一句话
构造函数中this指向对象实例
所以this指向的,就是function Food(...)
构造方法的实例,call方法的第一个参数是谁我们就找到了。
接下来是call方法的第二个参数,注意call方法的完全体的第二个参数名字为 “argsArray” ,这个名字的意思是什么?参数数组,对了,所以 “name” 和 “price” 应该有一个统一的名称,参数数组中的参数。
现在我们解释了代码块中调用call方法部分的两个参数,那么,接下来的问题是call方法利用这两个参数做了什么事情呢?
我们再把call方法的完全体拿过来看一看。
Function.prototype.apply(thisArg , argsArray);
除去原型链(prototype)部分,这个方法写为 Function.apply(thisArg , argsArray);
Function,Function是谁?在代码块中调用call方法部分中,Function是Product,call方法会把参数传给Product。
注意,call方法一旦调用就立即执行对应的Function。
经过上面的讨论我们基本上分析完了,下面给出我们的通俗理解。
“我们将Product构造方法,绑定给了Food构造方法,并将Product构造方法的this指向Food构造方法的实例。也就是说我们执行Food构造方法时调用Product构造方法,这个调用是Product构造方法的内容在Food构造方法的内部调用”
那这样说我直接在Food构造方法中调用Product构造方法就好了,为什么要用到call方法?
(这么问的话说明你还没有理解我上面的这段话,我给个例子)
我们把这句话翻译成代码。
function Food(name, price) {
Product(name, price);
this.category = 'food';
}
把我们的通俗理解翻译成代码如下
function Food(name, price) {
//Product.call(this, name, price);和下面代码等价
this.name = name;
this.price = price;
...
}
看出区别了吗?两个代码块调用this的指向是不同的,Product(name, price);
方法的this指向Product构造方法的实例,而后者代码块的this指向Food构造方法的实例。这样就使得console.log(new Food('cheese', 5).name);
运行时,呈现两种完全不同的结果。
后者代码块的new Food('cheese', 5)
运行时会将参数直接传给Product(name, price);
然后呢?然后就没有了!Product(name, price);
将参数传给了Product构造方法,而Product构造方法的this指向他自己的实例,赋值当然也会赋给它自己的实例。
这里附上Product构造方法的代码。
function Product(name, price) {
this.name = name;//赋值
this.price = price;//赋值
}
所以当运行new Food('cheese', 5).name
时,返回的值是undefined,因为new Food('cheese', 5)
产生的实例中,根本不含有name和price属性!
因此,想让name和price的值赋给Food构造方法的实例,必须改变Product构造方法中this的指向,让Product构造方法的this指向Food构造方法的实例才行。
call方法就为我们做了这件事,这也是call方法第一个参数的意义所在。
bind方法
const module = {
x: 42,
getX: function () {
return this.x;
},
};
const unboundGetX = module.getX;
console.log(unboundGetX()); // The function gets invoked at the global scope
// Expected output: undefined
const boundGetX = unboundGetX.bind(module);
console.log(boundGetX());
// Expected output: 42
经过call方法的磨练,想必理解上述代码十分简单,但是要注意一件事情,即bind方法调用后,它对应的Function不会立即执行,要等我们去调用才执行。
apply方法
const numbers = [5, 6, 2, 3, 7];
const max = Math.max.apply(null, numbers);
console.log(max);
// Expected output: 7
const min = Math.min.apply(null, numbers);
console.log(min);
// Expected output: 2
这里也不给出具体的解析了,同理call方法即可。注意,apply方法调用后,它对应的Function会立即执行。
标签:Product,name,构造方法,Food,price,JavaScript,call,apply From: https://www.cnblogs.com/sumuwen/p/17935853.html