标签:des style http color java os 使用 io strong
Chapter13 Annexure: JavaScript Language Overview 附录: JavaScript语言概览
Js语言总览; 提供一个Qt支持的所有语言特性的概览; 通过本文了解Js语言的基本特性; 特别是当你开始学习一个相关的技术, 如QML时, 你可以在这获得帮助;
这篇文章是对 JavaScript Language Overview http://qt-project.org/wiki/JavaScript 的轻微改动版本; 内容经过Qt4.8和QtQuick1.1测试; 另外, 本文提供一个QtQuick的应用作为样例; 路径: http://download.qt-project.org/learning/developerguides/qtquickappdevintro/qt_quick_app_dev_intro_src.zip js_basics;
13.1 Introduction 介绍
Js是一个minimalistic(简单/弱)动态类型的Scripting(脚本)语言; 它是真正object-oriented(面向对象的), 虽然它缺乏对class的支持; 虽然经常作为客户端的web开发工具, Js本身是一种语言; 原来是被Netscape开发, 现在Js标准化为 ECMAScript-262 (3rd and 5th edition) http://www.ecma-international.org/publications/standards/Ecma-262.htm, 这个语言被广泛使用而且以各种名称circulate流通; JScript是微软的derivative衍生语言; JavaScript是由Netscape挑选的原始名称, 在Netscape 2的时候开始使用; Adobe的ActionScript在v3发布之前也是基于ECMAScript-262的;
Qt从Qt4.3开始支持JavaScript引擎, 和ECMAScript-262兼容; 这个引擎称为 QtScript, 原本是一个独立的实现; 从Qt4.5开始, QtScript已经基于属于WebKit https://www.webkit.org/ 的JavaScriptCore了; QtQuick中intense大量地使用了QtScript;
13.2 The Type System 类型系统
Js支持以下的基础类型: boolean; number; string; object; function;
新的变量可以使用 var statement声明语句引入当前的scope;
| 
 
1 
2 
3 
 | 
var flag
 = false //
 a booleanvar x
 = 1., y = 2 //
 numbers can be integers and realsvar s1
 = ’abc’; //
 a string | 
要获取变量的类型, 可以使用 typeof 关键字; typeof返回一个string, 值为类型的名字;
| 
 
1 
2 
3 
4 
 | 
var x
 = 0; typeof x //
 ’number’typeof {
 x: 1 } //
 ’object’typeof typeof {
 x : 1 } //
 ’string’typeof JSON.parse(’{"a":
 7}’) //
 ’object’ | 
Js中所有的东西都表现得像一个对象;
| 
 
1 
2 
 | 
1.3333333.toFixed(2) //
 ’1.33’7..toString() //
 ’7’ | 
Note 在Js中expression表达式7.toString()不能被正确interpreted解析; 7. 被解析成一个数字, 然后产生语法错误;
primitive原始类型boolean, number, string在需要的时候会被隐式地转换成对象; 为了这个目的, 全局global对象提供了特殊的构造方法, 可以手动调用:
| 
 
1 
2 
3 
 | 
typeof 1. //
 ’number’typeof new Number(1.) //
 ’object’typeof new String(’Hi!’) //
 ’object’ | 
function方法是特殊的对象; 它们和对象的区别只是他们可以被调用, 像构造那样被调用; 方法可以动态地加上属性:
| 
 
1 
2 
3 
4 
 | 
function f(x)
 { return f.A
 x * x }f.A
 = 2.7function Buffer()
 {}Buffer.MAX_LINE_LENGTH
 = 4096 | 
通常这些属性作为全局常量使用, 因此以大写表示;
对象自己可以被表示为使用一个数组或对象literal字面量; 数组没有separate分开的类型, 但是specialized专门的对象会使用数组索引作为属性:
| 
 
1 
2 
3 
4 
5 
6 
 | 
var o
 = { name: ’Werner’, age: 84 } //
 allocate simple objectprint(o.name,
 o[age])//
 both notations are valid, but [] notation allows generated stringsvar a
 = [’a’, ’b’, 7, 11.]//
 an array, equivalent to {’0’: ’a’, ’1’: ’b’, ’2’: 7, ’3’: 11.}typeof o,
 a //
 ’object’, ’object’ | 
13.3 Expressions 表达式
表达式的语法更多地依照C语法(就像C++或Java); 主要的区别是, 语句和表达式之间没有sharp distinction明显差别; 基本上所有东西都有值(evaluate to something); 方法声明和compounds复合词可以在运行时(on-the-fly)包含进来:
| 
 
