-
Notifications
You must be signed in to change notification settings - Fork 118
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
实现MyNew方法 #15
Comments
function PolyfillNew(fn, ...args) {
// 如果不是函数报错
if (typeof fn !== 'function') {
throw TypeError(`Expected a function, but got a ${typeof fn}`)
}
// 创建新对象,并修改新对象的原型
const o = Object.create(fn.prototype)
// 以新对象作为 this 调用函数
const r = fn.apply(o, args)
const t = typeof r
// 如果函数返回值为对象或函数则返回,否则返回新对象
return (r !== null && t === 'object') || t === 'function' ? r : o
}
function Person(name, age) {
this.name = name
this.age = age
}
const kasong = PolyfillNew(Person, 'KaSong', 18)
console.log(kasong.age) // 18
function Something(name) {
this.name = name
return { name: 'something' }
}
const something = PolyfillNew(Something, 'XiaoMing')
console.log(something.name) // something
function Others(name) {
this.name = name
return function test() {
console.log(this)
}
}
const others = PolyfillNew(Others, 'others')
console.log(others)
// ƒ test() {
// console.log(this)
// }
const others2 = new Others('others2')
console.log(others2)
// ƒ test() {
// console.log(this)
// } |
const MyNew = (constructor, ...args) => {
const obj = Object.create(constructor.prototype)
constructor.apply(obj, args)
return obj
} |
function myNew(constructor) {
var _args = Array.prototype.slice.call(arguments, 1)
var _this = {}
_this.__proto__ = constructor.prototype
var res = constructor.apply(_this, _args)
return res !== null && typeof res === 'object' ? res : _this
} |
正好我最近在学习这块,就来尝试下~
function myNew(constructorFunction, ...args) {
const res = {}
Object.setPrototypeOf(res, constructorFunction.prototype)
constructorFunction.apply(res, args)
return res
} 有人实现 还有也不太懂题目中 |
function MyNew (cto, ...rest) {
let isFun = (cto) => typeof cto === 'function'
let isObj = (param) => typeof param === 'object' && param !== null
if (!isFun(cto)) return 'the first param must be a function'
MyNew.target = cto
let obj = Object.create(cto.prototype)
let res = cto.apply(obj, rest)
if (isFun(res) || isObj(res)) return res
return obj
} |
function myNew(fn, ...args) {
let obj = Object.create(fn.prototype);
let result = fn.apply(obj, args);
return result instanceof Object ? result : obj;
}
` |
在调用 new 的过程中会发生以下四件事情:
function MyNew(ctor) {
if(typeof ctor !== 'function') {
throw 'ctor must be a function';
}
let obj = Object.create(ctor.prototype); //1-2
let res = ctor.apply(obj, arguments);//3
return res instanceof Object ? res : obj;//4
}; |
首先,我们先来看看 // 构造函数 People (无显式返回值)
function People(name, age) {
this.name = name
this.age = age
}
People.prototype.printInfo = function () {
return `My name is ${this.name} and ${this.age}`
}
// 构造函数 Student (有显式返回值,且返回值为对象类型)
function Student(name) {
this.name = name
return { ps: 'balabala' }
}
const p1 = new People('Jack', 17)
const s1 = new Student('David')
console.log(p1.name) // Jack
console.log(p1.age) // 17
console.log(p1.printInfo()) // My name is Jack and 17
console.log(s1) // {ps: "balabala"} 可以看出
基于以上的内容,我们来实现一个
const MyNew = (Con, ...args) => {
const obj = Object.create(Con.prototype)
const result = Con.apply(obj, args)
return typeof result === 'object' ? result : obj
} |
/**
* @param {function} fn target function
* @param {any} fnArgs function rest arguments
* @returns {Object}
*/
function MyNew(fn, ...fnArgs) {
const PROTOTYPE_OBJECT = Object.create(null);
if (typeof fn !== 'function') {
return PROTOTYPE_OBJECT;
}
try {
const RESULT = fn.apply(PROTOTYPE_OBJECT, fnArgs);
return RESULT instanceof Object ? RESULT : PROTOTYPE_OBJECT;
} catch (error) {
return PROTOTYPE_OBJECT;
}
} |
实例化过程中构造函数内部工作流程:
实现: function MyNew(fn, ...args) {
const result = Object.create(fn.prototype) // 创建新对象,使用构造函数的原型作为新对象的原型对象
const obj = fn.apply(result, args)
// 引用类型直接返回
return (typeof obj === 'object' && obj !== null || typeof obj === 'function') ? obj : result
} 单测: describe('MyNew', () => {
it('should be defined', () => {
expect(MyNew).toBeDefined()
})
it('should work on common constructor', () => {
function Person(name, age) {
this.name = name
this.age = age
}
const result = MyNew(Person, 'KaSong', 18)
expect(result.age).toBe(18)
})
it('should work on constructor return object', () => {
function Something(name) {
this.name = name
return { name: 'something' }
}
const result = MyNew(Something, 'XiaoMing')
expect(result.name).toBe('something')
})
}) |
function myNew(fn, ...args) {
if (typeof fn !== 'function') throw new Error('fn nust be a function');
const obj = Object.create(fn.prototype);
const result = fn.apply(obj, args);
return (typeof result === 'object' && result !== null) || typeof result === 'function' ? result : obj;
} |
function myNew(fn, ...args) {
const obj = Object.create(fn.prototype)
let result = fn.apply(obj, args)
return result instanceof Object ? result : obj
}
测试:
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.say = function () {
console.log(this.name)
}
let p = mynew(Person, "su", 123)
console.log(p) // Person {name: "su", age: 123}
p.say() // "su" |
来个函数式的 const mynew = (fn, ...arg) =>
(((ctx) =>
(result => typeof result === 'object' ? result : ctx)
(fn.apply(ctx, arg)))
({ __proto__: fn.prototype }))
function mynew(fn, ...arg){
const ctx = { __proto__: fn.prototype }
const result = fn.apply(ctx, arg)
return typeof result === 'object' ? result : ctx
} |
function myNew(fn, ...args) {
// 创建临时对象,同时绑定原型
const obj = Object.create(fn.prototype)
// 执行构造函数
const result = fn.apply(obj, args);
// 返回构造结果或临时对象
return typeof result === 'object' ? result : obj;
} |
/** MDN
* new 运算符
* new 运算符创建一个用户定义的对象类型的实例或具有构造函数的内置对象的实例。
*
* new 关键字会进行如下的操作:
* 1. 创建一个空的简单JavaScript对象(即{});
* 2. 为步骤1新创建的对象添加属性__proto__,将该属性链接至构造函数的原型对象 ;
* 3. 将步骤1新创建的对象作为this的上下文 ;
* 4. 如果该函数没有返回对象,则返回this。
*/
function MyNew(fn, ...args) {
//1
const obj = Object.create(null);
//2
Object.setPrototypeOf(obj, fn.prototype)
//3
const ret = fn.apply(obj, args);
//4
return ret instanceof Object ? ret : obj;
} |
new 关键字js 中定义一个类 // 定义构造函数
function Person(name) {
console.log('constructor')
// 将构造函数的this指向新对象
this.name = name
}
// 定义类的属性
Person.prototype.say = function () {
console.log('My name is', this.name)
}
// 创建新对象
const p1 = new Person('tom')
p1.say() 在调用 new 时, 主要做了 4 件事:
根据以上规则,我们可以模拟实现一个 new 函数 function myNew(constructorFn, ...args) {
// 1. 创建一个空对象
const obj = {}
// 2. 将空对象的__proto__指向constructor的prototype
obj.__proto__ = constructorFn.prototype
// 3. 执行 constructor, 并将新对象绑定为constructor的this对象
const res = constructorFn.apply(obj, args)
// 4. 如果构造函数有返回值则返回res,否则返回新对象
return typeof res === 'object' ? res : obj
}
const p1 = myNew(Person, 'jack')
p1.say() |
内部工作流程:
代码实现:function myNew(Fn,...args){
// 检测异常
if(typeof Fn != 'function'){
throw new TypeError(Fn + 'is not a constructor')
}
// 修改 target 属性
myNew.target = Fn
// 创建空的实例对象
const instance = {}
// 检测构造函数原型是不是对象
instance.__proto__ = Fn.prototype instanceof Object ? Fn.prototype : Object.prototype
// 执行构造函数
const returnValue = Fn.call(instance,...args)
// 决定 new 的返回值
return returnValue instanceof Object ? returnValue : instance
} 测试:// 构造函数原型不为空的情况
function Student(name,age){
this.name = name
this.age = age
}
const student1 = myNew(Student,'Jack',20)
const student2 = new Student('Jack',20)
console.log(student1) // {name:'Jack',age:20}
console.log(student2) // {name:'Jack',age:20}
// 构造函数原型为空的情况
function Fn(){}
Fn.prototype = null
const fn1 = myNew(Fn)
const fn2 = new Fn()
Object.getPrototypeOf(fn1) === Object.prototype // true
Object.getPrototypeOf(fn2) === Object.prototype // true |
function myNew(argument) { |
实现new 创建实例的步骤: function MyNew(targetFn, ...arg) { |
思路(根据 new 的执行原理来mock)
代码实现 (测试用例均通过)function MyNew(fn, ...args) {
// 标注1
let obj = Object.create(fn.prototype);
// 标注2
let res = fn.apply(obj, args);
// 标注3
if ((typeof res === "object" && res !== null) || typeof res === "function") {
return res;
}
return obj;
} |
原理:
function MyNew(Fn, ...args) { //将不定数量的参数表示为一个数组
//1.创建空对象obj,并将obj._proto_指向构造函数Fn.prototype
const obj = Object.create(Fn.prototype);
//2.将构造函数Fn的this指向obj,并执行Fn代码,获得返回值
const res = Fn.apply(obj, args); //args是数组['dy','男']
//3.根据返回值类型,决定到底返回谁
return res instanceof Object ? res : obj;
}
//构造函数
function Person(name, sex) {
this.name = name;
this.sex = sex;
}
Person.prototype.getName = function () {
return this.name;
};
Person.getSex = 'bukeyisese'
const ymy = new Person("ymy", "女");
const dy = MyNew(Person, "dy", "男");
console.log(ymy);
console.log(dy);
console.log(dy.getName());
//共享原型上的方法
console.log(ymy.getName === dy.getName); //true
|
要实现的功能
我们可以使用
new
实例化一个构造函数,请根据实例化过程中构造函数内部工作流程,实现类似功能的MyNew
方法。代码示例
问题补充
最佳答案
Chorer的回答
理由:实现完备,且包含问题补充中的所有要素
答题同学须知
答题规范:请在
一次评论
中完成作答,后续修改也请编辑该评论,而不是追加新的评论评选标准:最佳答案由
围观同学
的 👍 和卡颂共同决定评选时间:一般是当日18:00左右评选,如果问题发布当天回答数较少,问题悬赏金额可能增加,同时悬赏时间也会增加
围观同学须知
对于你满意的答案,请不要吝惜你的 👍,这是评选最佳答案的依据
非答题的评论
会被删除,问题相关讨论请在赏金猎人群中进行The text was updated successfully, but these errors were encountered: