Skip to content
New issue

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

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

Already on GitHub? # to your account

2. 手写new和bind #2

Open
gumingWu opened this issue May 17, 2022 · 5 comments
Open

2. 手写new和bind #2

gumingWu opened this issue May 17, 2022 · 5 comments

Comments

@gumingWu
Copy link
Owner

先来两篇羽哥大大的文章镇场子

  1. JavaScript深入之new的模拟实现
  2. JavaScript深入之bind的模拟实现

老规矩,我们先的知道这个api的场景是什么
一句话介绍 new运算符号:

new

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

一句话介绍 bind:

bind()

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

题目:

  1. 因为 new 是关键字,所以无法像 bind 函数一样直接覆盖,所以我们写一个函数,命名为 objectFactory,来模拟 new 的效果
  2. 模拟bind的实现
@LuMMao
Copy link

LuMMao commented May 17, 2022

new

测试案例:

// 测试 1
function Otaku(name, age) {
  this.name = name;
  this.age = age;

  this.habit = "Games";
  return null;
  // return 1
  // return '1'
  // return true
  // return {}
  // return function(){}
  // return /a/
}
Otaku.prototype.strength = 60;
Otaku.prototype.sayYourName = function () {
  console.log("I am " + this.name);
};

// 测试2
Otaku.prototype = null;

var person1 = new Otaku("Kevin", "18");
var person2 = objectFactory(Otaku, "Kevin", "18");

console.log(person1, person2);
console.log(person1.name, person2.name); // Kevin
console.log(person1.habit, person2.habit); // Games
console.log(person1.strength, person2.strength); // 60

person1.sayYourName(); // I am Kevin
person2.sayYourName(); // I am Kevin

实现:

function objectFactory(ctor, ...args) {
  if(typeof ctor !== 'function') {
    throw TypeError('ctor is not a function');
  }

  var obj = {}

  // 处理 ctor.prototype 为 null 的情况
  obj.__proto__ = ctor.prototype instanceof Object ? ctor.prototype : Object.prototype;

  var res = ctor.apply(obj, args);

  var isObject = typeof res === 'object' && res !== null;
  var isFunction = typeof res === 'function';
  return isObject || isFunction ? res : obj;
}

@LuMMao
Copy link

LuMMao commented May 17, 2022

bind

测试案例:

// 测试 1
var foo1 = {
  value: 1,
};
function bar1() {
  console.log(this.value);
}
// 返回了一个函数
var bindFoo1 = bar1.myBind(foo1);

bindFoo1(); // 1

// 测试 2
var foo2 = {
  value: 1,
};
function bar2() {
  return this.value;
}
var bindFoo2 = bar2.myBind(foo2);

console.log(bindFoo2()); // 1

// 测试 3
var foo3 = {
  value: 1,
};
function bar3(name, age) {
  console.log(this.value);
  console.log(name);
  console.log(age);
}
var bindFoo3 = bar3.myBind(foo3, "daisy");
bindFoo3("18");

// 测试 4
var value4 = 2;
var foo4 = {
  value4: 1,
};
function bar4(name, age) {
  this.habit = "shopping";
  console.log(this.value4);
  console.log(name);
  console.log(age);
}
bar4.prototype.friend = "kevin";
var bindFoo4 = bar4.myBind(foo4, "daisy");
var obj4 = new bindFoo4("18");
console.log(obj4.habit);
console.log(obj4.friend);

// 测试 5
var value5 = 2;
var foo5 = {
  value5: 1,
  bar5: bar5.myBind(null),
};
function bar5() {
  console.log(this.value5);
}
foo5.bar5(); // 2

实现:

Function.prototype.myBind = function (context, ...outerArgs) {
  if(typeof this !== 'function') {
    throw TypeError('this is not a function')
  }

  var self = this;
  var fNOP = function() {}

  var fBind = function(...innerArgs) {
    return self.apply(this instanceof self ? this : context, outerArgs.concat(innerArgs));
  }

  fNOP.prototype = this.prototype;
  fBind.prototype = new fNOP();
  return fBind;
};