1 
2 
3 
4 
 | 
function f()
 {} //
 evaluates ’undefined’function f()
 {} + 1 //
 evaluates to 1, because ’undefined’ is casted to 0(function()
 {}) //
 evaluates to a function object(function()
 { return 0;
 })() //
 evaluates to 0 | 
表达式可以被分号或换行符分隔开;
13.4 Branching 分支语句
条件分支依照C语法:
| 
 
1 
2 
3 
4 
 | 
if (<expression>)    <statement1>else //
 optional    <statement2> //
 optional | 
switch语句和C语言的fall through语义完全一样:
| 
 
1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
 | 
switch(<expression>)
 {    case <expression>:        <statement-list-1>        break;    case <expression>:        <statement-list-2>        break;    ...    default:        <statement-list-n>} | 
13.5 Repetitions and Iterators 重复和迭代
重复的动作可以使用 do, while, for循环来解释:
| 
 
1 
2 
3 
4 
5 
6 
7 
 | 
...do <statement> while (<expression>)...while (<expression>)
 <statement>...for (<init-expression>;<test-expression>;<step-expression>)
 <statement>... | 
对于迭代的对象, Js提供了一个特殊的 for-in 语句:
| 
 
1 
 | 
for (<expression>; in <object>;)
 <statement> | 
给出的表达式需要有一个合适的左值来分配值; 最简单的情况下, 就是一个变量声明;
| 
 
1 
2 
3 
4 
5 
6 
7 
 | 
var a
 = [1,2,3,4]for (var i in a)    print(i,
 a[i] a[i])//
 ’0’, 1//
 ’1’, 4//
 ’2’, 9//
 ’3’, 16 | 
这里的变量 i 被consecutively连续地赋值给数组的所有的key; 下个example中, 左值表达式是动态生成的:
| 
 
1 
2 
3 
 | 
var o
 = {a0: 11, a1: 7, a2: 5}var k
 = []for(k[k.length] in o); | 
o 的keys被拷贝到了 k; 循环语句自身的内容是空的; 每个o的成员, 名字都被分配给k的成员;
13.6 Labeled Loops, Break and Continue 循环标签
Js中, 循环语句可以打标签; break和continue语句可以break或continue当前的循环; 使用标签名字可以做到从一个内部的循环break一个外部的循环:
| 
 
1 
2 
3 
4 
5 
6 
 | 
label_x:for (var x
 = 0; x < 11; ++x) {    for (var y
 = 0; y < 11; ++y) {        if ((x
 + y) % 7 == 0) break label_x;    }} | 
13.7 Objects and Functions 对象和方法
对象创建可以用literal字面意义上的对象或new操作符;
下面的example中, 一个point坐标可以用对象文字来表示:
| 
 
1 
 | 
var p
 = { x: 0.1, y: 0.2 } | 
对象是属性的整个动态集合; 新的属性会在第一次分配的时候被引入; 它们可以使用delete操作符删除; 要查询一个对象是否包含某个值, 使用 in 操作符;
| 
 
1 
2 
3 
4 
5 
 | 
’z’ in p //
 falsep.z
 = 0.3 //
 introduce new property ’z’’z’ in p //
 truedelete p.z //
 remove ’z’ from pp.z //
 undefined | 
属性值可以是任何类型--包括function类型; Js中的method方法就是function属性; 当一个function被method notation(方法符号)调用, 它就获得一个对象的引用来作为隐式的参数调用--this;
| 
 
1 
2 
3 
4 
5 
 | 
p.move
 = function(x,
 y) {    this.x
 = x    this.y
 = y}p.move(1,
 1) //
 invoke a method | 
使用 call 方法, Js允许任何function被当作任何对象的方法调用; 然而, 只有少数的情况下你会想要使用 call 方法;
| 
 
1 
2 
 | 
p2
 = { x: 0, y: 0 }p.move.call(p2,
 1, 1) | 
13.8 Prototype-based Inheritance 基于原型的继承结构
创建对象的第二种方式是使用new关键字+构造function;
| 
 
1 
2 
3 
 | 
var p
 = new Objectp.x
 = 0.1p.y
 = 0.2 | 
