记录一个知识点,共勉。
1. call 的简单使用
在使用 call 方法是注意以下两点:
- foo 函数本身执行了
- call 改变了函数 foo 中 this 的指向,该例指向到 obj
var obj = {
value: 1
}
function foo() {
console.log(this.value)
}
foo.call(obj) // 1
复制代码
2. 模拟实现原理
var obj = {
value: 1,
foo: function() {
console.log(this.value)
}
}
// 此时调用 obj.foo 也可以打印出 value 的值
复制代码
因而得到模拟的原理:
1. 给对象 obj 赋值函数 foo
2. 调用这个函数
3. 调用完后删除这个函数
obj.fn = foo
obj.fn()
delete obj.fn
复制代码
3. 第一步
Function.prototype.call2 = function (context) {
context.fn = this
context.fn()
delete context.fn
}
// 使用
var obj = {
value: 1
}
function foo() {
console.log(this.value)
}
foo.call2(obj) // 1
复制代码
4. 第二步
call 方法可接收不定量参数
1. 在函数内部使用 arguments 可得到参数类数组
2. 使用 eval 执行函数解决参数传递问题,内部会自动调用 Array.toString()
Function.prototype.call2 = function (context) {
context.fn = this
const args = []
for(var i = 1, len = arguments.length; i < len; i++) {
args.push('arguments[' + i + ']');
}
eval('context.fn(' + args + ')')
delete context.fn
}
// 使用
var obj = {
value: 1
}
function foo(name, age) {
console.log(name)
console.log(age)
console.log(this.value)
}
foo.call2(obj, 'Tom', 18)
// Tom
// 18
// 1
复制代码
5. 第三步
1. call 方法第一个参数可以传 null,此时 this 指向 window
2. 第一个参数也可以传常量,使用 Object 包一层
Function.prototype.call2 = function (context) {
var context = context || window
context.fn = this
const args = []
for(var i = 1, len = arguments.length; i < len; i++) {
args.push('arguments[' + i + ']');
}
eval('context.fn(' + args + ')')
delete context.fn
}
复制代码
6. 第四步
call 方法可以拥有返回值
Function.prototype.call2 = function (context) {
var context = context || window
context.fn = this
const args = []
for(var i = 1, len = arguments.length; i < len; i++) {
args.push('arguments[' + i + ']');
}
var res = eval('context.fn(' + args + ')')
delete context.fn
return res
}
var obj = {
value: 1
}
function foo(name, age) {
return {
name, age, val: this.value
}
}
console.log(foo.call(obj, 'Tom', 18))
// Object {
// name: 'Tom',
// age: 18,
// value: 1,
// }
复制代码
7. apply 方法的模拟实现
apply 的实现与 call 类似,唯一区别是 apply 接收的参数以数组的方式传入
Function.prototype.apply2 = function (context, arr) {
var context = context || window
context.fn = this
var res
if (!arr) {
res = context.fn()
} else {
var args = []
for(var i = 1, len = arguments.length; i < len; i++) {
args.push('arguments[' + i + ']');
}
res = eval('context.fn(' + args + ')')
}
delete context.fn
return res
}
复制代码
最后
这里只是简单的模拟实现,其中还有很多细节可以完善,例如对参数的类型判断,写法的优化等