[JavaScript]new运算符及构造函数的用法
JavaScript new 运算符和构造函数
在 JavaScript 中可以使用 new
运算符搭配构造函数 (function constructor) 创建新对象。
构造函数 (function constructor) 是一个用来创造新对象的函数,需要和 new
运算符一起搭配使用。
举例来说,假设现在要用 Cat()
构造函数创造新对象,我们需要搭配 new
运算符一起调用构造函数 Cat()
,调用 Cat()
时可以传入参数:
javascript
var kitty = new Cat("Kitty");
在 this 上定义对象属性
如果要定义对象的属性,需要在构造函数中修改 this
的属性 (property)。在构造函数中, this
代表我们要创造的新对象。
举例来说,假设对象需要有 name
属性,我们需要将构造函数的 name
参数指定给 this.name
。我们可以定义 Cat
构造式如下:
javascript
// Constructor
function Cat(name) {
this.name = name;
}
搭配 new 运算符调用构造函数时,将 "Kitty"
当作构造函数的参数传入,则新对象的 name
属性即为 "Kitty"
。我们可以调用 kitty.name
来验证:
javascript
var kitty = new Cat("Kitty");
console.log(kitty.name) // Kitty
在 prototype 上定义对象方法
要定义对象方法,需要将对象方法声明在构造函数的 prototype
属性里。构造函数的 prototype
属性,就是新对象的 prototype。
举例来说,如果 Cat
构造函数产生的对象都要有 speak()
方法,我们可以定义 Cat.prototype.speak()
:
javascript
// Define 'speak' method for Cat objects
Cat.prototype.speak = function() {
console.log(this.name + ": meow!");
};
接着用 new
运算符调用构造函数创造新对象,就可以在新对象上调用 speak()
方法:
javascript
var kitty = new Cat("Kitty");
kitty.speak(); // Kitty: meow!
原型继承
要了解 new 和构造函数的运作原理,首先我们要了解何谓原型继承 (prototypal inheritance)。
原型继承的意思是,JavaScript 中每个对象都有个 prototype 属性,对象能够继承 prototype 上的属性或方法。这个机制可以让我们产生继承自同一个 prototype 的多个对象,达到代码复用的效果。
用 new 运算符调用构造函数时背后发生了什么事?
当我们用 new 运算符调用构造函数 new Cat("Kitty")
的时候,JavaScript 引擎在背后做了几件事:
- 创建新对象。
- 将新对象的 prototype 指定为构造函数的
prototype
属性。以上面的例子来说就是Cat.prototype
。 - 将新对象绑定到
this
对象,并调用构造函数。 - 在不特别指定
return
值的情况下,返回刚创造的新对象。
因为新对象的原型是 Cat.prototype
,所以新对象可以调用定义在 Cat.prototype
上的 speak()
方法。
使用 new 运算符与构造函数容易犯的错误
构造式必须和 new
运算符搭配使用,但万一我们忘了 new
,直接调用构造函数:
javascript
var kitty = Cat("kitty");
此时并不会有任何错误或警告, this
会直接绑定全局变量,有可能会导致很难察觉的 bug!
用 Object.create() 创造新对象
ES5 中提供了 Object.create()
的方法,用途是创造新对象,并令其 prototype 等于第一个被传入的参数。
例如,我们想要创造很多猫对象,所以我们先创造一个对象 cat
来当作 prototype,里面定义了 speak()
方法:
javascript
var cat = {
speak: function() {
console.log(this.name + ": meow!");
}
};
当我们调用 Object.create(cat)
时,返回的新对象的 prototype 就是 cat
。
javascript
// Create a new cat
var kitty = Object.create(cat);
kitty.name = "Kitty";
kitty.speak(); // Kitty: meow!
虽然 kitty
本身没有定义 speak()
方法,但它的 prototype (也就是 cat
对象) 定义了 speak()
方法,于是可以成功调用。
使用 Object.create()
的好处是,省去了可能会忘记用 new
调用构造式的风险。
Object.create() 的 polyfill
被传进作为参数的对象,将会被当成新对象的原型对象。所以 Object.create()
的 polyfill 可以这样写:
javascript
if (!Object.create) {
Object.create = function(o) {
function F() {}
F.prototype = o;
return new F();
};
}
其中 F()
是构造函数,将构造函数的 prototype
设为传入的对象 o
,并且由 new
运算符调用构造函数,产生新对象。
结论
JavaScript 中可以用构造函数搭配 new 运算符,或是 ES5 的 Object.create()
来创造新对象。
定义构造函数的必要步骤:
- 声明构造函数。
- 在构造函数中,将对象属性定义在
this
上。 - 将对象方法定义在构造式的
prototype
属性里。 - 用
new
运算符调用构造函数。
使用 Object.create(obj)
方法创造的新对象,将继承自 obj
。
发表评论