@ClearMing
Copy link

ClearMing commented May 17, 2022

new

function objectFactory(cotr, ...args) {
    //判断边界
    if (typeof cotr !== 'function') {
        throw TypeError('cotr is not a function !');
    }


    // #1.创建一个空对象
    const obj = {} //new Object()  
    // #2.将新对象的原型对象指向cotr的原型对象
    obj.__prop__ = ctor.prototype; //Object.prototype(ctor.prototype)基于目标对象再创建出一个实例

    // #3.将构造函数的this指向新对象
    let res = ctor.apply(obj, [...args]);//获取所有属性

    let isObject = typeof res === 'object' && res != null;

    let isFunction = typeof res === 'function';

    // 4.根据返回值判断 
    return isObject || isFunction ? res : obj;

}

bind

Function.prototype.myBind = function (context) {
    //判断调用对象是否为函数
    if (typeof this !== 'function') {
        throw new TypeError('Function.prototype.bind -what is trying to be bound is not callable!')
    }

    console.log("111", this, context);

    //获取参数
    const args = [...arguments].slice(1),
        self = this;
    return function Fn() {
        console.log("222", this);
        self.apply(this instanceof Fn ? new self(...arguments) : context, [...args, ...arguments]);
    }
}

---后面再补注释

@gumingWu
Copy link
Owner Author

手写new

老规矩,写在注释里

/**
 * new,后面跟一个构造函数,返回一个对象
 * 具体步骤
 * 1. 创建一个新对象
 * 2. 新对象原型,指向构造函数原型
 * 3. 使用call/apply显示执行构造函数,获取一个返回值
 * 4. 如果返回值是一个对象,则返回该对象,如果不是一个对象或者没有返回值,则返回新对象
 */
function objectFactory(Ctor, ...args) {
  const obj = new Object();
  Object.setPrototypeOf(obj, Ctor.prototype);
  // obj.__proto__.constructor = Ctor;
  const res = Ctor.apply(obj, args);
  return Object.prototype.toString.call(res).slice(8, -1) === "Object"
    ? res
    : obj; // 如果用typeof,会包含null,而new对于返回null的构造函数是会返回新对象
}

// 测试1,返回null
function testFunc() {
  this.name = "hhh";
  return null;
}

// const res = new testFunc();
// console.log(res);
const res = objectFactory(testFunc);
console.log(res);

// 测试2,返回基本类型
function testFunc2() {
  this.name = "ooo";
  return 1;
}
// const res2 = new testFunc2();
// console.log(res2);
const res2 = objectFactory(testFunc2);
console.log(res2);

// 测试3,返回一个对象
function testFunc3() {
  this.name = "www";
  return {
    aaa: "bbb",
  };
}
// const res3 = new testFunc3();
// console.log(res3);
const res3 = objectFactory(testFunc3);
console.log(res3);

@fight-David
Copy link

Bind

Function.prototype.myBind = function (context = window, ...args) {
    const self = this

    return function () {
        return self.apply(context, args.concat(Array.from(arguments)))
    }
}

function test() {
    console.log(arguments);
    console.log(this);
    return '我是david'
}

let obj = {
    name: 'jerry',
    age: 12
}

test.myBind(obj, 1, 2, 3)(4, 5, 6)

new

function _new(obj, ...rest) {
    // 基于obj的原型创建一个新的对象 继承父类原型上的方法
    const newObj = Object.create(Object.getPrototypeOf(obj));
    // 添加属性到新创建的newObj上, 并获取obj函数执行的结果.
    const result = obj.apply(newObj, rest);
    // 如果执行结果有返回值并且是一个对象, 返回执行的结果, 否则, 返回新创建的对象
    return typeof result === 'object' ? result : newObj;
}

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants