手写 call、apply 及 bind 函数
call
Function.prototype.Dcall = function (context) {
if (typeof this !== "function") {
throw new TypeError("Error");
}
var context = context || window;
context.say = this;
var args = [];
for (let i = 1; i < arguments.length; i++) {
args.push("arguments[" + i + "]");
}
var result = eval("context.say(" + args + ")");
delete context.say;
return result;
};
apply
Function.prototype.Dapply = function (context, arr) {
if (typeof this !== "function") {
throw new TypeError("Error");
}
var context = context || window;
var result;
context.fn = this;
if (!arr) {
result = context.fn();
} else {
var args = [];
for (let i = 0; i < arr.length; i++) {
args.push("arr[" + i + "]");
}
result = eval("context.fn(" + args + ")");
}
return result;
};
bind
Function.prototype.Dbind = function (context) {
if (typeof this !== "function") {
throw new TypeError("Error");
}
var self = this;
var args = Array.prototype.slice.call(arguments, 1);
return function () {
var bindArgs = Array.prototype.slice.call(arguments);
return self.apply(context, args.concat(bindArgs));
};
};
new
在调用 new 的过程中会发生以上四件事情:
- 新生成了一个对象
- 链接到原型
- 绑定
this
-
实现分析:
创建一个空对象
- 获取构造函数
- 设置空对象的原型
- 绑定
this
并执行构造函数 - 确保返回值为对象 ```javascript Function.prototype.Dnew = function (fn, …args) { var obj = Object.create(fn.prototype); var ret = fn.apply(obj, args); return ret instanceof Object ? ret : obj; };
// 或 Function.prototype.DDnew = function () { var obj = {}; var Constructor = Array.prototype.shift.call(arguments); obj.proto = Constructor.prototype; var result = Constructor.call(obj, arguments); return result instanceof Object ? result : obj; };
<a name="QT1J2"></a>
# instanceof
<a name="wRHDV"></a>
## 实现原理
就是只要右边变量的 prototype 在左边变量的原型链上即可。因此,instanceof 在查找的过程中会遍历左边变量的原型链,直到找到右边变量的 prototype,如果查找失败,则会返回 false,告诉我们左边变量并非是右边变量的实例。
```javascript
{
function new_instance_of(leftVaule, rightVaule) {
let rightProto = rightVaule.prototype;
leftVaule = leftVaule.__proto__;
while (true) {
if (leftVaule === null) return false;
if (leftVaule === rightProto) return true;
leftVaule = leftVaule.__proto__;
}
}
}
{
function new_instance_of(leftVaule, rightVaule) {
let proto = Object.getPrototypeOf(leftVaule);
while (true) {
if (proto == null) return false;
if (proto === rightVaule.prototype) return true;
proto = Object.getPrototypeOf(proto);
}
}
}
总结:
使用 typeof 来判断基本数据类型是 ok 的,不过需要注意当用 typeof 来判断 null 类型时的问题,如果想要判断一个对象的具体类型可以考虑用 instanceof,但是 instanceof 也可能判断不准确,比如一个数组,他可以被 instanceof 判断为 Object。所以我们要想比较准确的判断对象实例的类型时,可以采取 Object.prototype.toString.call() 方法