new操作符会allocate分配一个新的对象, 调用已有的constructor构造函数来初始化对象; 这个例子中, ctor是Object, 但是它可以是任何其他的function; ctor function由新创建的对象作为隐式的this参数来传递; Js中没有class, 但是ctor function的继承结构操作起来就像对象工厂; 一般ctor function以大写字母开头, 这样可以和平常的fucntion区分开; 下面的example展示了如何使用ctor function来创建point坐标:
| 
 
1 
2 
3 
4 
5 
 | 
function Point(x,
 y) {    this.x
 = x    this.y
 = y}var p
 = new Point(1,
 2) | 
Js中每个function可以当作一个ctor和new操作符来组合使用; 为了支持继承机制, 每个function有一个默认属性叫做prototype ;
| 
 
1 
2 
3 
4 
5 
6 
7 
8 
9 
 | 
function Point(x,
 y) {    this.x
 = x    this.y
 = y}Point.prototype
 = new Object //
 can be omitted herePoint.prototype.translate
 = function(dx,
 dy) {    this.x
 += dx    this.y
 += dy} | 
[prototype是对象原型?]
首先声明一个新的function称为Point, 可以初始化一个point; 之后创建自己的prototype对象, 不会在这里是redundant多余的; function的prototype已经默认是一个空的Object; 分配给prototype的属性将在所有的point中被共享; 这个例子中, 我们定义了translate function可以将point平移一段距离;
现在可以使用Point ctor来实例化point;
| 
 
1 
2 
3 
4 
5 
 | 
var p0
 = new Point(1,
 1)var p1
 = new Point(0,
 1)p1.translate(1,
 -1)p0
 === p1 //
 falsep0.translate
 === p1.translate //
 true | 
p0和p1对象携带了自己的 x和 y属性, 但是它们是共享 translate方法; 无论何时一个对象的属性值是通过名字来索取的, underlying潜在的Js引擎首先寻找object自己, 然后如果它不包含那个名字, 它就fall back回退到object的prototype; 每个object携带一份ctor的prototype的拷贝来达到这个目的;
如果一个object确实含有每个属性, 或者它继承了某个属性, 它就可以使用 Object.hasOwnProperty() 方法来询问:
| 
 
1 
2 
 | 
p0.hasOwnProperty("x") //
 truep0.hasOwnProperty("translate") //
 false | 
目前我们只定义了一个单独的ctor, 还没有涉及object的继承机制; 我们现在会引入两个额外的ctor来展示如何chain连接prototype以及thereby从而在object之间构建更多复杂的关系:
| 
 
1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
 | 
function Point(x,
 y) {    this.x
 = x    this.y
 = y}Point.prototype
 = {    move: function(x,
 y) {        this.x
 = x        this.y
 = y    },    translate: function(dx,
 dy) {        this.x
 += dx        this.y
 += dy    },    area: function()
 { return 0;
 }}function Ellipsis(x,
 y, a, b) {    Point.call(this,
 x, y)    this.a
 = a    this.b
 = b}Ellipsis.prototype
 = new PointEllipsis.prototype.area
 = function()
 { return Math.PI this.a
 * this.b;
 }function Circle(x,
 y, r) {    Ellipsis.call(this,
 x, y, r, r)}Circle.prototype
 = new Ellipsis | 
这里有3个ctor分别创建point, ellipsis, circle; 对于每个ctor, 我们设置了一个prototype; 当一个新的object使用new操作符来创建的时候, object被给予一个ctor的prototype的内部拷贝; prototype的内部引用会在resolving解析属性名字的时候使用, 名字并不是直接存储在object中的; 所以prototype的属性是在以某个ctor创建的object之间被重用的; e.g. 我们创建一个circle然后调用它的move方法:
| 
 
1 
2 
 | 
var circle
 = new Circle(0,
 0, 1)circle.move(1,
 1) | 
Js引擎首先查找circle对象, 查看它是否有 move属性; 由于它找不到, 它会去circle的prototype寻求; 在构造过程中, circle的object的内部prototype引用被设置到了 Circle.prototype; 它是使用Ellipsis的ctor创建的, 但是也不包含move属性; 因此, name resolution名字解析随着prototype的prototype继续, 找到创建它的Point的ctor; 这次name resolution成功找到Point的ctor包含了move属性;
 内部的prototype引用通常指向一个object的prototype chain;
要查询prototype chain的信息, Js提供了 instanceof 操作符:
| 
 
1 
2 
3 
4 
5 
 | 
