Open Abiel1024 opened 6 years ago
你好,你的 apply 实现代码有问题。
apply实现:
Function.prototype.newApply = function(context, parameter) {
if (typeof context === 'object') {
context = context || window
} else {
context = Object.create(null)
}
let fn = Symbol()
context[fn] = this
context[fn](parameter); // 应该加上扩展运算符
delete context[fn]
}
@Lamborshea 已修正 谢谢~
感谢分享
@zhangyuexin 不客气
看了之后很喜欢,然后自己对 call 的最后实现稍微做了修改,欢迎各位也能指点指点。
Function.prototype.newCall = function (context, ...args) {
if (context === null || context === undefined) {
context = window;
} else {
context = Object(context);
}
let fn = Symbol();
context[fn] = this;
context[fn](...args);
delete context[fn];
};
let person = {
name: "Jim"
};
function sayHi(age, sex) {
console.log(this.name, age, sex, this);
}
sayHi.newCall(person, 25, "male");
看了之后很喜欢,然后自己对 call 的最后实现稍微做了修改,欢迎各位也能指点指点。
Function.prototype.newCall = function (context, ...args) { if (context === null || context === undefined) { context = window; } else { context = Object(context); } let fn = Symbol(); context[fn] = this; context[fn](...args); delete context[fn]; }; let person = { name: "Jim" }; function sayHi(age, sex) { console.log(this.name, age, sex, this); } sayHi.newCall(person, 25, "male");
我同意这个 传入null this直线window
我自己对bind做了一下修改
Function.prototype._bind = function (ctx) {
const origin = this;
const Mid = function () {};
const args = [].slice.call(arguments, 1);
const newFn = function () {
const args1 = [...arguments].concat(args);
return origin.apply(this instanceof newFn ? this : ctx, args1);
};
Mid.prototype = this.prototype;
newFn.prototype = new Mid();
return newFn;
};
Function.prototype.myBind = function (context, ...args) {
let self = this
function fn(...args) {
context.fun = self
context.fun(...args)
}
return function () {
return fn(...args)
}
}
同意 @samualle 的观点,因为作者写的代码当传入 undefined
时 this
应该指向 window
,而作者的代码 this
指向了一个对象。
下面是我的实现
Function.prototype.fakeCall = function(target, ...params) {
if (target == null) {// undefined || null
target = window
} else if (typeof target !== 'object') {
target = Object.create(null)
}
const key = Symbol()
target[key] = this
target[key](...params)
delete target[key]
}
因为关乎到了this指向的问题,call、apply和bind的用法可以说是老生常谈了。这篇文章的主要作用是利用js原生方法对三个方法进行实现,升入了解其中的原理,对相关知识点有更好的掌握。
call与apply
简单介绍:call和apply方法都是使用一个指定的this值和对应的参数前提下调用某个函数或方法。区别则在于call是通过传多个参数的方式,而apply则是传入一个数组。 举个例子:
模拟实现
思路:在JavaScript中的this指向说到了:函数还可以作为某个对象的方法调用,这时this就指这个上级对象。也就是我们平时说的,谁调用,this就指向谁。所以实现的方法就是在传入的对象中添加这么一个方法,然后再去执行这个方法。为了保持对象一直,在执行完之后再把这个对象给删除了。是不是很简单^-^。 初体验:
这样就完成了基础版本的实现,但是如果说有传参数呢? 所以我们可以进行优化一下,因为传入的参数数量是不确定的,所以我们可以从Arguments对象中去获取,这个比较简单。问题是参数是不确定的,我们如何传入到我们要执行的函数中去呢 ? 这里我们有两种选择:一种是通过eval拼接的方式,另一种就要用到es6了。 体验升级(eval版本):
体验升级(ES6版本):
让然ES6的方法还可以不用到arguments就能实现 ES6版本再升级:
这样我们基本上实现了call的功能,但是还是存在一些隐患和区别。 当对象本身就有fn这个方法的时候,就有大问题了。 当call传入的对象是null的时候,或者其他一些类型的时候,函数会报错。 终极体验:
实现了call之后,apply也是同样的思路。 apply实现:
bind
bind也是函数的方法,作用也是改变this执行,同时也是能传多个参数。与call和apply不同的是bind方法不会立即执行,而是返回一个改变上下文this指向后的函数,原函数并没有被改变。并且如果函数本身是一个绑定了 this 对象的函数,那 apply 和 call 不会像预期那样执行。 初体验:
加入参数: