很简单的一个分享~
首先看了一下new操作符的使用:
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.job = 'engineer';
Person.prototype.sayAge = function() {
return this.age;
}
const person1 = new Person('wang', 24);
console.log(typeof person1); // "object"
console.log(person1.name); // wang
console.log(person1.sayAge()); // 24
console.log(person1.job); // engineer

Person是一个构造函数,实例person1能访问到构造函数的属性,以及Person的原型对象Person.prototype的属性和方法。
其实我做的更像是已知new的过程,来求证的。new调用函数的过程在 ES5官方文档 在 函数定义 一节中做了定义:
- 创建一个ECMAScript的原生对象obj.
- 给obj设置原生对象的内部属性;(和原型不同,内部属性表示为
[[PropertyName]],两个方括号包裹属性名,并且属性名大写,比如[[Prototype]]和[[Constructor]]) - 设置obj的
[[Class]]为Object. - 设置obj的
[[Extensible]]为true.([[Extensible]]决定是否可以向对象添加属性) - 将
proto的值设置为F的prototype属性值. - 如果
proto是对象类型,则obj的内部属性[[Prototype]]的值为proto;(进行原型链关联,实现继承的关键) - 如果
proto不是对象类型,则设置obj的内部属性[[Prototype]]的值为内建构造函数Object的[[prototype]]的值.(函数的prototype属性可以被改写,如果改成非对象类型,obj的[[prototype]]就指向Object的原型对象) - 调用函数
F,将其返回值赋给result;其中,F执行时的实参传递给[[Construct]](即F的本身)的参数,F内部this指向obj. - 如果
result是Object类型,返回result. - 如果
F返回的不是对象类型(第9步不成立),则返回创建的对象obj.
很多地方都更简洁的归纳为4个步骤:
- 创建一个新的空对象{}.
- 将构造函数的作用域赋值给这个新的对.(将构造函数的_prototype_赋值给对象的_proto_属性)
- 执行构造函数的代码.
- 返回对象.
开始我的简单的测试
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.job = 'engineer';
Person.prototype.sayAge = function() {
return this.age;
}
function newOperator(fn) {
const obj = {};
// 或者 const obj = new Object();
obj._proto_ = fn.prototype;
fn.apply(obj, arguments);
return obj;
}
const person1 = newOperator(Person, 'wang', 24);
console.log(person1.name);
console.log(person1.age);
打印结果:

查查查原因:发现arguments导致的。
arguments是一个类数组,slice和shift结合Function.call可以处理。
重新改一下newOperator函数
// example 1
function newOperator(fn, ...res) {
const obj = new Object();
obj._proto_ = fn.prototype;
fn.apply(obj, res);
return obj;
}
// example 2
function newOperator(fn) {
const obj = new Object();
obj._proto_ = fn.prototype;
fn.apply(obj, Array.slice.call(arguments, 1));
return obj;
}
// example 3
function newOperator() {
const obj = new Object();
const Construct = [].shift.call(arguments)
Construct.apply(obj, arguments);
return obj;
}
// example 4
function newOperator(fn) {
newOperator.target = fn; // ES6 new.target 是指向构造函数
const obj = Object.create(fn.prototype);
fn.apply(obj, [].slice.call(arguments, 1));
return obj;
}
修正后的打印结果 -- 正确了:

如果我们在构造函数有处理返回值的情况:
function Person(name, age) {
this.name = name;
this.age = age;
return { name: 'yun' }
}
// newOperator 函数直接返回新的对象
const person1 = newOperator(Person, 'wang', 24);
console.log(person1.name); // wang
上面所说的newOperator是最简单的情况,没有考虑到之前说的构造函数显示返回的情况,所以在稍微考虑一下返回结果的情况:
如果函数没有返回对象类型Object(包含Functoin, Array, Date, RegExg, Error),那么new表达式中的函数调用会自动返回这个新的对象。
function newOperator() {
const obj = new Object();
const Construct = [].shift.call(arguments)
const result = Construct.apply(obj, arguments);
const isObject = typeof result === 'object' && result !== null;
const isFunction = typeof result === 'function';
if (isObject || isFunction) {
return result;
}
return obj;
}
简单测试一下:
function Person(name, age) {
this.name = name;
this.age = age;
return { name: 'yun' }
}
// newOperator 有判断构造函数的返回值的情况
const person1 = newOperator(Person, 'wang', 24);
console.log(person1.name); // yun
一点点说明
关于Object类型的检测,可以用typeOf,也可以用instanceof。
function newOperator() {
const obj = new Object();
const Construct = [].shift.call(arguments)
const result = Construct.apply(obj, arguments);
return (result instanceof Object) ? result : obj;
}
但是instanceof的工作原理是:在表达式x instanceof Foo 中,如果 Foo 的原型(即 Foo.prototype)出现在x的原型链中,则返回 true,不然,返回false。
实例创建之后重写构造函数原型,实例指向的原型已经不是构造函数的新的原型了。
const Foo = function() {};
const o = new Foo();
o instanceof Foo; // true
// 重写 Foo 原型
Foo.prototype = {};
o instanceof Foo; // false
关于创建的新的对象:
//方式多种
const obj = {};
const obj = new Object();
const obj = Object.create();
但是我还没有理解他们是有什么区别的吗,在最后创建出来实例当中的引用。