Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

2.手写new和bind #4

Open
webVueBlog opened this issue May 21, 2022 · 0 comments
Open

2.手写new和bind #4

webVueBlog opened this issue May 21, 2022 · 0 comments

Comments

@webVueBlog
Copy link
Owner

webVueBlog commented May 21, 2022

new 运算符:

运算符创建一个用户定义的对象类型的实例 或 具有构造函数的内置对象类型之一。

bind 函数:

方法会创建一个新函数,当这个新函数被调用时,bind()的第一个参数将作为它运行时的this,之后的一系列参数将会传递的实参前传入作为它的参数。

bind函数的特点:

  1. 改变this指向
  2. 第一个参数是this的值,后面的参数是函数接收的参数的值
  3. 返回值不变
// 手写bind
Function.prototype.myBind = function() {
 // 为了获取原函数
 const self = this;

 // 执行slice方法,其中的this指向arguments,得到真正的数组
 const args = Array.prototype.slice.call(arguments);

 // 拿到第一个参数
 const thisValue = args.shift();

 return function() {
  // 返回一个函数,它是一个匿名函数,整个匿名函数,就是保存在变量中的新的函数
  // 返回新函数里执行原函数
  return self.apply(thisValue, args);
 }
}

new原理:

  1. 创建空对象,作为将要返回的对象实例
  2. 指向原型,将这个空对象的原型,指向构造函数的prototype属性
  3. 绑定this,将这个空对象赋值给函数内部的this关键字
  4. 返回新对象,开始执行构造函数内部的代码
// 手写new
function myNew(fn, ...args) {
 // 定义个空对象
 const obj = {};

 // 隐式原型指向构造函数的显式原型
 obj.__proto__ = fn.prototype;

 // 执行构造函数,this指向空对象
 fn.apply(obj, args);

 // 返回对象
 return obj;
}
// new,创建实例,构造函数,剩余参数
const createInstance = (Constructor, ...args) => {
 // 创建对象,并指向构造函数的原型
 const obj = Object.create(Constructor.prototype);

 // 构造函数内部的 this 指向 instance 变量
 let res = Constructor.call(obj, ...args);

// 判断 是否是 函数或对象
const isObj = res !== null && typeof res === 'object';
const isFunc = typeof res === 'function';

 const isFunc || isObj ? res : obj;
}
// objectFactory
function objectFactory() {
 var object = new Object();
 var Constructor = Array.prototype.shift.call(arguments);
 // 原型式继承
 object.__proto__ = Constructor.prototype;
 // arguments第一个已经被shift,此时arguments是我们想要的参数
 var result = Constructor.apply(object, arguments);
 return typeof result === 'object'  ? result : object;
}

new的运行过程:

  1. 新建一个内部对象
  2. 给这个对象指定一个隐式原型链,对象的__proto__指向构造函数的prototype
  3. 指定对象的this
  4. 执行构造函数内部的代码
  5. 如果有返回值,就返回构造函数的返回值,否则就返回新建的对象
function objectFactory() {
 const constructor = [].shift.call(arguments)

 // 新建一个对象,并且将对象的隐式原型指定为构造函数的显示原型
 // 这样就能访问到构造函数的原型中的属性
 let newObject = Object.create(constructor.prototype);
 
 // apply将 this 指定为 newObject
 let res = constructor.apply(newObject, arguments);
 
 // 判断 构造函数 返回的值是否是对象
 return typeof res === 'object' ? res : newObject
}

模拟手写new

// new
function create(Con, ...args) {
 let obj = {}
 // Object.getPrototypeOf(obj) 相当于obj.__proto__
 Object.setProrotypeOf(obj, Con.prototype);
 let result = Con.apply(obj, args)
 return result instanceof Object ? result : obj
}

模拟手写bind

Function.prototype.myBind = function(context) {
 if(typeof this !== 'function') {
  throw new TypeError('Error');
 }
 var _this = this
 var args = [...arguments].slice(1)
 return function F() {
  if (this instanceof F) {
   // instanceof 返回true
  return new _this(...args, ...arguments);
  }
  return _this.apply(content, [...args, ...arguments])
 }
}

new关键字实现了什么

  1. this指向新创建的对象
  2. 对象的[[prototype]]属性指向构造函数的prototype
  3. 执行函数,返回一个新对象
  4. 如果函数没有返回对象类型Object,那么new表达式中的函数调用会自动返回这个新的对象
function objectFactory(func) {
 if(typeof func !== 'functio') {
   throw new Error('请传入一个函数')
 }

 let obj = Object.create(func.prototype);
 let args = [...arguments].slice(1);
 const result = func.apply(obj, args);
 
 let objectResult = typeof result === 'object' && result !== null;
 let funcResult = typeof result === 'function';

 return (objectResult || funcResult) ? result : obj;
}

bind实现了什么

  1. bind返回一个函数
  2. bind可以传入参数
  3. bindFunc返回的函数也可以传入参数
  4. this指向bindObjNew
Function.prototype.myBind = function(context) {
 if(typeof this !== 'function') {
  throw new Error('请输入一个函数');
 }
 let args = [...arguments].slice(1);
 let _this = this;

 let fBound = function() {
  let args2 = [...arguments];
  // return _this.apply(context, [...args, ...args2]);
 return _this.apply(this instanceof fBound ? this : context, [..args, ...args2])
 }
 return fBound; 
}

Bind函数实现:

  1. 返回一个函数
  2. 可以传入参数
Function.prototype.myBind = function(context) {
 if(typeof this != 'function') {
  throw new TypeError('error')
 }
 
 let _this = this
 // 函数剩余的参数
 let args = [...arguments].slice(1)

 return function F() {
  // 因为返回的是一个函数,所以可以 new F(),所以要进行判断
  if(this instanceof F) {
   return new _this(...args, ...arguments);
  }
  return _this.apply(context, args.concat(...arguments));
 }
}

New 实现:

  1. 创建了一个新对象
  2. 链接到原型
  3. 绑定到this
  4. 返回新对象
function objectFactory() {
 // 新创建一个对象
 let obj = {}
 
 // 取出构造函数
 constructor = [].shift.call(arguments);
 // 链接到原型
 obj.__proto__ = constructor.prototype;
 // 绑定到this
 constructor.apply(obj, arguments);
 // 返回新对象
 return obj;
}

new 关键字做了什么?

  1. 一个新的对象
  2. 新对象的__proto__指向构造函数的prototype
  3. 使用apply改变构造函数的this指向,使其指向新对象,这样一来obj就有构造函数里面的属性啦
  4. 判断构造函数是否有返回值,如果构造函数返回对象,则直接返回构造函数中的对象
  5. 返回新对象
function myNew() {
  let obj = new Object();
  let constrctor = Array.prototype.shift.call(arguments);
  obj.__proto__ = constrctor.prototype;
  let res = constrctor.apply(obj, arguments);
  return typeof res === "object" ? res : obj;
}

bind:

Function.prototype.Mybind = function (context) {
  if (typeof this !== "function") return "我们要函数才可以调用哦~";
  let myFn = this;

  // 当前调用传进来的参数
  let arg = Array.prototype.slice.call(arguments, 1);

  let fNOP = function () {};

  let fBound = function () {
    let bindArg = Array.prototype.slice.call(arguments);
    // 当函数作为构造函数时,this会指向他的实例fbound
    // 当函数作为普通函数的时候,this会指向window
    return myFn.apply(
      this instanceof fNOP ? this : context,
      bindArg.concat(arg)
    );
  };
  // 修改函数的原型指向this的原型 实例可以继承绑定函数的原型中的值,因为是引用类型~
  fBound.prototype = this.prototype;
  // 中转一下就不会修改到绑定函数的this啦
  fBound.prototype = new fNOP();
  return fBound;
};

new实践

Object.create = function(o) {
 function f() {}
 f.prototype = o
 return new f;
}
function objectFactory() {
 var obj = new Object(), // 从Object.prototype上克隆一个对象
 Constructor = [].shift.call(arguments); // 取得外部传入的构造器
 
 var F = function() {}
 F.prototype = Constructor.prototype;
 obj = new F(); // 指向正确的原型

 var res = Constructor.apply(obj, arguments); // 借用外部传入的构造器给obj设置属性
 return typeof res === 'object' ? res : obj; // 确保构造器总是返回一个对象
}
Function.prototype.myBind = function(context) {
 if (typeof this !== 'function') {
  throw new Error('Function.prototype.bind - what is trying to be bound is not callable');
 }
 
 var selft = this;
 var args = Array.prototype.slice.call(arguments, 1);
 
 var fNOP = function() {};
 
 var fBound = function() {
  var bindArgs = Array.prototype.slice.call(arguments);
  return self.apply(this instanceof fNOP ? this : context, args.concat(bindArgs));
 }
 fNOP.prototype = this.prototype;
 fBound.prototype = new fNOP();
 return fBound;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant