Презентацию к данной лекции Вы можете скачать здесь.
Основные архитектурные черты [1, 2]:
invoke(), delay() ).На
В 1992 году компания Nombas начала разработку встраиваемого скриптового языка Cmm (Си-минус-минус), который, по замыслу разработчиков, должен был стать достаточно мощным, чтобы заменить макросы, сохраняя при этом схожесть с Си, чтобы разработчикам не составляло труда изучить его [2]. Главным отличием от Си была работа с памятью. В новом языке все управление памятью осуществлялось автоматически: не было необходимости создавать буферы, объявлять переменные, осуществлять преобразование типов. В остальном языки были сильно похожи друг на друга: в частности, Cmm поддерживал стандартные функции и операторы Си. Cmm был переименован в ScriptEase, поскольку исходное название звучало слишком негативно, а упоминание в нем Си "отпугивало" людей.
На основе этого языка был создан продукт CEnvi. В конце ноября 1995 года Nombas разработала версию CEnvi, внедряемую в веб-страницы. Страницы, которые можно было изменять с помощью скриптового языка, получили название Espresso Pages – они демонстрировали использование скриптового языка для создания игры, проверки пользовательского ввода в формы и создания анимации. Espresso Pages позиционировались как демоверсия, призванная помочь представить, что случится, если в браузер будет внедрен язык Cmm. Работали они только в 16-битовом Netscape Navigator под управлением Windows.
Перед Бренданом Айхом, нанятым в компанию Netscape 4 апреля 1995 года, была поставлена задача внедрить язык программирования Scheme или что-то похожее в браузер Netscape. Поскольку требования были размыты, Айха перевели в группу, ответственную за серверные продукты, где он проработал месяц, занимаясь улучшением протокола HTTP. В мае разработчик был переброшен обратно в команду, занимающуюся клиентской частью (браузером), где он немедленно начал разрабатывать концепцию нового языка программирования. Менеджмент разработки браузера был убежден, что Netscape должен поддерживать язык программирования, встраиваемый в HTML-код страницы.
Помимо Брендона Айха в разработке участвовали один из основателей Netscape Communications Марк Андрисин и один из основателей Sun Microsystems Билл Джой: чтобы успеть закончить работы над языком к релизу браузера, компании заключили соглашение о сотрудничестве в разработке. Они ставили перед собой цель обеспечить "язык для склеивания" составляющих частей веб-ресурса: изображений, плагинов, Java-апплетов, который был бы удобен для веб-дизайнеров и программистов, не обладающих высокой квалификацией.
Первоначально язык назывался LiveScript и предназначался как для программирования на стороне клиента, так и для программирования на стороне сервера (там он должен был называться LiveWire). На синтаксис оказали влияние языки Си и Java, и, поскольку Java в то время было модным словом, 4 декабря 1995 года LiveScript переименовали в
В 1996 году компания Microsoft выпустила аналог языка
По инициативе компании Netscape была проведена стандартизация языка ассоциацией ECMA. Стандартизированная версия имеет название
В статье "Самый непонимаемый язык программирования в мире стал самым популярным в мире языком программирования" [3] Дуглас Крокфорд утверждает, что лидирующую позицию
По данным Black Duck Software в разработке открытого программного обеспечения доля использования
Несмотря на схожий с Си синтаксис,
Однако в
Синтаксис языка
В
//, многострочные и внутристрочные комментарии начинаются с /* и заканчиваются */.Структурно
Если рассматривать
Объектную модель документа иногда рассматривают как отдельную от
Объектная модель браузера – "браузероспецифичная" часть языка, являющаяся прослойкой между ядром и объектной моделью документа. Основное предназначение объектной модели браузера – управление окнами браузера и обеспечение их взаимодействия. Каждое из окон браузера представляется объектом window, центральным объектом
Помимо управления окнами, в рамках объектной модели браузера, браузерами обычно обеспечивается поддержка следующих сущностей:
Объектная модель документа –
В
Number ;String ;Boolean ;Object:Function ;Array ;Date ;RegExp ;Null ;Undefined ;Error.Все числа в Integer, что может привести к неожиданным последствиям, например:
0.1 + 0.2 = 0.30000000000000004
Поддержаны стандартные арифметические операторы, такие как сложение, деление, остаток от деления и так далее. Здесь стоит вспомнить встроенный объект Math содержащий математические методы:
Math.sin(3.5); d = Math.PI * r * r;
С использованием встроенной функции parseInt() можно преобразовать строку в число. Вторым параметром эта функция принимает базу, которую стоит всегда указывать во избежание казусов:
parseInt("123", 10) //результат – "123"
parseInt("010", 10) //результат – "10"
а если не указать базу то получим:
parseInt("010") //результат – "8"
Это произошло, потому что parseInt посчитало число восьмеричным из-за предшествующего 0.
Если функция не может преобразовать строку в число, она возвращает специальное значение NaN (сокращение от "Не Число"):
parseInt("Привет", 10) //результат – "NaN"
Результатом математической операции с NaN всегда будет NaN:
NaN + 5 //результат – "NaN"
Можно проверить значение на равенство NaN переменной с помощью встроенной функции isNaN():
isNaN(NaN) //результат – "true"
В и -:
1 / 0 //результат – "Infinity" -1 / 0 //результат – "-Infinity"
Strings в length:
"Привет".length //результат – "5"
Также строка имеет набор полезных методов:
"Привет".charAt(0) //результат – "П"
"Привет, мир!".replace("Привет", "Прощай") //результат – "Прощай, мир!"
"Привет".toUpperCase() //результат – "ПРИВЕТ"
null – явное (программно-установленное) пустое значения, и значение undefined типа "undefined", которое говорит о том, что значение еще не было назначено:
typeof null //результат – "object" typeof undefined //результат – "undefined"
В undefined.
В true и false (оба являются ключевыми словами в
false, 0, пустая строка ( "" ), NaN, null, и undefined трактуются как false ;true.Преобразование можно провести в явном виде с использованием функции Boolean():
Boolean("") //результат – "false"
Boolean(234) //результат – "true"
Эта возможность используется достаточно редко, поскольку такое преобразование производится автоматически в тех случаях, когда ожидается логическое значение, как в выражении if. Поэтому обычно просто говорят о "истинных значениях" и "ложных значениях", подразумевая, в какое из логических значений оно преобразуется.
Поддерживаются стандартные логические операторы ! (логическое не ).
Переменная в var:
var a; var name = "Иван";
В +, -, *, / и % (остаток от деления). Значения присваиваются оператором =, также есть операторы составного присваивания += и -=. Они позволяют записать короче часто встречающиеся выражения типа: x = x operator y:
x += 5 x = x + 5
Можно использовать ++ и -- для увеличения или уменьшения значения переменной на единицу. Помещать этот оператор можно как за символом переменной ( i++ ) так и перед или ( ++i ).
Оператор " + " применяется еще и для конкатенации строк:
"Привет, " + "мир!" //результат – "Привет, мир!"
При добавлении строки к числу последнее автоматически конвертируется в строку:
"3" + 4 + 5 //результат – "345" 3 + 4 + "5" //результат – "75"
Добавление пустой строки к чему-либо можно использовать, как преобразование к строке.
В <, >, <= и >=. Их можно использовать и со строками и с числами. Сравнение значений уже несколько сложнее. Оператор двойного равенства производит преобразование типов, что может привести к несколько неожиданным результатам:
"Привет" == "Привет" //результат – "true" 1 == true //результат – "true"
Чтобы этого избежать следует использовать оператор тройного равенства, который учитывает типы:
1 === true //результат – "false" true === true //результат – "true"
Есть также обратные операторы != и !== для двойного и тройного равенства соответственно.
if и else, из которых можно делать цепочки:
var name = "Котенок";
if (name == "Щенок") {
name += "!";
} else if (name == "Котенок") {
name += "!!";
} else {
name = "!" + name;
}
name == Котенок!!"
В while и do-while. Первый можно использовать для бесконечного цикла; второй в том случае если вы хотите, чтобы тело цикла выполнилось как минимум один раз:
while (true) {
// Бесконечный цикл!
}
do {
var input = get_input();
}
while (inputIsNotValid(input))
В for такой же, как в C, C# и Java:
for (var i = 0; i < 5; i++) {
// будет выполнен 5 раз
}
Операторы и || "закорачиваются", т.е. будет ли выполнен или нет второй операнд, зависит от значения первого. Это можно использовать для проверки значения объекта на null перед тем как пытаться прочитать его свойства:
var name = o o.getName();
Или для установки значений по умолчанию:
var name = otherName || "default";
В
var allowed = (age > 18) ? "Да" : "Нет";
Конструкция switch может быть использована для разветвления на основании числового или строчного значения:
switch (action) {
case 'Рисовать':
drawit();
break;
case 'Есть':
eatit();
break;
default:
donothing();
}
Если забыть написать break, то выполнение "провалится" в следующий case:
switch (a) {
case 1: // проваливаемся
case 2:
eatit();
break;
default:
donothing();
}
Выражение default необязательно, его можно опустить.
Можно использовать "выражения" как в switch, так и в case ; сравнение будет проводиться с использованием оператора тройного равенства ===:
switch(1 + 3):
case 2 + 2:
yay();
break;
default:
neverhappens();
}
В
Так как в
"Ключ" должен быть в
Есть два способа создать объект:
var obj = new Object();
или
var obj = {};
Эти два способа абсолютно идентичны. Второй способ называется объектный литерал.
После создания объекта ему можно присвоить свойства двумя способами:
obj.name = "Иван" var name = obj.name;
или
obj["name"] = "Иван"; var name = obj["name"];
Эти два варианта дают один и тот же результат. Во втором случае имя свойства передается, как строка и может быть вычислено динамически во время выполнения. Также через квадратные скобки можно установить и получить свойства с именами из зарезервированных в
obj.for = "Иван"; // Синтаксическая ошибка, т.к. 'for' является зарезервированным словом obj["for"] = "Иван"; // Нет ошибки
Объектно-литеральный синтаксис может быть использован для определения свойств объекта в момент его создания:
var obj = {
name: "Петров",
"for": "Иван",
details: {
color: "orange",
size: 12
}
}
Доступ к свойствам можно выстраивать в цепь (т.е. вызывать свойства свойств и т.д.):
obj.details.color //результат – "orange" obj["details"]["size"] //результат – "12"
Массивы в [] синтаксис), но имеют свойство "length", значение которого всегда больше на единицу наибольшего индекса в массиве.
Старый способ создания массивов:
var a = new Array(); a[0] = "собака"; a[1] = "кошка"; a[2] = "мышь"; a.length //результат – "3"
Более удобен "массивно-литеральный" синтаксис:
var a = ["собака", "кошка", "мышь"]; a.length //результат – "3"
Необходимо помнить, что array.length не всегда число элементов массива:
var a = ["собака", "кошка", "мышь"]; a[100] = "лиса"; a.length //результат – "101"
Длина массива это просто число на единицу большее наибольшего индекса.
Если запросить элемент с несуществующим индексом, то будет возвращено undefined:
typeof (a[90]) //результат – "undefined"
Обойти массив можно вот так:
for (var i = 0; i < a.length; i++) {
// работаем с a[i]
}
Но этот способ немного не эффективен, поскольку свойство length будет выбираться на каждом цикле.
Безопасный способ добавления элемента к концу массива:
a[a.length] = item; //тоже что и a.push(item);
Поскольку a.length на единицу больше наибольшего индекса, вы можно быть уверенным, что добавлен элемент в пустую позицию в конец массива.
Массивы имеют набор встроенных методов:
concat возвращает новый массив с элементами, добавленными к нему;pop удаляет из массива и возвращает последний элемент;push добавляет один или несколько элементов в конец массива (также как ar[ar.length] );sort сортирует элементы в качестве необязательного параметра можно передать функцию;splice позволяет удалить или заменить целый интервал элементов в массиве;unshift добавляет элемент в начало массива.Вместе с объектами функции играют ключевую роль в
function add(x, y) {
var total = x + y;
return total;
}
В 0 и больше именованных параметров. Тело функции может содержать любые выражения return может быть использовано в любое время для прекращения выполнения функции и возврата значения. Если return отсутствует или не возвращает значения (пустой return ), функция возвращает undefined.
Именованные параметры условны, т.е. можно вызвать функцию без параметров или с лишними параметрами. В первом случае значения параметров будут установлены в undefined:
add() //результат – "NaN", т.к. undefined нельзя складывать
Также можно передать аргументов больше, чем ожидает функция:
add(2, 3, 4) //результат – "5", т.к. складывает первые два параметра, а 4 игнорируется
Внутри тела функции доступна дополнительная переменная "arguments". Это "массиво-подобный" объект, в котором хранятся все переменные, переданные в функцию. Перепишем предыдущую функцию, чтобы она суммировала все параметры, которые ей передают:
function add() {
var sum = 0;
for (var i = 0, j = arguments.length; i < j; i++) {
sum += arguments[i];
}
return sum;
}
И вызовем ее:
add(2, 3, 4, 5) //результат – "14"
Напишем функцию для подсчета среднего арифметического:
function avg() {
var sum = 0;
for (var i = 0, j = arguments.length; i < j; i++) {
sum += arguments[i];
}
return sum / arguments.length;
}
И вызовем ее:
avg(2, 3, 4, 5) //результат – "3.5"
Если мы захотим вычислить среднее по массиву, то можно переписать функцию, но можно воспользоваться уже существующей, поскольку в
Первый это классический func(). Любую функцию можно вызвать также с помощью встроенного в Function метода apply(), который вызовет функцию с параметрами, переданными в виде массива в apply() вторым параметром:
avg.apply(null, [2, 3, 4, 5]) //результат – "3.5"
var avg = function() {
var sum = 0;
for (var i = 0, j = arguments.length; i < j; i++) {
sum += arguments[i];
}
return sum / arguments.length;
}
function countChars(elm) {
if (elm.nodeType == 3) {
return elm.nodeValue.length;
}
var count = 0;
for (var i = 0, child; child = elm.childNodes[i]; i++) {
count += countChars(child);
}
return count;
}
В классических объектно-ориентированных языках объект – это коллекция данных и методов, оперирующих этими данными [5].
Рассмотрим объект person с полями first и last name (имя и фамилия). Предположим, надо иметь два метода для различных отображений полного имени: как "first last" или как "last, first". Это можно сделать с использованием объекта и функций следующим образом:
function makePerson(first, last) {
return {
first: first,
last: last
}
}
function personFullName(person) {
return person.first + ' ' + person.last;
}
function personFullNameReversed(person) {
return person.last + ', ' + person.first
}
Тогда при вызове этих функций:
s = makePerson("Иван", "Петров");
personFullName(s) //результат – "Иван Петров"
personFullNameReversed(s) //результат – "Петров, Иван"
Но если необходимо как-то присоединять имена функций к объектам, то, как это делается в обычных объектно-ориентированных языках программирования, то можно написать следующий код:
function makePerson(first, last) {
return {
first: first,
last: last,
fullName: function() {
return this.first + ' ' + this.last;
},
fullNameReversed: function() {
return this.last + ', ' + this.first;
}
}
}
Тогда при вызове этих функций:
s = makePerson("Иван", "Петров")
s.fullName()//результат – "Иван Петров"
s.fullNameReversed()//результат – "Петров, Иван"
Здесь встречается ключевое словом "this". При использовании внутри функции "this" ссылается на текущий объект. Чему будет равно "this" на самом деле зависит от того как была вызвана функция. Если функция будет вызвана через "this" указывает на этот объект. Если просто вызвать функцию, то "this" будет указывать на глобальный объект. Непонимание этого может привести к неприятным последствиям:
s = makePerson("Иван", "Петров")
var fullName = s.fullName;
fullName()//результат – "undefined undefined"
Когда вызывается fullName(), в роли "this" выступает глобальный объект. И поскольку не определены глобальные переменные first и last, для каждой из них будет получено undefined.
Можно использовать "this" для усовершенствования нашей функции makePerson:
function Person(first, last) {
this.first = first;
this.last = last;
this.fullName = function() {
return this.first + ' ' + this.last;
}
this.fullNameReversed = function() {
return this.last + ', ' + this.first;
}
}
var s = new Person("Иван", "Петров");
Здесь присутствует ключевое слово "new". "new" связан с "this". Он создает пустой объект и вызывает указанную функцию, внутри которой "this" указывает на этот новый объект. Функции, которые будут использоваться вместе с "new" называются "конструкторами". Обычно название таких функций начинается с заглавной буквы, и напоминает о том, что функция должна быть использована вместе с "new".
Однако до сих пор остались некоторые проблемы: каждый раз при создании объекта, необходимо создавать по две новых функции внутри него. Разделим эти функции между всеми объектами:
function personFullName() {
return this.first + ' ' + this.last;
}
function personFullNameReversed() {
return this.last + ', ' + this.first;
}
function Person(first, last) {
this.first = first;
this.last = last;
this.fullName = personFullName;
this.fullNameReversed = personFullNameReversed;
}
Теперь функции будут создаваться только один раз, а ссылки на них назначаются в конструкторе. Однако существует более хороший вариант:
function Person(first, last) {
this.first = first;
this.last = last;
}
Person.prototype.fullName = function() {
return this.first + ' ' + this.last;
}
Person.prototype.fullNameReversed = function() {
return this.last + ', ' + this.first;
}
Person.prototype это объект общий для всех объектов, созданных с помощью Person. Он входит в "prototype chain" (Person, которое у него отсутствует, Person.prototype. Таким образом, все, что будет присвоено Person.prototype становится доступно всем объектам порожденным конструктором Person, в том числе и через объект this.
Это необычайно мощное средство. В prototype (прототипы) объектов в любое время и в любом месте программы, что означает, что можно добавлять методы к объектам в процессе выполнения программы:
s = new Person("Иван", "Петров");
s.firstNameCaps(); //результат – "TypeError on line 1: s.firstNameCaps is not a function"
Person.prototype.firstNameCaps = function() {
return this.first.toUpperCase()
}
s.firstNameCaps() //результат – "ИВАН"
Как уже упоминалось, прототип является частью цепочки, в конце которой находится Object.prototype, у которого есть метод toString() – он вызывается, когда объект приводится к строке. И его можно переопределить для отладки:
var s = new Person("Иван", "Петров");
s //результат – "[object Object]"
Person.prototype.toString = function() {
return '<ФИО: ' + this.fullName() + '>';
}
s //результат – "<ФИО: Иван Петров>"
Теперь вернемся к рассмотрению первого параметр метода avg.apply().Первый параметр apply() это объект, на который будет ссылаться ключевое слово "this", если оно используется в теле вызываемой функции. Например, можно сделать тривиальную реализацию "new":
function trivialNew(constructor) {
var o = {}; // создаем объект
constructor.apply(o, arguments);
return o;
}
Это конечно не совсем "new", так как не создается прототипная цепочка ( prototype chain ).
Для apply() есть похожая функция call, которая также позволяет установить "this", но вместо массива параметров принимает параметры через запятую (как при обычном вызове):
function lastNameCaps() {
return this.last.toUpperCase();
}
var s = new Person("Иван", "Петров");
lastNameCaps.call(s);
// Тоже самое, что и:
s.lastNameCaps = lastNameCaps;
s.lastNameCaps();
В
function betterExampleNeeded() {
var a = 1;
function oneMoreThanA() {
return a + 1;
}
return oneMoreThanA();
}
Это позволяет не засорять глобальный контекст ( scope ) именами функций, которые нужны для решения частных проблем в одной части кода. А также разделять переменные между разными вложенными функциями, не пользуясь глобальным пространством имен.
Для добавления <script></script>. Скрипт, выводящий "Hello, World!" внутри браузера:
<script type="text/javascript">
alert('Hello, World!');
</script>
Спецификация HTML описывает набор атрибутов, используемых для задания обработчиков событий. Пример использования:
<a href="delete.php" onclick="return confirm('Вы уверены?');">Удалить</a>
В приведенном примере при нажатии на ссылку функция confirm('Вы уверены?') ; вызывает return false; блокирует переход по ссылке. Разумеется, этот код будет работать, только если в браузере есть и включена поддержка
Использование кода alertLink ):
<a href="delete.aspx" id="alertLink">Удалить</a>
приведенного примера может выступать, например, следующий фрагмент
window.onload = function() {
var linkWithAlert = document.getElementById("alertLink");
linkWithAlert.onclick = function() {
return confirm('Вы уверены?');
};
};
Есть и третья возможность подключения
<script type="text/javascript" src="http://Путь_к_файлу_со_скриптом"></script>
Тег script, широко используемый для подключения к странице
type для указания MIME-типа содержимого;
необязательный атрибут src, принимающий в качестве значения адрес к файлу со скриптом;charset, используемый вместе с src для указания используемой кодировки внешнего файла;defer, используемый для того, чтобы показать, что скрипт не генерирует никакого содержимого (что означает, в частности, то, что в этом скрипте отсутствует вызов document.write() ).При этом атрибут language (language="JavaScript"), несмотря на его активное использование, относится к не рекомендуемым (
(рис 12.1) Пример сеанса eyeOS [8]
Пользовательские скрипты в браузере – это программы, написанные на
Приложения, написанные на
Перевод мобильных устройств Palm на использование Palm webOS в качестве операционной системы с Mojo SDK в качестве средств разработки позволяет использовать
Виджет – вспомогательная мини-программа, графический модуль, которой размещается в рабочем пространстве соответствующей родительской программы, служащая для украшения рабочего пространства, развлечения, решения отдельных рабочих задач или быстрого получения информации из интернета без помощи веб-браузера.
Google Chrome OS в качестве прикладного ПО использует Веб-приложения.
Для обеспечения высокого уровня абстракции и достижения приемлемой степени кросс-браузерности при разработке веб-приложений используются библиотеки
Среди известных
На сегодняшний день поддержку
sandbox ), в которой они могут выполнять только ограниченный круг действий, а не задачи программирования общего назначения (например, создание файлов, работа с сокетами);document ) при отличии в протоколе, хосте и номере порта этих страниц.Помимо этого, разработчики браузеров вносят дополнительные ограничения в ответ на имеющие место злоупотребления. Так появился, в частности, запрет на открытие окна, размер одной стороны которого меньше ста пиксел.
Общая проблема, касающаяся
Уязвимости
Другим типом межсайтовой уязвимости является подделка межсайтовых запросов или CSRF. Она заключается в возможности сайта злоумышленника заставить браузер пользователя осуществить нежелательное действие на целевом сайте (например, банковский перевод денег). Такая возможность имеется, если целевой сайт полагается только на HTTP cookie или запросы авторизации. В этом случае запросы, инициализированные кодом сайта злоумышленника, выполняются так же как запросы пользователя, если он авторизован на целевом сайте. Одним из средств защиты от CSRF является осуществление аутентификации при любом запросе, который приводит к необратимым последствиям.
Подобные ошибки выявлялись у часто используемых браузеров, включая Mozilla Firefox, Internet Explorer, Safari. При выявлении потенциально опасных ошибок в браузере и наличия сведений о реализованных эксплойтов фирма-производитель и эксперты по безопасности рекомендуют отключать
Плагины, такие как плееры, Macromedia Flash и ряд ActiveX компонент, доступных по умолчанию в Internet Explorer, могут также содержать ошибки, эксплуатируемые с помощью
Расширения Mozilla Firefox не изолированы друг от друга: одно расширение может исправлять другое, что может использоваться злоумышленниками.
Браузеры могут запускать
Неправильное наделение привилегиями
Microsoft Windows позволяет файлам с кодом
Основные архитектурные черты
Структурно
В
Boolean );Null ;Undefined ;Error.Для добавления <script></script>. При этом
Область применения
Среди известных
На сегодняшний день поддержку
В целях безопасности
Презентацию к данной лекции Вы можете скачать здесь.
Основные архитектурные черты [1, 2]:
invoke(), delay() ).На
В 1992 году компания Nombas начала разработку встраиваемого скриптового языка Cmm (Си-минус-минус), который, по замыслу разработчиков, должен был стать достаточно мощным, чтобы заменить макросы, сохраняя при этом схожесть с Си, чтобы разработчикам не составляло труда изучить его [2]. Главным отличием от Си была работа с памятью. В новом языке все управление памятью осуществлялось автоматически: не было необходимости создавать буферы, объявлять переменные, осуществлять преобразование типов. В остальном языки были сильно похожи друг на друга: в частности, Cmm поддерживал стандартные функции и операторы Си. Cmm был переименован в ScriptEase, поскольку исходное название звучало слишком негативно, а упоминание в нем Си "отпугивало" людей.
На основе этого языка был создан продукт CEnvi. В конце ноября 1995 года Nombas разработала версию CEnvi, внедряемую в веб-страницы. Страницы, которые можно было изменять с помощью скриптового языка, получили название Espresso Pages – они демонстрировали использование скриптового языка для создания игры, проверки пользовательского ввода в формы и создания анимации. Espresso Pages позиционировались как демоверсия, призванная помочь представить, что случится, если в браузер будет внедрен язык Cmm. Работали они только в 16-битовом Netscape Navigator под управлением Windows.
Перед Бренданом Айхом, нанятым в компанию Netscape 4 апреля 1995 года, была поставлена задача внедрить язык программирования Scheme или что-то похожее в браузер Netscape. Поскольку требования были размыты, Айха перевели в группу, ответственную за серверные продукты, где он проработал месяц, занимаясь улучшением протокола HTTP. В мае разработчик был переброшен обратно в команду, занимающуюся клиентской частью (браузером), где он немедленно начал разрабатывать концепцию нового языка программирования. Менеджмент разработки браузера был убежден, что Netscape должен поддерживать язык программирования, встраиваемый в HTML-код страницы.
Помимо Брендона Айха в разработке участвовали один из основателей Netscape Communications Марк Андрисин и один из основателей Sun Microsystems Билл Джой: чтобы успеть закончить работы над языком к релизу браузера, компании заключили соглашение о сотрудничестве в разработке. Они ставили перед собой цель обеспечить "язык для склеивания" составляющих частей веб-ресурса: изображений, плагинов, Java-апплетов, который был бы удобен для веб-дизайнеров и программистов, не обладающих высокой квалификацией.
Первоначально язык назывался LiveScript и предназначался как для программирования на стороне клиента, так и для программирования на стороне сервера (там он должен был называться LiveWire). На синтаксис оказали влияние языки Си и Java, и, поскольку Java в то время было модным словом, 4 декабря 1995 года LiveScript переименовали в
В 1996 году компания Microsoft выпустила аналог языка
По инициативе компании Netscape была проведена стандартизация языка ассоциацией ECMA. Стандартизированная версия имеет название
В статье "Самый непонимаемый язык программирования в мире стал самым популярным в мире языком программирования" [3] Дуглас Крокфорд утверждает, что лидирующую позицию
По данным Black Duck Software в разработке открытого программного обеспечения доля использования
Несмотря на схожий с Си синтаксис,
Однако в
Синтаксис языка
В
//, многострочные и внутристрочные комментарии начинаются с /* и заканчиваются */.Структурно
Если рассматривать
Объектную модель документа иногда рассматривают как отдельную от
Объектная модель браузера – "браузероспецифичная" часть языка, являющаяся прослойкой между ядром и объектной моделью документа. Основное предназначение объектной модели браузера – управление окнами браузера и обеспечение их взаимодействия. Каждое из окон браузера представляется объектом window, центральным объектом
Помимо управления окнами, в рамках объектной модели браузера, браузерами обычно обеспечивается поддержка следующих сущностей:
Объектная модель документа –
В
Number ;String ;Boolean ;Object:Function ;Array ;Date ;RegExp ;Null ;Undefined ;Error.Все числа в Integer, что может привести к неожиданным последствиям, например:
0.1 + 0.2 = 0.30000000000000004
Поддержаны стандартные арифметические операторы, такие как сложение, деление, остаток от деления и так далее. Здесь стоит вспомнить встроенный объект Math содержащий математические методы:
Math.sin(3.5); d = Math.PI * r * r;
С использованием встроенной функции parseInt() можно преобразовать строку в число. Вторым параметром эта функция принимает базу, которую стоит всегда указывать во избежание казусов:
parseInt("123", 10) //результат – "123"
parseInt("010", 10) //результат – "10"
а если не указать базу то получим:
parseInt("010") //результат – "8"
Это произошло, потому что parseInt посчитало число восьмеричным из-за предшествующего 0.
Если функция не может преобразовать строку в число, она возвращает специальное значение NaN (сокращение от "Не Число"):
parseInt("Привет", 10) //результат – "NaN"
Результатом математической операции с NaN всегда будет NaN:
NaN + 5 //результат – "NaN"
Можно проверить значение на равенство NaN переменной с помощью встроенной функции isNaN():
isNaN(NaN) //результат – "true"
В и -:
1 / 0 //результат – "Infinity" -1 / 0 //результат – "-Infinity"
Strings в length:
"Привет".length //результат – "5"
Также строка имеет набор полезных методов:
"Привет".charAt(0) //результат – "П"
"Привет, мир!".replace("Привет", "Прощай") //результат – "Прощай, мир!"
"Привет".toUpperCase() //результат – "ПРИВЕТ"
null – явное (программно-установленное) пустое значения, и значение undefined типа "undefined", которое говорит о том, что значение еще не было назначено:
typeof null //результат – "object" typeof undefined //результат – "undefined"
В undefined.
В true и false (оба являются ключевыми словами в
false, 0, пустая строка ( "" ), NaN, null, и undefined трактуются как false ;true.Преобразование можно провести в явном виде с использованием функции Boolean():
Boolean("") //результат – "false"
Boolean(234) //результат – "true"
Эта возможность используется достаточно редко, поскольку такое преобразование производится автоматически в тех случаях, когда ожидается логическое значение, как в выражении if. Поэтому обычно просто говорят о "истинных значениях" и "ложных значениях", подразумевая, в какое из логических значений оно преобразуется.
Поддерживаются стандартные логические операторы ! (логическое не ).
Переменная в var:
var a; var name = "Иван";
В +, -, *, / и % (остаток от деления). Значения присваиваются оператором =, также есть операторы составного присваивания += и -=. Они позволяют записать короче часто встречающиеся выражения типа: x = x operator y:
x += 5 x = x + 5
Можно использовать ++ и -- для увеличения или уменьшения значения переменной на единицу. Помещать этот оператор можно как за символом переменной ( i++ ) так и перед или ( ++i ).
Оператор " + " применяется еще и для конкатенации строк:
"Привет, " + "мир!" //результат – "Привет, мир!"
При добавлении строки к числу последнее автоматически конвертируется в строку:
"3" + 4 + 5 //результат – "345" 3 + 4 + "5" //результат – "75"
Добавление пустой строки к чему-либо можно использовать, как преобразование к строке.
В <, >, <= и >=. Их можно использовать и со строками и с числами. Сравнение значений уже несколько сложнее. Оператор двойного равенства производит преобразование типов, что может привести к несколько неожиданным результатам:
"Привет" == "Привет" //результат – "true" 1 == true //результат – "true"
Чтобы этого избежать следует использовать оператор тройного равенства, который учитывает типы:
1 === true //результат – "false" true === true //результат – "true"
Есть также обратные операторы != и !== для двойного и тройного равенства соответственно.
if и else, из которых можно делать цепочки:
var name = "Котенок";
if (name == "Щенок") {
name += "!";
} else if (name == "Котенок") {
name += "!!";
} else {
name = "!" + name;
}
name == Котенок!!"
В while и do-while. Первый можно использовать для бесконечного цикла; второй в том случае если вы хотите, чтобы тело цикла выполнилось как минимум один раз:
while (true) {
// Бесконечный цикл!
}
do {
var input = get_input();
}
while (inputIsNotValid(input))
В for такой же, как в C, C# и Java:
for (var i = 0; i < 5; i++) {
// будет выполнен 5 раз
}
Операторы и || "закорачиваются", т.е. будет ли выполнен или нет второй операнд, зависит от значения первого. Это можно использовать для проверки значения объекта на null перед тем как пытаться прочитать его свойства:
var name = o o.getName();
Или для установки значений по умолчанию:
var name = otherName || "default";
В
var allowed = (age > 18) ? "Да" : "Нет";
Конструкция switch может быть использована для разветвления на основании числового или строчного значения:
switch (action) {
case 'Рисовать':
drawit();
break;
case 'Есть':
eatit();
break;
default:
donothing();
}
Если забыть написать break, то выполнение "провалится" в следующий case:
switch (a) {
case 1: // проваливаемся
case 2:
eatit();
break;
default:
donothing();
}
Выражение default необязательно, его можно опустить.
Можно использовать "выражения" как в switch, так и в case ; сравнение будет проводиться с использованием оператора тройного равенства ===:
switch(1 + 3):
case 2 + 2:
yay();
break;
default:
neverhappens();
}
В
Так как в
"Ключ" должен быть в
Есть два способа создать объект:
var obj = new Object();
или
var obj = {};
Эти два способа абсолютно идентичны. Второй способ называется объектный литерал.
После создания объекта ему можно присвоить свойства двумя способами:
obj.name = "Иван" var name = obj.name;
или
obj["name"] = "Иван"; var name = obj["name"];
Эти два варианта дают один и тот же результат. Во втором случае имя свойства передается, как строка и может быть вычислено динамически во время выполнения. Также через квадратные скобки можно установить и получить свойства с именами из зарезервированных в
obj.for = "Иван"; // Синтаксическая ошибка, т.к. 'for' является зарезервированным словом obj["for"] = "Иван"; // Нет ошибки
Объектно-литеральный синтаксис может быть использован для определения свойств объекта в момент его создания:
var obj = {
name: "Петров",
"for": "Иван",
details: {
color: "orange",
size: 12
}
}
Доступ к свойствам можно выстраивать в цепь (т.е. вызывать свойства свойств и т.д.):
obj.details.color //результат – "orange" obj["details"]["size"] //результат – "12"
Массивы в [] синтаксис), но имеют свойство "length", значение которого всегда больше на единицу наибольшего индекса в массиве.
Старый способ создания массивов:
var a = new Array(); a[0] = "собака"; a[1] = "кошка"; a[2] = "мышь"; a.length //результат – "3"
Более удобен "массивно-литеральный" синтаксис:
var a = ["собака", "кошка", "мышь"]; a.length //результат – "3"
Необходимо помнить, что array.length не всегда число элементов массива:
var a = ["собака", "кошка", "мышь"]; a[100] = "лиса"; a.length //результат – "101"
Длина массива это просто число на единицу большее наибольшего индекса.
Если запросить элемент с несуществующим индексом, то будет возвращено undefined:
typeof (a[90]) //результат – "undefined"
Обойти массив можно вот так:
for (var i = 0; i < a.length; i++) {
// работаем с a[i]
}
Но этот способ немного не эффективен, поскольку свойство length будет выбираться на каждом цикле.
Безопасный способ добавления элемента к концу массива:
a[a.length] = item; //тоже что и a.push(item);
Поскольку a.length на единицу больше наибольшего индекса, вы можно быть уверенным, что добавлен элемент в пустую позицию в конец массива.
Массивы имеют набор встроенных методов:
concat возвращает новый массив с элементами, добавленными к нему;pop удаляет из массива и возвращает последний элемент;push добавляет один или несколько элементов в конец массива (также как ar[ar.length] );sort сортирует элементы в качестве необязательного параметра можно передать функцию;splice позволяет удалить или заменить целый интервал элементов в массиве;unshift добавляет элемент в начало массива.Вместе с объектами функции играют ключевую роль в
function add(x, y) {
var total = x + y;
return total;
}
В 0 и больше именованных параметров. Тело функции может содержать любые выражения return может быть использовано в любое время для прекращения выполнения функции и возврата значения. Если return отсутствует или не возвращает значения (пустой return ), функция возвращает undefined.
Именованные параметры условны, т.е. можно вызвать функцию без параметров или с лишними параметрами. В первом случае значения параметров будут установлены в undefined:
add() //результат – "NaN", т.к. undefined нельзя складывать
Также можно передать аргументов больше, чем ожидает функция:
add(2, 3, 4) //результат – "5", т.к. складывает первые два параметра, а 4 игнорируется
Внутри тела функции доступна дополнительная переменная "arguments". Это "массиво-подобный" объект, в котором хранятся все переменные, переданные в функцию. Перепишем предыдущую функцию, чтобы она суммировала все параметры, которые ей передают:
function add() {
var sum = 0;
for (var i = 0, j = arguments.length; i < j; i++) {
sum += arguments[i];
}
return sum;
}
И вызовем ее:
add(2, 3, 4, 5) //результат – "14"
Напишем функцию для подсчета среднего арифметического:
function avg() {
var sum = 0;
for (var i = 0, j = arguments.length; i < j; i++) {
sum += arguments[i];
}
return sum / arguments.length;
}
И вызовем ее:
avg(2, 3, 4, 5) //результат – "3.5"
Если мы захотим вычислить среднее по массиву, то можно переписать функцию, но можно воспользоваться уже существующей, поскольку в
Первый это классический func(). Любую функцию можно вызвать также с помощью встроенного в Function метода apply(), который вызовет функцию с параметрами, переданными в виде массива в apply() вторым параметром:
avg.apply(null, [2, 3, 4, 5]) //результат – "3.5"
var avg = function() {
var sum = 0;
for (var i = 0, j = arguments.length; i < j; i++) {
sum += arguments[i];
}
return sum / arguments.length;
}
function countChars(elm) {
if (elm.nodeType == 3) {
return elm.nodeValue.length;
}
var count = 0;
for (var i = 0, child; child = elm.childNodes[i]; i++) {
count += countChars(child);
}
return count;
}
В классических объектно-ориентированных языках объект – это коллекция данных и методов, оперирующих этими данными [5].
Рассмотрим объект person с полями first и last name (имя и фамилия). Предположим, надо иметь два метода для различных отображений полного имени: как "first last" или как "last, first". Это можно сделать с использованием объекта и функций следующим образом:
function makePerson(first, last) {
return {
first: first,
last: last
}
}
function personFullName(person) {
return person.first + ' ' + person.last;
}
function personFullNameReversed(person) {
return person.last + ', ' + person.first
}
Тогда при вызове этих функций:
s = makePerson("Иван", "Петров");
personFullName(s) //результат – "Иван Петров"
personFullNameReversed(s) //результат – "Петров, Иван"
Но если необходимо как-то присоединять имена функций к объектам, то, как это делается в обычных объектно-ориентированных языках программирования, то можно написать следующий код:
function makePerson(first, last) {
return {
first: first,
last: last,
fullName: function() {
return this.first + ' ' + this.last;
},
fullNameReversed: function() {
return this.last + ', ' + this.first;
}
}
}
Тогда при вызове этих функций:
s = makePerson("Иван", "Петров")
s.fullName()//результат – "Иван Петров"
s.fullNameReversed()//результат – "Петров, Иван"
Здесь встречается ключевое словом "this". При использовании внутри функции "this" ссылается на текущий объект. Чему будет равно "this" на самом деле зависит от того как была вызвана функция. Если функция будет вызвана через "this" указывает на этот объект. Если просто вызвать функцию, то "this" будет указывать на глобальный объект. Непонимание этого может привести к неприятным последствиям:
s = makePerson("Иван", "Петров")
var fullName = s.fullName;
fullName()//результат – "undefined undefined"
Когда вызывается fullName(), в роли "this" выступает глобальный объект. И поскольку не определены глобальные переменные first и last, для каждой из них будет получено undefined.
Можно использовать "this" для усовершенствования нашей функции makePerson:
function Person(first, last) {
this.first = first;
this.last = last;
this.fullName = function() {
return this.first + ' ' + this.last;
}
this.fullNameReversed = function() {
return this.last + ', ' + this.first;
}
}
var s = new Person("Иван", "Петров");
Здесь присутствует ключевое слово "new". "new" связан с "this". Он создает пустой объект и вызывает указанную функцию, внутри которой "this" указывает на этот новый объект. Функции, которые будут использоваться вместе с "new" называются "конструкторами". Обычно название таких функций начинается с заглавной буквы, и напоминает о том, что функция должна быть использована вместе с "new".
Однако до сих пор остались некоторые проблемы: каждый раз при создании объекта, необходимо создавать по две новых функции внутри него. Разделим эти функции между всеми объектами:
function personFullName() {
return this.first + ' ' + this.last;
}
function personFullNameReversed() {
return this.last + ', ' + this.first;
}
function Person(first, last) {
this.first = first;
this.last = last;
this.fullName = personFullName;
this.fullNameReversed = personFullNameReversed;
}
Теперь функции будут создаваться только один раз, а ссылки на них назначаются в конструкторе. Однако существует более хороший вариант:
function Person(first, last) {
this.first = first;
this.last = last;
}
Person.prototype.fullName = function() {
return this.first + ' ' + this.last;
}
Person.prototype.fullNameReversed = function() {
return this.last + ', ' + this.first;
}
Person.prototype это объект общий для всех объектов, созданных с помощью Person. Он входит в "prototype chain" (Person, которое у него отсутствует, Person.prototype. Таким образом, все, что будет присвоено Person.prototype становится доступно всем объектам порожденным конструктором Person, в том числе и через объект this.
Это необычайно мощное средство. В prototype (прототипы) объектов в любое время и в любом месте программы, что означает, что можно добавлять методы к объектам в процессе выполнения программы:
s = new Person("Иван", "Петров");
s.firstNameCaps(); //результат – "TypeError on line 1: s.firstNameCaps is not a function"
Person.prototype.firstNameCaps = function() {
return this.first.toUpperCase()
}
s.firstNameCaps() //результат – "ИВАН"
Как уже упоминалось, прототип является частью цепочки, в конце которой находится Object.prototype, у которого есть метод toString() – он вызывается, когда объект приводится к строке. И его можно переопределить для отладки:
var s = new Person("Иван", "Петров");
s //результат – "[object Object]"
Person.prototype.toString = function() {
return '<ФИО: ' + this.fullName() + '>';
}
s //результат – "<ФИО: Иван Петров>"
Теперь вернемся к рассмотрению первого параметр метода avg.apply().Первый параметр apply() это объект, на который будет ссылаться ключевое слово "this", если оно используется в теле вызываемой функции. Например, можно сделать тривиальную реализацию "new":
function trivialNew(constructor) {
var o = {}; // создаем объект
constructor.apply(o, arguments);
return o;
}
Это конечно не совсем "new", так как не создается прототипная цепочка ( prototype chain ).
Для apply() есть похожая функция call, которая также позволяет установить "this", но вместо массива параметров принимает параметры через запятую (как при обычном вызове):
function lastNameCaps() {
return this.last.toUpperCase();
}
var s = new Person("Иван", "Петров");
lastNameCaps.call(s);
// Тоже самое, что и:
s.lastNameCaps = lastNameCaps;
s.lastNameCaps();
В
function betterExampleNeeded() {
var a = 1;
function oneMoreThanA() {
return a + 1;
}
return oneMoreThanA();
}
Это позволяет не засорять глобальный контекст ( scope ) именами функций, которые нужны для решения частных проблем в одной части кода. А также разделять переменные между разными вложенными функциями, не пользуясь глобальным пространством имен.
Для добавления <script></script>. Скрипт, выводящий "Hello, World!" внутри браузера:
<script type="text/javascript">
alert('Hello, World!');
</script>
Спецификация HTML описывает набор атрибутов, используемых для задания обработчиков событий. Пример использования:
<a href="delete.php" onclick="return confirm('Вы уверены?');">Удалить</a>
В приведенном примере при нажатии на ссылку функция confirm('Вы уверены?') ; вызывает return false; блокирует переход по ссылке. Разумеется, этот код будет работать, только если в браузере есть и включена поддержка
Использование кода alertLink ):
<a href="delete.aspx" id="alertLink">Удалить</a>
приведенного примера может выступать, например, следующий фрагмент
window.onload = function() {
var linkWithAlert = document.getElementById("alertLink");
linkWithAlert.onclick = function() {
return confirm('Вы уверены?');
};
};
Есть и третья возможность подключения
<script type="text/javascript" src="http://Путь_к_файлу_со_скриптом"></script>
Тег script, широко используемый для подключения к странице
type для указания MIME-типа содержимого;
необязательный атрибут src, принимающий в качестве значения адрес к файлу со скриптом;charset, используемый вместе с src для указания используемой кодировки внешнего файла;defer, используемый для того, чтобы показать, что скрипт не генерирует никакого содержимого (что означает, в частности, то, что в этом скрипте отсутствует вызов document.write() ).При этом атрибут language (language="JavaScript"), несмотря на его активное использование, относится к не рекомендуемым (
(рис 12.1) Пример сеанса eyeOS [8]
Пользовательские скрипты в браузере – это программы, написанные на
Приложения, написанные на
Перевод мобильных устройств Palm на использование Palm webOS в качестве операционной системы с Mojo SDK в качестве средств разработки позволяет использовать
Виджет – вспомогательная мини-программа, графический модуль, которой размещается в рабочем пространстве соответствующей родительской программы, служащая для украшения рабочего пространства, развлечения, решения отдельных рабочих задач или быстрого получения информации из интернета без помощи веб-браузера.
Google Chrome OS в качестве прикладного ПО использует Веб-приложения.
Для обеспечения высокого уровня абстракции и достижения приемлемой степени кросс-браузерности при разработке веб-приложений используются библиотеки
Среди известных
На сегодняшний день поддержку
sandbox ), в которой они могут выполнять только ограниченный круг действий, а не задачи программирования общего назначения (например, создание файлов, работа с сокетами);document ) при отличии в протоколе, хосте и номере порта этих страниц.Помимо этого, разработчики браузеров вносят дополнительные ограничения в ответ на имеющие место злоупотребления. Так появился, в частности, запрет на открытие окна, размер одной стороны которого меньше ста пиксел.
Общая проблема, касающаяся
Уязвимости
Другим типом межсайтовой уязвимости является подделка межсайтовых запросов или CSRF. Она заключается в возможности сайта злоумышленника заставить браузер пользователя осуществить нежелательное действие на целевом сайте (например, банковский перевод денег). Такая возможность имеется, если целевой сайт полагается только на HTTP cookie или запросы авторизации. В этом случае запросы, инициализированные кодом сайта злоумышленника, выполняются так же как запросы пользователя, если он авторизован на целевом сайте. Одним из средств защиты от CSRF является осуществление аутентификации при любом запросе, который приводит к необратимым последствиям.
Подобные ошибки выявлялись у часто используемых браузеров, включая Mozilla Firefox, Internet Explorer, Safari. При выявлении потенциально опасных ошибок в браузере и наличия сведений о реализованных эксплойтов фирма-производитель и эксперты по безопасности рекомендуют отключать
Плагины, такие как плееры, Macromedia Flash и ряд ActiveX компонент, доступных по умолчанию в Internet Explorer, могут также содержать ошибки, эксплуатируемые с помощью
Расширения Mozilla Firefox не изолированы друг от друга: одно расширение может исправлять другое, что может использоваться злоумышленниками.
Браузеры могут запускать
Неправильное наделение привилегиями
Microsoft Windows позволяет файлам с кодом
Основные архитектурные черты
Структурно
В
Boolean );Null ;Undefined ;Error.Для добавления <script></script>. При этом
Область применения
Среди известных
На сегодняшний день поддержку
В целях безопасности
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.