circle instanceof Circle //
 truecircle instanceof Ellipsis //
 truecircle instanceof Point //
 truecircle instanceof Object //
 truecircle instanceof Array //
 false, is not an Array | 
因为属性是它们第一次被分配的时候引入的, prototype chain中的属性在新分配的时候被覆盖; Object.hasOwnProperty 方法和 in 操作符给出了研究是否一个属性被存储起来的方式;
| 
 
1 
2 
3 
 | 
circle.hasOwnProperty("x") //
 true, assigned by the Point constructorcircle.hasOwnProperty("area") //
 false"area" in circle //
 true | 
可以看到, in 操作符使用prototype chain解析名字, Object.hasOwnProperty则只查询当前对象;
在多数Js引擎里, 内部prototype引用称为 __proto__ 而且可以从外部访问; 下一个example中, 我们会使用 __proto__ 引用来探索prototype chain; 不应该在其他context(上下文)中使用这个属性因为它是non-standard非标准的; 首先我们定义一个function, 通过iterate迭代它的成员来inspect查看一个对象;
| 
 
1 
 | 
function inspect(o)
 { for (var n in o) if (o.hasOwnProperty(n))
 print(n, "=",
 o[n]); } | 
inspect function 会将所有存储在object中的成员打印出来, 我们将function应用在circle object和它的prototype上, 获得下面的输出:
| 
 
1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
 | 
js>
 inspect(circle)x
 = 1y
 = 1a
 = 1b
 = 1js>
 inspect(circle.__proto__)x
 = undefinedy
 = undefineda
 = undefinedb
 = undefinedjs>
 inspect(circle.__proto__.__proto__)x
 = undefinedy
 = undefinedarea
 = function ()
 { return Math.PI this.a
 * this.b;
 }js>
 inspect(circle.__proto__.__proto__.__proto__)move
 = function (x,
 y) {    this.x
 = x    this.y
 = y;}translate
 = function (dx,
 dy) {    this.x
 += dx    this.y
 += dy;}area
 = function ()
 { return 0;
 }js>
 inspect(circle.__proto__.__proto__.__proto__.__proto__)js> | 
