JavaScript 原型和对象创建底层原理
2021-06-30 02:04
标签:没有 转换 共享 结束 步骤 相同 create 不能 应该 JS原型链和继承网上已经烂大街了,5毛可以买一堆,这里只提一下: constructor:普通对象和函数对象都有,指向创建它的函数 当实例化新对象时,JS将使用与来自相同构造函数的先前对象相同的初始隐藏类创建它们。 创建过程大致如下(对于普通对象{a:1, b:2}也会有类似的过程): 在第二次用同样的构造函数创建一个新的对象实例时(如: var o2 = new fun1()),会复用M0,M1和M2。 这种机制有下面几个优点: 可以参考如下: 与实例的创建过程不同,原型的创建过程并不会使用隐藏类,因为原型prototypes通常情况下是一个唯一的对象,并且不会被其他的不同对象所共享结构。 Prototype创建有二个主要的阶段: 那么了解上面的原型创建过程有什么用呢? 因为原型是可以改变的,因此以上代码并不能确定O被用作原型,除非直到所有步骤结束。 那么应该怎么做呢?如下: 如果一个对象要作为原型,那么尽量在给对象添加属性之前就把该对象赋给原型属性。 更好的方式是下面这种: 最后,优雅的写法是: JavaScript 原型和对象创建底层原理 标签:没有 转换 共享 结束 步骤 相同 create 不能 应该 原文地址:https://www.cnblogs.com/full-stack-engineer/p/9644012.html1. prototype/__proto__/constructor
prototype: 函数对象才有,指向构造函数的原型对象(另一个普通对象)
__proto__: 普通对象和函数对象都有,指向创建它的构造函数的原型对象function Fun1(){};
Fun1.prototype.constructor == Fun1 //true
var f2 = new Fun1();
f2.__proto__ == Fun1.prototype //true
2. 对象实例的创建过程
当添加属性时,对象从一个隐藏类转换为另外一个隐藏类,通常遵循所谓的“转换树”中的先前转换。例如,如果我们有以下构造函数:function fun1(){
this.a = 1;
this.b = 2;
}
fun1: M0 {}
|
this.a: M1 {a:?}
|
this.b: M2 {a:?,b:?}
M0
{}
|
M1
{a:?}
/ \
M2 M3
{a:?,b:?} {a:?,c:?}3. prototype的创建过程
原型在建立阶段使用dictionary键值对存储,速度非常快。对比隐藏类的建立过程,使用键值对存储不会切换到底层运行环境。
任何对原型的访问,或者通过原型链的访问,都会切换到使用阶段。function Foo() {}
// Prototype在‘建立‘模式
var proto = Foo.prototype;
proto.method1 = function() { ... }
proto.method2 = function() { ... }
var o = new Foo();
// 从‘建立‘模式切换到‘使用‘模式
o.method1();
// 同样切换到‘使用‘模式
proto.method1.call(o);
4. prototype优化
JS很难在编译阶段进行代码分析,即使某个类被用作原型。当我们发现一个类被当做原型,如:var o = {x:1};
func.prototype = o;
所以:JS不得不首先进行隐藏类的创建过程,并转化为原型建立过程,这非常消耗性能。var o = {};
func.prototype = o;
o.x = 1;
func.prototype = Object.create(…);
func.prototype.method1 = …
func.prototype.method2 = …
var proto = func.prototype = Object.create(…);
proto.method1 = …
proto.method2 = …