call()、apply()、bind()
那该多好 Lv2

call()

call()的使用方法

语法:function.call(thisObj, arg1, arg2, …)

说明:call() 方法可将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定的新对象。如果提供的thisObj参数为nullundefined时会自动替换为指向全局对象,原始值会被包装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function Class1(){
this.name = "class1";
this.showName = function(){
console.log(this.name);
}
}

function Class2(){
this.name = "class2";
}

var c1 = new Class1();
var c2 = new Class2();

c1.showNam.call(c2); //class2

call()的意思是把c1的方法放到c2上执行,原来c2是没有showName()方法的,现在把c1的showName方法放进c2里执行,所以this.name应该是class2,执行的结果就是’class2’;
call()方法实现继承

1
2
3
4
5
6
7
8
9
10
11
function Class1(){
this.showTxt = function(){
console.log(txt)
}
}
function Class2(){
Class1.call(this);
}

var c2 = new Class2()
c2.showTxt('cc')

这样Class2就继承Class1了,Class1.call(this)的意思就是使用Class1对象代替this对象,那么Class2中就可以有了Class1的所有属性和方法了,c2对象就能够直接调用Class1的方法及属性,执行结果就是console.log(‘cc’);
使用call()继承的弊端: 如果Class1后续向prototype添加了新的属性或方法,Class2拿不到新增的属性和方法

1
2
Class1.prototype.name = 'class1'
console.log(c2.name) // undefined

call()原理

js实现call

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function person(a, b, c, d) {
return {
name: this.name,
a: a, b: b, c: c, d: d
}
}
var yx = { name: 'yx' };

Function.prototype.newCall = function (obj, ...args) {
var obj = obj || window;
obj.p = this;
/**
* var result = obj.p(...args);
* */
var newArgs = [];
for (var i = 0; i < args.length; i++) {
newArgs.push('args[' + i + ']')
}
var result = eval('obj.p(' + newArgs + ')')
delete obj.p;
return result
}
var bib = person.newCall(yx, '1', '2', '3', '4')
console.log(bib);

apply()

apply()的使用方法

语法: function.apply(thisArg, [argArr])

说明: apply()方法与call()方法类似。也是改变this指向(函数执行时所在的作用域),然后在指定的作用域中,调用该函数,同时也会立即执行该函数。唯一的区别在于,apply()接受一个数组作为执行时的参数。

1
2
3
4
5
6
7
var obj = {
name:'yx'
};
function test(firstName,lastName){
console.log(firstName + ' ' + this.name + ' ' + lastName);
}
test.apply(obj,['a','b']) // a yx b

apply()原理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
function person(a,b,c,d){
return {
name: this.name,
a:a,b:b,c:c,d:d
}
}
var yx = {
name: 'yx'
}
Function.prototype.newApply = function(obj, arr){
var obj = obj || window, result;
obj.p = this;
if(!arr){
result = obj.p()
}else{
// result = obj.p(...arr)
var newArgs = [];
for(var i=0; i<arr.length; i++){
newArgs.push('arr['+ i +']')
}
result = eval('obj.p('+ newArgs +')')
}
delete obj.p
return result;
}
var res = person.newApply(yx,['a','b','c','d']);

bind()

bind()使用方法

语法: function.bind(thisArg, arg1, arg2, …)

说明:  bind()方法主要就是将函数绑定到某个对象,bind()会创建一个函数,函数体内的this对象的值会被绑定到传入bind()中的第一个参数的值,例如:f.bind(obj),实际上可以理解为obj.f(),这时f函数体内的this自然指向的是obj

1
2
3
4
5
6
7
8
9
10
this.num = 9;
var moduleA = {
num:81,
getNum (){ return this.name }
}
var getNum = moduleA.getNum
getNum() //9. 因为这个这例子中this 指向全局window

var boundGetNum = getNum.bind(moduleA)
boundGetNum(); //81

bind()原理

1
2
3
4
5
6
7
8
9
Function.prototype.newBind = function(){
const that = this;
var args = Array.prototype.slice.call(arguments);
var context = args.shift();
return function(){
var arrSum = args.concat([...arguments])
return that.apply(context, arrSum)
}
}
 评论