Javascript - 如何创建函数的新实例

Javascript - How to create new instance of functions

我知道,我们可以通过以下方法创建新的函数实例。但我的问题是还有其他方法可以达到同样的效果吗?

var Person = function (firstName) {
  this.firstName = firstName;
  console.log('Person instantiated');
};

var person1 = new Person('Alice');
var person2 = new Person('Bob');

// Show the firstName properties of the objects
console.log('person1 is ' + person1.firstName); // logs "person1 is Alice"
console.log('person2 is ' + person2.firstName); // logs "person2 is Bob"

因为,有时 new 声明失败,我也没有得到 error..

特别是,在 javascript oops 概念中需要不同的方法。

有时候,我什至没有调用 new 关键字就感到困惑,但一切正常.. 使用 new 关键字和不使用它有什么区别?

示例:

var setColor = function (color) {
   return color;
}

var x = setColor('red');
var y = setColor('blue');

console.log(y);
console.log(x);

调用函数时使用 new 关键字将函数内部的上下文 (this) 设置为新实例化的对象,而不是 window 或其他上下文,这就是为什么您可以在函数内部分配给 this.firstName,然后将其称为 person1.firstName.

如果不使用 new 关键字,this 的值将不会是空白对象,因此您将分配给 window。在这种情况下,您想使用 new 因为您将该函数用作构造函数。如果您不打算将该函数用作构造函数,则不想使用 new.

调用它

new [Function]关键字做了很多事情,但它主要做的事情是:

  • 创建一个新对象
  • 使用 [Function] 的原型作为新对象的父原型
  • 执行[Function]的内容,使用this作为对新对象的引用

如果您在没有 new 的情况下调用这样的函数,this 引用将按照通常为函数确定的方式确定,并且通常是全局对象。

要更容易地发现这些错误,您可以做的一件事是使用严格模式:

"use strict";

var Person = function (firstName) {
  this.firstName = firstName;
  console.log('Person instantiated');
};

var person1 = Person('Alice');

如果执行上面的代码,this 将是 null 而不是全局对象,您会立即得到一个错误,而不是将属性分配给全局对象(并且有难以捕捉的错误)。

一种完全避免 new 错误的方法是让函数 return 成为一个新对象而不是构造函数:

var person = function (firstName) {
  console.log('person instantiated');
  return {
      firstName: firstName
  };
};

var person1 = person('Alice');
var person2 = person('Bob');

如果你这样做,你是否使用new并不重要,因为该函数不使用this

编辑 下面有一个关于原型的问题。如果您不熟悉原型,这是一个允许您指定将在对象的所有实例之间共享的属性和方法的功能:

"use strict";

var Person = function (firstName) {
  this.firstName = firstName;
  console.log('Person instantiated');
};

Person.prototype.getMyName = function () {
    return this.firstName;
};

var person1 = new Person('Alice');
console.log(person1.getMyName());

如果您这样做,那么使用 new Person() 创建的所有实例将共享 getMyName 方法。

我稍后详述的 new-less 选项 提供这个自动原型扩展,但有替代方案:

选项 1 - 不使用原型:

var person = function (firstName) {
  console.log('person instantiated');
  return {
      firstName: firstName,
      getMyName: function () {
          return this.firstName;
      }
  };
};

选项 2 - 使用 Object.create() 扩展原型:

var person = function (firstName) {
  console.log('person instantiated');
  var person = Object.create(person.prototype);
  person.firstName = firstName;

  return person;
};

选项 3 - 使用 .extend() 方法将原型的内容复制到新对象:

var person = function (firstName) {
  console.log('person instantiated');

  return _.extend({
      firstName: firstName
  }, person.prototype);
};

.extend() 没有内置到 JavaScript 中,但是 jQuery 和 lodash 等几个库提供了它的基本等效实现。

我认为您需要更好地了解对象和原型在 Javascript 中的工作原理。

假设您有一个用例,您需要一个表示 user 的对象并存储它们的 first_name.

无需使用任何函数,您可以简单地创建一个具有所需属性的对象:

var person = {
    first_name: 'joel'
};

这是一个标准的 javascript 对象 - 没有什么特别之处,也没有使用 new 关键字来构造它。完成同样事情的另一种语法是:

var person = new Object();
person.first_name = 'joel';

同样 - 这只是一个标准对象 - 没有什么特别之处。

创建 new 个函数实例的主要原因是使用 javascript 的原型系统。这类似于其他语言中的 class。假设您希望一个人的所有实例都有一个名为 getName() 的方法。您可以确保为您拥有的每个人创建该方法...

var person = {
    first_name: 'joel',
    getName: function() {
        return this.first_name;
    }
};

或...

var person = new Object();
person.first_name = 'joel';
person.getName = function() {
    return this.first_name;
};

然而,对于这种情况,您总是希望为每个用户都定义此方法,更好的方法是创建一个 person 对象的新实例,并定义 [= Person 函数的原型 属性 上的 24=] 方法:

function Person() {}
Person.prototype.getName = function() {
    return this.first_name;
}

var user = new Person();
user.first_name = 'joel';
console.log(user.getName());

... 或者根据您的示例,您可以使用 Person 构造函数的参数来设置名字 属性:

function Person(first_name) {
    this.first_name = first_name;
}
Person.prototype.getName = function() {
    return this.first_name;
};
var user = new Person('joel');
console.log(user.getName());

请注意,使用此方法创建 Person 实例时,您将始终使用 new 关键字。当您考虑以下因素时,其原因就变得很清楚了:

function Person() {this.first_name = 'joel'; return 'test';}
console.log(window.first_name); // Undefined, as expected
console.log(Person()); // Shows "test";
console.log(window.first_name); // shows "joel".
console.log(new Person()); // Shows "{first_name: 'joel'}"

请注意,在上面的第 4 行,您可以看到,通过在期望您使用它的函数调用中省略 new 关键字,您不小心修改了 属性 window 对象,而不是将其设置在新的常规对象上。

有效 - 您可以考虑使用 new 关键字导致 Person 函数的 return 值被丢弃,取而代之的是返回一个新的 Person 实例对象。

另请注意,您可以通过在函数内部省略 new 关键字来降低意外修改 window 对象的风险,方法是检查 this 是否等于 window 和 return 取而代之的是函数的新实例:

function Person() {
    if (this === window) return new Person();
    this.first_name = 'joel';
}

根据以上内容,您可以使用以下任一方法实例化您的 person 对象,两者的效果相同:

var user1 = new Person();
var user2 = Person();

有关 javascript 函数和原型对象如何工作的更多信息,我建议阅读 http://www.w3schools.com/js/js_object_prototypes.asp

另一种可能的结构使用闭包而不是对象

这个结构也可以嵌套创建私有静态变量

它没有用到这个词

var thing = function(private_var){

   function get(){
     console.log(private_var)
   }

   function set(z){
      private_var = z
   }

   return {
    get:get,
    set:set
   }


}

var x = thing(0)
var y = thing(1)

请注意:
这让某些类型的程序员惊慌失措

&& 重要的是 x.say !== y.say