call,apply,bind是JS里面的改变作用域的三种方式,区别很明显,call参数是一个个穿进去的,apply的参数是数组,bind跟call,apply不同的是,bind绑定对象后,没有立即执行,前面的两个有执行。
下面来实现自己的call,apply,bind
call的自定义实现
function a(){
console.log(arguments)
}
var b = {
name: 'gaofeng'
}
很显然b对象是不能调用a方法的,那非要强制调用a方法呢,我们可以
a.call(b) //{}
a.call(b,1,2,3,4) //{ '0': 1, '1': 2, '2': 3, '3': 4 }
其他的两个也可以实现,但不是这次要记录的重点。下面封装自己的call,apply,bind方法
Function.prototype.myCall = function (contxt) {
//this 这里的this,我们要明白指的是谁,原型方法里的this,指的是实例,是我们new出来的对象
//比如a.myCall(b)现在的this指代的是a对象
if(typeof this !== 'function'){
throw new Errow('not a function')
}
console.log(this) //[Function: a]
}
a.myCall(b)
现在的思路是在myCall里面调用a,然后把结果返回出来
Function.prototype.myCall = function (contxt) {
//this 这里的this,我们要明白指的是谁,原型方法里的this,指的是实例,是我们new出来的对象
//比如a.myCall(b)现在的this指代的是a对象,记住函数也是对象
if(typeof this !== 'function'){
throw new Errow('not a function')
}
console.log(this)
contxt = contxt || window;
var args = [...arguments]; //方法要接收的参数
var self = this; // 我们要调用的方法名
var res = this(...args);
return res;
}
a.myCall(b,123,456)
//{ '0': { name: 'gaofeng' }, '1': 123, '2': 456 }
另一种方法
Function.prototype.myCall = function (contxt = window) {
if(typeof this !== 'function'){
throw new Errow("not a function")
}
contxt.fn = this; //上下文对象上添加一个属性指向this;
var args = [...arguments].slice(1);
var res = contxt.fn(...args);
return res;
}
function a(){
console.log(arguments)
}
var b = {
name: 'gaofeng'
}
a.myCall(b) //{ '0': { name: 'gaofeng', fn: [Function: a] }}
可以看到答应的对象里面多出了一个fn属性,这不是我们想要的,所以要删掉
Function.prototype.myCall = function (contxt = window) {
if(typeof this !== 'function'){
throw new Errow("not a function")
}
contxt.fn = this; //上下文对象上添加一个属性指向this;
var args = [...arguments].slice(1);
var res = contxt.fn(...args);
delete contxt.fn
return res;
}
function a(){
console.log(arguments)
}
var b = {
name: 'gaofeng'
}
a.myCall(b,1,2) //{ '0': 1, '1': 2 }
也实现了需求。
2.apply,与call方法的区别是参数的传递方式不一样
Function.prototype.myApply = function (contxt = window) {
if (typeof this !== 'function') {
throw new Error('not a function')
}
var args = arguments[1];
var self = this;
var res;
if (args) {
res = this(...args
)
} else {
res = self();
}
}
function a(){
console.log(arguments)
}
var b = {
name: 'gaofeng'
}
a.myApply(b,[1,2,3,4,5]) //{ '0': 1, '1': 2, '2': 3, '3': 4, '4': 5 }
另外一种实现方式
Function.prototype.myApply = function (contxt) {
if(typeof this !== 'function'){
throw new Error('not a function')
}
contxt = contxt || window;
let res,args=arguments[1];
contxt.fn = this;
if(args){
res - contxt.fn(...args)
}else{
res = contxt.fn();
}
delete contxt.fn;
}
function a(){
console.log(arguments)
}
var b = {
name: 'gaofeng'
}
a.myApply(b,[1,2,3,4,5]) //{ '0': 1, '1': 2, '2': 3, '3': 4, '4': 5 }
3.bind的实现
Function.prototype.myBind = function (contxt) {
if(typeof this !== 'function'){
throw new Errow('not a function')
}
let _this = this; // 当前实例指的是a
let args = [...arguments].slice(1); //这里是myBind函数的参数
return function F(){
if(this instanceof F){ //这里我们可以使用new方法来调用
return new _this(...args,...arguments)
}else{
return _this.apply(contxt,args.concat(...arguments))
}
}
}
function a(){
console.log(arguments)
}
var b = {
name: 'gaofeng'
}
var b = a.myBind(b,'a','b')(1,2,3,4) //{ '0': 'a', '1': 'b', '2': 1, '3': 2, '4': 3,
'5': 4 }
var c = a.myBind(b,'a')
var c1 = new c('1',2)
console.log(c1)
//{ '0': 'a', '1': '1', '2': 2 }
//a {}
4.instanceof
function instanceOf(left, right) {
let leftValue = left.__proto__
let rightValue = right.prototype
while (true) {
if (leftValue === null) {
return false
}
if (leftValue === rightValue) {
return true
}
leftValue = leftValue.__proto__
}
}
function A(){
}
var a = new A()
var b = {}
console.log(instanceOf(a,A)) //true
console.log(instanceOf(b,A)) //false
5.object.create()方法的实现
function create(obj){
function F(){}
F.prototype = obj;
return new F();
}
var d = {c:1}
var a = create(d)
console.log(a.c);
a.c = 2;
console.log(a.c);
console.log(d.c)
6.实现new
function myNew(fun){
return function (){
let obj = {
__proto__:fun.prototype
}
fun.call(obj,...arguments)
return obj;
}
}
function person(name,age){
this.name = name;
this.age =age;
}
let obj = myNew(person)('gaofeng',20)
console.log(obj)
简易版的promise
class MyPromise{
constructor(fn){
this.state = 'pending';
this.value = undefined;
this.reason = undefined;
let resolve = value => {
if(this.state === 'pending'){
this.state = 'fulfilled';
this.value = value
}
}
let reject = value => {
if(this.state === 'pending'){
this.state = 'rejected';
this.reason = value;
}
}
try{
fn(resolve,reject);
}catch(e){
reject(e)
}
}
then(onFulfilled,onRejected){
switch(this.state){
case 'fulfilled':
onFulfilled();
break;
case 'rejected':
onRejected();
break;
default:
}
}
}
new MyPromise((resolve,reject) => {
resolve('dddd')
})