new
分析:
通过new方法生成实例的原理:
1、产生了一个新的实例对象。
2、通过改变this的指向继承构造函数的属性和方法。
3、继承了原型链上的属性和方法。新对象的__proto__指向构造函数的prototype。
用代码来实现:
function myNew(fun) {
return function() {
let obj = {
__proto__: fun.prototype
};
fun.apply(obj, arguments);
return obj
}
}
改进版:
function myNew() {
var obj = new Object(),
constructor = [].shift.call(arguments);
obj.__proto__ = constructor.prototype;
var ret = constructor.apply(obj, arguments);
return typeof ret === 'object' ? ret : obj;
};
bind
bind是Function中的原型方法。
它的原理:
1、改变this的指向。
2、将函数柯里化,传入参数会保存直到参数传入完毕。
代码实现:
Function.prototype.bind = function(newThis) {
var aArgs = Array.prototype.slice.call(arguments, 1)
var that = this
var NoFunc = function () {}
var resultFunc = function () {
return that.apply(this instanceof that ? this : newThis, aArgs.concat(Array.prototype.slice.call(arguments)))
}
NoFunc.prototype = that.prototype
resultFunc.prototype = new NoFunc()
return resultFunc
}
aArgs.concat(Array.prototype.slice.call(arguments))
表示参数拼接,curring化实现
这段代码的作用是判断调用func()时的执行环境;直接调用func()的时候,this指向的是全局对象;如果是通过构造函数调用的话,this指向改变。this instanceof that ? this : newThis
NoFunc.prototype = that.prototype; resultFunc.prototype = new NoFunc();
相当于将得到的新对象的原型指向原对象,如果直接用‘resultFunc.prototype=that.prototype’的话会使得新对象能直接修改原型链属性,造成原型链污染。
MDN上的polyfill:
if (!Function.prototype.bind) { Function.prototype.bind = function(oThis) { if (typeof this !== 'function') { // closest thing possible to the ECMAScript 5 // internal IsCallable function throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable'); } var aArgs = Array.prototype.slice.call(arguments, 1), fToBind = this, fNOP = function() {}, fBound = function() { // this instanceof fNOP === true时,说明返回的fBound被当做new的构造函数调用 return fToBind.apply(this instanceof fNOP ? this : oThis, // 获取调用时(fBound)的传参.bind 返回的函数入参往往是这么传递的 aArgs.concat(Array.prototype.slice.call(arguments))); }; // 维护原型关系 if (this.prototype) { // Function.prototype doesn't have a prototype property fNOP.prototype = this.prototype; } // 下行的代码使fBound.prototype是fNOP的实例,因此 // 返回的fBound若作为new的构造函数,new生成的新对象作为this传入fBound,新对象的__proto__就是fNOP的实例 fBound.prototype = new fNOP(); return fBound; }; }
call和apply
call和apply的原理:
1.Call和apply中的对象调用了当前对象,this指向改变.
2.执行.
代码实现:
Function.prototype.myCall=function(toCall){
toCall.fn=this;
let args=[];
let len=arguments.length;
for(let i=0;i<len;i++){
args.push(arguments[i])
}
var res=eval('toCall.fn('+args+')');
delete toCall.fn;
return res;
}
原理:
1.将函数设为对象的属性
2.执行该函数
3.删除该函数
apply:
Function.prototype.apply = function (context, arr) {
var context = Object(context) || window;
context.fn = this;
var result;
if (!arr) {
result = context.fn();
}
else {
var args = [];
for (var i = 0, len = arr.length; i < len; i++) {
args.push('arr[' + i + ']');
}
result = eval('context.fn(' + args + ')')
}
delete context.fn
return result;
}