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

Javascript-如何创建函数的新实例,javascript,javascript-objects,Javascript,Javascript Objects,我知道,我们可以通过以下方法创建新的函数实例。但我的问题是,还有其他方法可以达到同样的效果吗 var Person = function (firstName) { this.firstName = firstName; console.log('Person instantiated'); }; var person1 = new Person('Alice'); var person2 = new Person('Bob'); // Show the firstName prop

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

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
声明失败的情况下,我也没有得到
错误

特别是,在
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
的值将不会是空对象,因此您将改为分配给
窗口。在这种情况下,您希望使用
new
,因为您将函数用作构造函数。如果您不打算将函数用作构造函数,则不希望使用
new
调用它
new[function]
关键字做很多事情,但它做的主要事情是:

  • 创建一个新对象
  • 使用[Function]的原型作为新对象的父原型
  • 执行[函数]的内容,使用
    作为对新对象的引用
如果在没有
new
的情况下调用这样一个函数,则
引用将按照通常为函数确定的方式确定,并且通常是全局对象

要更容易发现这些错误,您可以使用严格模式:

"use strict";

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

var person1 = Person('Alice');
如果执行上述代码,
将是
null
而不是全局对象,并且您将立即得到一个错误,而不是将属性分配给全局对象(并且具有难以捕获的bug)

使用
new
避免此类错误的一种方法是让函数返回一个新对象,而不是构造函数:

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
方法

我在后面详细介绍的
新的
-less选项不提供此自动原型扩展,但还有其他选择:

选项1-不要使用原型:

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

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

var person = function (firstName) {
  console.log('person instantiated');
  return {
      firstName: firstName,
      getMyName: function () {
          return this.firstName;
      }
  };
};
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中的工作方式

假设您有一个用例,您需要一个表示
用户的对象,并存储他们的
名字

不使用任何函数,只需创建具有所需属性的对象:

var person = {
    first_name: 'joel'
};
这是一个标准的javascript对象——没有任何特殊之处,也没有使用new关键字来构造它。实现相同功能的另一种语法是:

var person = new Object();
person.first_name = 'joel';
再说一遍,这只是一个标准对象,没有什么特别之处

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

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

但是,对于这种情况,更好的方法是创建
person
对象的新实例,并在person函数的prototype属性上定义
getName
方法,因为您总是希望为每个用户定义此方法:

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

var user = new Person();
user.first_name = 'joel';
console.log(user.getName());
。。。或者,根据您的示例,您可以使用
Person
构造函数的参数来设置first-name属性:

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
关键字,您就意外地修改了
窗口
对象上的属性,而不是在新的常规对象上设置它

有效地-可以考虑使用<代码>新< /Cord>关键字,以使人函数的返回值被删除,而您将返回一个新的人对象实例。

还请注意,通过从函数内部省略
new
关键字,检查
this
是否等于
window
并返回函数的新实例,可以降低意外修改
window
对象的风险:

function Person() {
    if (this === window) return new Person();
    this.first_name = 'joel';
}
使用上述方法,您可以使用以下任一方法实例化您的
person
对象,两者的效果相同:

var user1 = new Person();
var user2 = Person();
有关javascript函数和原型对象如何工作的更多信息,我建议阅读