可以看到, move方法是存储在 circle.__proto__.__proto__.__proto__.__proto__ 中的; 有许多重复的未定义成员, 但prototype object仍然可以在instance之中共享; 
13.9 Scopes, Closures and Encapsulation 范围, 闭包和封装
在Js中, 开始执行时的范围是global scope(全局); 预定义的global function比如 Math 或 String 是global object的属性; global object就像是scope chain的root, 而且是第一个被创建的object; 另外对于global object的标准属性( ECMAScript Reference http://qt-project.org/doc/qt-4.8/ecmascript.html), QtQuick提供了一个 Qt global object http://qt-project.org/doc/qt-4.8/qdeclarativeglobalobject.html 以及一些附加的属性;
通常, global object可以从global scope使用 this 关键字显式地引用; 但 this的值在目前的QtQuick的大多数context上下文中是未定义的; refer to "QML JavaScript Restrictions"--Integrating JavaScript http://qt-project.org/doc/qt-4.8/qdeclarativejavascript.html
更多的scope是根据是否function被调用而创建的; scope像其他的object会在不再需要的时候被destroy销毁; 当一个function被定义, enclosing scope保持和function的定义一样, 作为invocation scope的parent scope使用; 新的scope是根据function invocation(函数调用者)来创建, 通常refer to as称为 activation object; function中的scope定义通常被称为 lexical scope;
下面的example展示如何使用 lexical scope 来隐藏私有成员:
| 
 
1 
2 
3 
4 
5 
6 
 | 
function Point(x,
 y) {    this.getX
 = function()
 { return x;
 }    this.setX
 = function(x2)
 { x = x2; }    this.getY
 = function()
 { return y;
 }    this.setY
 = function(y2)
 { y = y2; }} | 
当Point的ctor被调用, 会创建get和set方法; 新生成的scope, 基于Point ctor的调用者, 携带着x和y成员; getter和setter引用这个scope, 因而它也保留了和新创建的object的生存期; 有趣的是, 除了通过set和get方法, 没有其他的方式可以获取x和y; 在这种方式下Js支持了 data encapsulation--数据封装;
closure闭包的概念--一个funcion引用了封闭的scope, 保留了function的生存期; 低层次的编程语言如C语言不支持closure, 因为局部的scope是通过stack frame(堆栈结构)创建的, 因此在function return的时候需要被destroy;
13.10 Namespaces 名字空间
function在Js中扮演了pivotal中枢角色; 它们可以作为简单的function, method, ctor, 原来封装私有属性; 另外function也可以作为匿名namespcae;
| 
 
1 
2 
3 
4 
5 
6 
7 
 | 
(function()
 {    //
 my code    var smth
 = new Smth //
 safe    other
 = [1,2,3] //
 bad, goes into global scope    Array
 = function()
 {} //
 forbidden})
 ()var smthElse
 = {} //
 bad, goes into global scope | 
一个匿名function可以在on-the-fly运行时被定义; 特别是global初始化代码, 通常以这种方式wrapped包装来防止污染global scope; 因为global object可以在Js中作为另一个object来修改, 以这种方式wrapping code包装代码可以减少不经意地覆盖global变量的可能性; 为了确保做到这点, 所有的变量需要duly充分地使用 var 语句来引入;
命名的名字空间也可以使用function创建; 比如如果我们想要写一个utility库来做绘画, 可以这么写:
| 
 
1 
2 
3 
4 
5 
6 
7 
8 
9 
 | 
function PaintUtil()
 {    PaintUtil.Point
 = function(x,
 y) {        this.move
 = function(x2,
 y2) { x = x2; y = y2 }        this.getX
 = function()
 { return x;
 }        this.getY
 = function()
 { return y;
 }    }//
 Ellipsis, Circle, other painting utility methods}PaintUtil() | 
一旦这个小小的库模块被执行, 它会提供单个的 PaintUtil object, 使得utility function可以访问; Point可以使用PaintUtil提供的ctor来实例化:
| 
 
1 
 | 
var p
 = new PaintUtil.Point(0.1,
 0.2) | 
可重用的Js模块应该只会以一个可分辨的名字来引入单个global object;
13.11 Common Methods 普通方法
Js允许一个object的默认行为被 valueoOf() 和 toString() 方法改变; valueOf会返回一个基本类型的值; 它用来比较object(在排序的时候), 以及评估comprising组成object和基本类型的表达式; toString()可以把object转化为string; 在Js中, object的比较是关于equality, 而不是大于或小于;
equality的comparison比较总是比较object的引用; 而对大小的比较则是先把object转化为基本类型的value再做比较; 首先调用 valueOf(), 然后如果它没有返回一个基本类型, 则调用 toString()代替;
对于Point类, 我们可以定义以下的方法:
| 
 
1 
2 
3 
4 
5 
6 
 | 
Point.prototype.valueOf
 = function ()
 {    return Math.sqrt(this.getX()
 * this.getX()
 + this.getY()
 * this.getY());}Point.prototype.toString
 = function ()
 {    return this.getX().toString()
 + "," + this.getY().toString();} | 
13.12 Exceptions
Js提供了一个exception handling异常处理机制, 和其他高层次语言一样; exception使用 throw 语句抛出; 任何值都可以在一个exception中使用:
| 
 
1 
 | 
throw <expression>; | 
抛出一个exception的时候, Js会将当前的scope进行unwind(退栈/栈展开), 直到它到达一个try-catch的scope:
| 
 
1 
2 
3 
4 
5 
6 
7 
8 
9 
 | 
try {    <statement-list>}catch (<name for exception
 object>) {    //
 handle exception}finally
 {    //
 always go through here} | 
exception object的名字仅仅是局部地定义在catch scope中的; exception可以被 re-thrown 重新抛出;
13.13 Resources
web链接:
“The JavaScript Reference”Mozilla Developer Network https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference
“JavaScript. The core.” by Dmitry A. Soshnikov”http://dmitrysoshnikov.com/ecmascript/javascript-the-core/
“Changes to JavaScript: EcmaScript 5 by Mark Miller”video from Google Tech Talk, May 18, 2009
“Standard ECMA-262”official standard PDF http://www.ecma-international.org/publications/standards/Ecma-262.htm
推荐书籍:
“JavaScript: The Good Parts” by Douglas Crockford10 * “Part I - Core JavaScript” in“JavaScript: The Definitive Guide” by David Flanagan11
---13---
---YCR---
refer to http://qt-project.org/wiki/developer-guides
Qt Quick应用开发介绍 13 (JavaScript)
标签:des style http color java os 使用 io strong
原文地址:http://blog.csdn.net/roymuste/article/details/38637321