我对javascript中构造函数的目的有点困惑。我知道通过使用new
关键字创建构造函数也会创建一个全局对象的新实例。这是所有人都可以做到的吗?
此外,新实例的原型与全局对象相同,那么为什么不只是根据需要使用全局对象而不是创建实例?可以为new
实例添加属性吗?
另外,我错过了关于构造函数的要点?任何帮助理解这一点将非常感激。
答案 0 :(得分:3)
“我知道通过使用new关键字创建构造函数也会创建一个全局对象的新实例。”
那不对。 使用new
调用函数创建一个新对象,但它不是全局对象。它是该函数的一个实例,并将该函数作为其.constructor
引用。
prototype
只是构造函数的所有实例指向的对象。它允许您的所有实例引用一组通用属性。
prototype
只是构造函数创建的所有实例都包含隐式指针的对象。它允许您的所有实例引用一组通用属性。
“可以为新实例添加属性吗?”
是的,它们将被添加到从构造函数创建的对象中,而不是它的原型。
function MyConstructor( arg ) {
// If you invoke this with "new",
// then "this" will be a reference to the new instance that is returned
this.instance_prop = arg;
}
MyConstructor.prototype.proto_prop = "baz";
var inst1 = new MyConstructor( "foo" );
var inst2 = new MyConstructor( "bar" );
console.log( inst1.instance_prop ); // foo
console.log( inst1.proto_prop ); // baz
console.log( inst2.instance_prop ); // bar
console.log( inst2.proto_prop ); // baz
编辑:以下是一个非常简单的DOM包装示例:
// constructor
var DOMWrapper = function(id) {
// initialize a count property for the instance created
this.count = 0;
// if a String was passed to the constructor, go head and call fetchById
if (typeof id === 'string') {
this.fetchById(id);
}
};
// fetches an element by the ID given, and calls the .setup() method
DOMWrapper.prototype.fetchById = function(the_id) {
// store the element with this instance
this.element = document.getElementById(the_id);
if( this.element != null ) {
this.setup();
}
};
// stores a function on the .listener property that is passed to
// addEventListener. When clicked, the counter is incremented, and
// appended to the element.
DOMWrapper.prototype.setup = function() {
if (this.element != null) {
// retain a reference to this instance that the listener can use
var wrapper = this;
// store the listener with this instance
this.listener = function() {
wrapper.count++;
wrapper.element.appendChild(
document.createTextNode( ' ' + wrapper.count )
);
// when count is 10, call the tear_down method for this instance
if( wrapper.count === 10 ) {
wrapper.tear_down();
}
};
this.element.addEventListener('click', this.listener, false);
} else {
this.no_element();
}
};
DOMWrapper.prototype.no_element = function() {
alert("you must first fetch an element");
};
// remove the listener that is stored on the .listener property
DOMWrapper.prototype.tear_down = function() {
if (this.element != null) {
if( typeof this.listener === 'function' ) {
this.element.removeEventListener('click', this.listener );
}
} else {
this.no_element();
}
};
<div id="one">element number one</div>
<div id="two">element number two</div>
var wrapper1 = new DOMWrapper(); // constructor with no arguments
wrapper1.fetchById("one"); // you must fetch the element manually
var wrapper2 = new DOMWrapper( "two" ); // with a string, it will fetchById for you
构造函数在从它创建的每个实例上放置一个单独的count
属性初始化为0
。
如果您将构造函数传递给String,它将自动调用fetchById
上的prototype
。否则,您可以在返回新实例后直接调用fetchById()
。
成功getElementById
后,fetchById
会存储在该实例的element
属性中找到的元素,并调用setup
方法,该方法存储click
元素的.listener
属性上的事件侦听器,并使用它来向元素添加click
事件侦听器。
侦听器只是递增该实例的计数器,并将新计数附加到元素。
count
到达10
后,会调用tear_down
方法删除侦听器。
答案 1 :(得分:0)
构造函数是Javascript启用原型继承的方式。
新实例的原型是而不是全局对象 - 它是构造函数的prototype
属性。
function MyConstructor(){
//set member variables of the instance with
this.x = 17;
}
MyConstructor.prototype = {
//stuff in here will be shared by all MyConstructor objects:
foo: function(){
//
},
bar = 17;
}
var x = new MyConstructor();
//x's prototype is the MyConstructor.prototype object.
//the "new" sets the prototype magically behind the scenes.
// x can now use all attributes (and methods) of its prototype as its own:
x.foo();
//this is how OO works in Javascript - there are no "classes"
//note that overwriting a variable that is defined on the prototype overwrites
// only on the instance instead;
x.bar = 42;
vay y = new MyConstructor();
y.bar; //is still 17