手写 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() 方法
