Open hifizz opened 5 years ago
假设现在有这么一个构造函数:
function BOOM(name, age) {
this.name = name;
this.age = age;
return this;
}
BOOM.prototype.say = function() {
console.log(`Name: ${this.name} ; age: ${this.age}`);
}
const boom = new BOOM("stackfizz", 25)
boom.say();
现在控制台执行以下我们能够看到:
要创建 BOOM 的新实例,必须使用 new 操作符。以new 运算符调用构造函数实际上会经历以下 4 个步骤:
基于上面的描述,我们可以自己构造一个函数来实现new的操作:
function newer(_class_, ...argus) {
const newObj = {};
newObj.__proto__ = _class_.prototype;
return _class_.call(newObj, ...argus);
}
我们来调用它:
const boom1 = newer(BOOM, "stackfizz", 25)
boom1.say();
Bingo!我们实现了它:)
上面的例子有一个BOOM构造函数,我们使用了prototype
来指定say方法
function BOOM(name, age) {
this.name = name;
this.age = age;
return this;
}
BOOM.prototype.say = function() {
console.log(`Name: ${this.name} ; age: ${this.age}`);
}
const boom = new BOOM("stackfizz", 25)
boom.say();
我们来看看boom的实例到底是什么东西?
哦,会发现 boom 是没有 prototype
属性的。没错!
其实呀,关于 __proto__
prototype
只要记住两点就OK了!
1. proto是每个对象都有的一个属性,而prototype是函数才会有的属性。
2. proto指向的是当前对象的原型对象,而prototype指向的,是以当前函数作为构造函数构造出来的对象的原型对象
function foo(boo) {
console.log(this.bar);
console.log("hello");
console.log(boo);
return 42;
}
console.log(foo.call());
console.log("------------");
console.log(foo.call({bar: "stackfizz"}, "fizz"));
console.log("------------");
console.log(foo.apply(this));
console.log("------------");
console.log(foo.apply({bar: "stackfizz"}, ["fizz"]));
console.log("------------");
function bind(func, target) {
return function (...argus) {
return func.call(target, ...argus)
}
}
const bindedFoo = bind(foo, {bar: "stackfizz"});
const bindedFoo2 = bind(foo, {bar: "222222"});
const bindedFoo3 = bind(foo, {bar: "333333"});
console.log(bindedFoo("fizz"));
console.log("------------");
function binding(target) {
const func = this;
return function (...argus) {
return func.call(target, ...argus)
}
}
const bindingFoo = binding.call(foo, {bar: "stackfizz"});
console.log(bindingFoo("fizz"));
foo.__proto__.binding = binding;
const bindedFooFunc = foo.binding({bar: "stackfizz"})
console.log(bindedFooFunc("fizz"));
console.log("------bindingFoo------");
function newer(_class_, ...argus) {
const newObj = {};
newObj.__proto__ = _class_.prototype;
return _class_.call(newObj, ...argus);
}
function BOOM(name, age) {
this.name = name;
this.age = age;
return this;
}
// BOOM.prototype.say = () => {
// console.log(`Name: ${this.name} ; age: ${this.age}`);
// }
BOOM.prototype.say = function() {
console.log(`Name: ${this.name} ; age: ${this.age}`);
}
console.log(BOOM.prototype.constructor === BOOM);
const boom = new BOOM("stackfizz", 25)
boom.say();
const boom1 = newer(BOOM, "stackfizz", 25)
boom1.__proto__.sing = function() {
console.log(`${this.name} sings song`);
}
boom1.say();
boom1.sing();
boom.sing();
boom.__proto__.high = function() {
console.log("high");
}
boom1.high();
boom.high();
function PUMB() {}
call 和 apply
call
假设有以下函数:
我们可以直接调用:
也可以用call()
看见结果了吗?你可以直接在foo后面加两个()
foo()
进行调用foo函数,也可以直接在调用foo的方法callfoo.call()
进行调用foo函数,他们的结果完全一模一样!我们再来看看call函数的函数签名:
现在我们调用call的时候传入想要的值
OK,我们改变了 this的指向。call就是用来改变函数执行时this指向的方法。
apply
call 和 apply 不同的地方在于apply的第二个参数只能是数组。这一点我们可以从函数签名上看出来。
实例测试一下:
bind
先看函数签名
现在我们来实现一把bind函数,用👆说过的call和apply
当然,目前的实现我们还只能是传入要绑定的函数,我们可以使用上面学过的call和apply来修改一下:
当然,这样还是不够的,我们期望直接以这样的方式调用:
OK, 那么就来实现一下吧,很简单:
Bingo!