JavaScript 中 new 一个对象的过程中发生了什么

用户头像
Verlime
关注
发布于: 2020 年 07 月 21 日
JavaScript 中 new 一个对象的过程中发生了什么

在 JavaScript 中我们实例化一个对象(或者说是类)的时候,一般会用到 new 操作符,那么在这个过程中发生了些什么呢,接下来就来分析一下。



首先来看一段代码:



function Person(name, age) {
this.name = name;
this.age = age;
// return { a: 1 };
}
Person.prototype.say = function() {
console.log(this.name + ' say a message');
};
var person = new Person('tom', 18);
person.say();
// tom say a message
console.log(person.__proto__ === Person.prototype);
// true
console.log(person.constructor === Person);
// true
console.log(Person.prototype.constructor === Person);
// true



这里声明了一个构造函数 Person,有自己的属性和原型方法,然后通过 new 来实例化一个 person,此时 person 也拥有了 Person 所具有属性和原型方法。



我们知道每一个实例都有一个内部属性(称之为proto)指向它的构造函数的原型对象,这样就把实例和构造函数关联了起来,使实例可以访问到构造函数下的原型方法。



同时实例化的时候,我们也执行了构造函数,并把新的实例作为上下文(改变 this 指向),这样新创建的实例就拥有了构造函数的内部属性。



总结一下就是这几个步骤:



  • 创建一个空对象

  • 把该对象关联到原始对象或者是构造函数

  • 把新创建的空对象作为原始对象或者构造函数的上下文

  • 如果原始对象或者构造函数有返回值且为对象,则返回该对象,否则返回新创建的对象



原理我们知道了,那么我们如何去自己实现一个 new 呢?下面就来看下具体实现:



// var person = _new(Person, 'tom', 18)
function _new(fn) {
// 通过 slice 把类数组对象转化为数组
var args = [].slice.call(arguments);
// 去掉第一个参数,因为第一是传入构造函数,后面的才是实际的参数
args.shift(args);
var obj = {};
obj.__proto__ = fn.prototype;
// 或者直接用 Object.create 实现
// var obj = Object.create(fn.prototype);
var ret = fn.apply(obj, args);
// 如果有返回值且为对象类型,那么就返回结果,否则就返回 obj
return Object.prototype.toString.call(ret) === '[object Object]' ? ret : obj;
}



Photo by The Honest Company on Unsplash

发布于: 2020 年 07 月 21 日 阅读数: 25
用户头像

Verlime

关注

一个前端工程师 2018.01.01 加入

每天进步一点点ヽ(•̀ω•́ )ゝ

评论

发布
暂无评论
JavaScript 中 new 一个对象的过程中发生了什么