js constructor vs prototype

71 阅读3分钟

文心一言的悄悄话 js

在您给出的两个 Test 函数定义中,主要存在几个关键的区别,这些区别主要涉及到函数内部变量的作用域和可访问性。

第一个 Test 函数

function Test(){  

    this.name = 'rose'  

    this.say = function(){  

        console.log('我能说话')  

    }  

}
  1. this 关键字的作用:在这个函数中,this 关键字被用来访问函数的上下文对象。当这个函数被用作构造函数(即使用 new 关键字创建对象时),this 会指向新创建的对象。因此,this.name 和 this.say 会被添加到这个新对象的属性中。
  2. 属性与方法name 和 say 被定义为对象的属性。name 是一个简单的字符串属性,而 say 是一个方法(函数),它可以通过对象实例来调用(例如 var obj = new Test(); obj.say();)。
  3. 可访问性:由于 name 和 say 是对象的属性,它们可以在对象被创建后通过对象实例来访问和修改。

第二个 Test 函数

function Test(){  

    let name = 'rose'  

    let say = function(){  

        console.log('我能说话')  

    }  

}
  1. 块级作用域:这里使用了 let 关键字来声明 name 和 say,它们被限制在 Test 函数的块级作用域内。这意味着这些变量和方法在函数外部是不可访问的。
  2. 私有变量:由于 name 和 say 是在函数内部声明的,它们被视为私有变量和函数。这意味着它们只能在 Test 函数的内部被访问和修改,外部代码无法直接访问它们。
  3. 可访问性限制:由于 name 和 say 的作用域限制,它们无法像第一个 Test 函数中的 name 和 say 那样被外部代码直接访问或修改。这种设计在封装和隐藏内部实现细节时非常有用。

总结

  • 第一个 Test 函数定义了一个构造函数,其属性(包括方法)可以通过对象实例来访问和修改。
  • 第二个 Test 函数则使用块级作用域来隐藏其内部变量和函数,这些内部变量和函数在函数外部是不可访问的,这有助于封装和隐藏实现细节。

注意:在 JavaScript 中,如果您在同一个作用域内(例如全局作用域或同一个文件内)重复定义同一个函数名,后面的定义会覆盖前面的定义。因此,在您的示例中,第二个 Test 函数定义实际上会覆盖第一个 Test 函数定义。这可能会导致混淆或错误,特别是当您尝试使用第一个 Test 函数的功能时。

prototype__proto__constructor

假设我们有一个构造函数Person,以及一个由Person创建的实例person

function Person(name) {  
    this.name = name;  
}  

var person = new Person('Alice');

在这个例子中:

  • Person.prototype是一个对象,它有一个constructor属性指向Person函数。
  • person对象的内部[[Prototype]](可以通过Object.getPrototypeOf(person)或旧式的person.__proto__访问)指向Person.prototype
  • 因此,person.constructor实际上是从Person.prototype上继承来的,它指向Person函数。

结论

  • prototype是函数的一个属性,它指向一个对象,该对象包含可以被函数创建的实例共享的属性和方法。
  • __proto__(尽管是非标准的)是一个对象属性,用于访问对象的内部[[Prototype]]链接。
  • constructor是对象从其原型链上继承的一个属性,它指向创建该对象的构造函数。