В функциях и конструкторах нет ничего волшебного. Все объекты в JavaScript являются & hellip; хорошо, объекты. Но некоторые объекты более специфичны, чем другие, а именно: встроенные объекты. Разница заключается в основном в следующих аспектах:
- Общая обработка объектов. Примеры:
- Числа и строки неизменны (& rArr; константы). Не определены методы для их внутреннего изменения & mdash; новые объекты всегда создаются в результате. Хотя у них есть некоторые врожденные методы, вы не можете их изменить или добавить новые методы. Любые попытки сделать это будут игнорироваться.
null
и undefined
- специальные объекты. Любая попытка использовать метод для этих объектов или определить новые методы вызывает исключение.
- Применимые операторы. JavaScript не позволяет (пере) определять операторы, поэтому мы остановились на том, что доступно.
- Числа имеют особый способ с арифметическими операторами:
+
, -
, *
, /
.
- В строках есть специальный способ обработки оператора конкатенации:
+
.
- Функции имеют специальный способ обработки оператора вызова:
()
и оператора new
. Последний обладает врожденными знаниями о том, как использовать свойство prototype
конструктора, создать объект с соответствующими внутренними ссылками на прототип и вызвать для него функцию конструктора, правильно установив this
.
Если вы загляните в стандарт ECMAScript ( PDF ), то увидите, что все эти «дополнительные» функции определены как методы и свойства, но многие из них напрямую не доступны программистам. Некоторые из них будут представлены в новой редакции стандарта ES3.1 (проект от 15 декабря 2008 г .: PDF ). Одно свойство (__proto__
) уже выставлено в Firefox .
Теперь мы можем ответить на ваш вопрос напрямую. Да, у объекта функции есть свойства, и мы можем добавлять / удалять их по желанию:
var fun = function(){/* ... */};
fun.foo = 2;
console.log(fun.foo); // 2
fun.bar = "Ha!";
console.log(fun.bar); // Ha!
Не имеет значения, что на самом деле делает функция & mdash; это никогда не приходит в игру, потому что мы не называем это! Теперь давайте определим это:
fun = function(){ this.life = 42; };
Сам по себе это не конструктор, это функция, которая работает в своем контексте. И мы можем легко предоставить это:
var context = {ford: "perfect"};
// now let's call our function on our context
fun.call(context);
// it didn't create new object, it modified the context:
console.log(context.ford); // perfect
console.log(context.life); // 42
console.log(context instanceof fun); // false
Как видите, добавлено еще одно свойство к уже существующему объекту.
Чтобы использовать нашу функцию в качестве конструктора, мы должны использовать оператор new
:
var baz = new fun();
// new empty object was created, and fun() was executed on it:
console.log(baz.life); // 42
console.log(baz instanceof fun); // true
Как видите, new
сделал нашу функцию конструктором. Следующие действия были выполнены new
:
- Создан новый пустой объект (
{}
).
- Его внутреннее свойство прототипа было установлено на
fun.prototype
. В нашем случае это будет пустой объект ({}
), потому что мы его не модифицировали.
fun()
был вызван с этим новым объектом в качестве контекста.
В нашу функцию входит изменение нового объекта. Обычно он устанавливает свойства объекта, но может делать все, что ему захочется.
Веселые мелочи:
Поскольку конструктор - это просто объект, мы можем его вычислить:
var A = function(val){ this.a = val; };
var B = function(val){ this.b = val; };
var C = function(flag){ return flag ? A : B; };
// now let's create an object:
var x = new (C(true))(42);
// what kind of object is that?
console.log(x instanceof C); // false
console.log(x instanceof B); // false
console.log(x instanceof A); // true
// it is of A
// let's inspect it
console.log(x.a); // 42
console.log(x.b); // undefined
// now let's create another object:
var y = new (C(false))(33);
// what kind of object is that?
console.log(y instanceof C); // false
console.log(y instanceof B); // true
console.log(y instanceof A); // false
// it is of B
// let's inspect it
console.log(y.a); // undefined
console.log(y.b); // 33
// cool, heh?
Конструктор может вернуть значение, переопределяющее вновь созданный объект:
var A = function(flag){
if(flag){
// let's return something completely different
return {ford: "perfect"};
}
// let's modify the object
this.life = 42;
};
// now let's create two objects:
var x = new A(false);
var y = new A(true);
// let's inspect x
console.log(x instanceof A); // true
console.log(x.ford); // undefined
console.log(x.life); // 42
// let's inspect y
console.log(y instanceof A); // false
console.log(y.ford); // perfect
console.log(y.life); // undefined
Как видите, x
имеет A
с прототипом и всем, тогда как y
- это наш "голый" объект, который мы вернули из конструктора.