-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
1.手写call和apply #1
Comments
|
手写call本人比较懒,讲解都写在注释里
第一版Function.prototype.myCall1 = function (obj, ...args) {
const fn = this;
if (typeof fn !== "function") {
throw new Error("输入一个函数啊!");
}
const key = Symbol(); // 一般题解是obj.fn = fn,但为了避免这个obj里真的有fn这个属性,用Symbol会比较安全
obj[key] = fn;
const res = obj[key](...args);
delete obj[key];
return res;
};
// 普通情况
function foo() {
console.log(this);
}
const obj = {
name: "hhh",
};
foo.call(obj); // { name: 'hhh' }
// 特殊情况,测试第一个兜底
obj.__proto__ = Function.prototype;
obj.myCall1(); // Error: 输入一个函数啊! 第二版// 情况2,不输入参数,默认指向window,node指向globalThis
Function.prototype.myCall2 = function (obj, ...args) {
const fn = this;
if (typeof fn !== "function") {
throw new Error("输入一个函数啊!");
}
// let defaultThis = null;
// try {
// defaultThis = window; // 因为node环境没有window,所以执行这步的时候会报错
// } catch {
// defaultThis = globalThis;
// }
// obj = obj || defaultThis;
// 经提醒,window中globalThis就是window
obj = obj || globalThis;
const key = Symbol(); // 一般题解是obj.fn = fn,但为了避免这个obj里真的有fn这个属性,用Symbol会比较安全
obj[key] = fn;
const res = obj[key](...args);
delete obj[key];
return res;
};
foo.myCall2(); |
Function.prototype.myCall = function (context, ...args) {
let ctx = context || globalThis;
const fn = this;
if (typeof fn !== 'function') {
throw new Error('this is not a function');
}
let key = Symbol();
ctx[key] = fn;
const res = ctx[key](...args);
delete ctx[key];
return res;
};
function foo() {
console.log(this.name);
}
const obj = {
name: 'xys'
};
foo.myCall(obj);
var name = 'xys2';
foo.myCall(); |
手写 call测试案例: // 测试 1
var foo1 = {
value: 1,
};
function bar1() {
console.log(this.value);
}
console.log('测试1');
bar1.myCall(foo1);
// 测试 2
var foo2 = {
value: 1,
};
function bar2(name, age) {
console.log(name);
console.log(age);
console.log(this.value);
}
console.log('测试2');
bar2.myCall(foo2, 'kevin', 18);
// 测试 3
var value3 = 1;
function bar3() {
console.log(this.value3);
}
console.log('测试3');
bar3.myCall(null);
// 测试 4
var obj4 = {
value: 1,
};
function bar4(name, age) {
return {
value: this.value,
name: name,
age: age,
};
}
console.log('测试4');
console.log(bar4.myCall(obj4, 'kevin', 18));
// 测试 5
function foo5() {
console.log(this);
}
var obj5 = {
name: 'kevin'
}
obj5.__proto__ = Function.prototype;
obj5.myCall(); 实现: Function.prototype.myCall = function (context) {
if(typeof this !== 'function') {
throw new TypeError('this is not a function');
}
// 兼容 context 为 null 的情况
// window 中 globalThis 指向 window,node 指向 globalThis
context = context || globalThis;
// 防止污染 context 内部属性
const fn = Symbol("fn");
context[fn] = this;
// 获取参数,这里是 ES3 的实现方式,也可以用 ES6 的拓展运算符传参 context[fn](...[...arguments].slice(1))
var args = [];
for (var i = 1, len = arguments.length; i < len; ++i) {
args.push("arguments[" + i + "]");
}
var result = eval("context[fn](" + args + ")");
delete context[fn];
return result;
}; |
手写 apply测试案例: // 测试 1
var foo1 = {
value: 1,
};
function bar1() {
console.log(this.value);
}
console.log("测试1");
bar1.myApply(foo1);
// 测试 2
var foo2 = {
value: 1,
};
function bar2(name, age) {
console.log(name);
console.log(age);
console.log(this.value);
}
console.log("测试2");
bar2.myApply(foo2, ["kevin", 18]);
// 测试 3
var value3 = 1;
function bar3() {
console.log(this.value3);
}
console.log("测试3");
bar3.myApply(null);
// 测试 4
var obj4 = {
value: 1,
};
function bar4(name, age) {
return {
value: this.value,
name: name,
age: age,
};
}
console.log("测试4");
console.log(bar4.myApply(obj4, ["kevin", 18]));
// 测试 5
function foo5() {
console.log(this);
}
var obj5 = {
name: 'kevin'
}
obj5.__proto__ = Function.prototype;
obj5.myApply(); 实现: Function.prototype.myApply = function (context, arr) {
if (typeof this !== "function") {
throw new TypeError('this is not a function');
}
// 兼容 context 为 null 的情况
context = context || globalThis;
// 防止污染 context 内部属性
const fn = Symbol("fn");
context[fn] = this;
// 获取参数,这里是 ES3 的实现方式,也可以用 ES6 的拓展运算符传参 context[fn](...[...arguments].slice(1))
var args = [];
if (!arr || !arr.length) {
var result = context[fn]();
} else {
for (var i = 0, len = arr.length; i < len; ++i) {
args.push("arr[" + i + "]");
}
var result = eval("context[fn](" + args + ")");
}
delete context[fn];
return result;
}; |
手写 callFunction.prototype.myCall = function (context, ...args) {
if (typeof this !== 'function') throw Error('type error')
context = context || window
const fn = Symbol('fn')
context[fn] = this
let res = context[fn](...args)
delete context[fn]
return res
}
// 案例
var obj = {
name: 'obj'
}
function sayName(...rest) {
console.log(this.name, ...rest)
}
sayName.myCall(obj, 123, 321) // obj 123 321 手写 applyFunction.prototype.myApply = function (context, args) {
if (typeof this !== 'function') throw Error('type error')
context = context || window
const fn = Symbol('fn')
context[fn] = this
let res = context[fn](args)
delete context[fn]
return res
}
// 案例
var obj = {
name: 'obj'
}
function sayName(arr) {
console.log(this.name, arr)
}
sayName.myApply(obj, [123, 321]) // obj [123,321] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
先来一篇精彩的文章镇一下场子:mqyqingfeng/Blog#11
call的场景是什么呢?每次写一个api,肯定得先知道他的用途才可以。
一句话介绍calll:call() 方法在使用一个指定的 this 值和”若干个“指定的参数值的前提下调用某个函数或方法。
注意两点:
那我们来看看 这个call自己能怎么模拟出来吧~
思路:
The text was updated successfully, but these errors were encountered: