1、手写new
function Student (name, age){
this.name = name;
this.age = age;
}
Student.prototype.like = function () {
console.log('读书');
}
function MyNew(){
const obj = Object.create({});
const [constructor, ...args] = [...arguments];
obj.__proto__ = constructor.prototype;
const result= constructor.apply(obj, args); // 判断构造函数是否存在返回值
if (result && ( typeof (result) == "object") || typeof(result) == "function") {
return result;
}
return obj;
}
var myName = MyNew(Student , '张三', 46)
console.log(myName.name) // 张三
console.log(myName.age) // 46
myName.like() // 读书
上面代码解释
1、创建一个新的对象,并返回。
2、截取传入MyNew函数的第一个参数, 其实就是创建构造函数。
3、将第一个参数的prototype与要返回的对象建立关联。
4、使用apply,改变构造函数的this指向,使其指向新对象,这样,obj就可以访问到构造函数中的属性了。
5、构造函数如果return 出一个对象或函数,那么new 实例,只能访问到 这个对象属性,所以判断一下
2、手写call
Function.prototype.myCall = function (context) {
// 判断有没有传进来对象, 没有默认就是 windows
context= context ? Object(context) : windows;
// 属性唯一 , 防止属性名冲突
var fn = Symbol();
context[fn] = this;
const args = [...arguments].slice(1);
// call 参数是字符串 所以需要 ... 运算符
const result = context[fn](...arg);
delete context[fn];
return result;
}
var obj = {
name: "张三"
};
function person (sex, weight) {
console.log(this.name, sex, weight);
}
person.myCall(obj, '李四', 18);
3、手写 apply
Function.prototype.myApply= function(context, arr) {
context = context ? Object(context) : window;
let fn = Symbol();
context[fn] = this;
// 参数有没有
let result = arr ? context[fn](...arr) : context[fn]();
delete context[fn];
return result;
};
4、手写 bind
Function.prototype.bind2 = function(context) {
if (typeof this !== "function") {
throw new Error(
"Function.prototype.bind - what is trying to be bound is not callable"
);
}
var self = this;
var args = Array.prototype.slice.call(arguments, 1);
var fBound = function() {
// 接收 额外 的参数
var innerArgs = Array.prototype.slice.call(arguments);
// 当 被 new 时, this 指向当前 实例, 不再指向 绑定的 对象
return self.apply(
this instanceof fNOP ? this : context,
args.concat(innerArgs)
);
};
// 绑定原型 , 当 返回的 fBound 被当初 构造函数, 其实就是 被调用的函数当作 构造函数, 所以 返回的函数要 继承 被调用函数的 原型
var fNOP = function() {};
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
return fBound;
};
使用
function foo(name) {
this.name = name;
}
var obj = {};
var bar = foo.myBind(obj);
bar('Jack');
console.log(obj.name); // Jack
// new bar 其实就是 new foo
var alice = new bar('Alice');
console.log(obj.name); // Jack
console.log(alice.name);