什么是JavaScript?
一种最流行的web脚本语言,运行在浏览器中的解释性的编程语言。在Web世界里,JavaScript能跨平台、跨浏览器驱动网页,与用户交互。
JavaScript实现
JavaScript主要由三部分组成:
- 核心ECMAScript,描述了该语言的语法和基本对象
- 文档对象模型DOM,描述了处理网页内容的方法和接口
- 浏览器对象模型BOM,描述了与浏览器进行交互的方法与接口
JavaScript语言核心
JavaScript的语言核心主要是实现ECMAScript标准。ECMAScript定义了脚本语言的所有属性、方法和对象。主要描述内容为:语法、类型、语句、关键字、保留字、运算符、对象。
1.词法结构--基础性规则
JS程序使用Unicode字符集编写的;区分大小写(HTML的标签和属性名不区分大小写);支持两种格式的注释(“//”,“/* */”);标识符必须以字母、下划线(_)或美元符号($)开始;使用分号(;)将语句分隔开。
注意:JS自动补充语句后的分号。如果一条语句以“(”、“[”等开头,那么它极有可能和前一句合在一起解析。return、break、continue后换行,JS会在换行处加分号。
var y = x + f
(a+b).toString()
// 解析成
var y = x+f(a+b).toString();
//--------------------------------------
return
true
//解析成
return; true;
2.类型、值、变量
JS数据类型:原始类型(primitive type)和对象类型(object type)。原始类型:数字、字符串、布尔值。JS还有两种特殊原始值:null和undefined。JS可以自由的进行数据类型转换,使用var关键字申明变量。
字符串(string):是一组由16位值组成的不可变的有序数列。字符串直接量由""或''括起来。字符串可以拆分成多行,每行结尾须以\结束。
布尔值(boolean):true和false,比较结果常为布尔值。比较中,undefined、null、0、-0、NaN、""都会转换为false,其他值,包括对象都会转换成true.
null和undefined: 表示值的空缺。
全局对象(global object):当JS解释器启动时,它将创建一个新的全局对象,并给它一组定义的初始属性。全局对象定义了JS中所有的预定义全局值。同样如果代码中声明了全局变量,则这个变量就是全局变量的一个属性。
JS中原始值是不可更改的,包括字符串。但对象的属性值是可以修改的,对象是引用类型,对象的比较是比较引用。
变量作用域(scope):let 申明的变量作用域为块级作用域。而var申明的变量则只能是全局或整个函数块中。
3.表达式与运算符
属性访问表达式:expression.identifier expression[expression] 第一种方法只适用于要访问的属性名是合法的标识符,并且需要知道要访问的属性的名字。如果属性名有空格或标点符号,或是数字,则需要使用方括号的写法。
调用表达式:调用函数或方法的语法。f(arg)
对象创建表达式:创建对象并调用一个函数(构造函数)初始化新对象的属性。new Object()
var o ={x:1,y:{z:3}};
var a = [o,4,[5,6]];
o.x // 1
o.y.z // 3
o["x"] // 1
a[1] // 4
a[2]["1"] // 6
a[0].x // 1
运算符:注意“==”——相等(类型不同,也可能相等)和“===” ——恒等。注意逻辑与(&&)和逻辑或(||)的操作数不一定是布尔值,可以对真值和假值进行操作。
4.语句
JS程序就是一系列可执行语句的集合。默认情况下,JS解释器依照语句的编写顺序依次执行。此外还有“使某件事发生”的方法改变语句执行顺序。语句主要有表达式语句、空语句、声明语句(var、let、function)、条件语句(if、switch)、循环语句(while、for、do/while、for/in)、跳转语句(break、continue、标签语句、return)。
5.对象
JS对象分为内置对象、宿主对象(如web浏览器)、自定义对象。属性有自有属性和继承属性。
对象创建:对象直接量;通过new关键字创建;Object.create()
原型:每一个JS对象都从原型继承属性(与原型对象关联)。对象直接量创建的对象可以通过Object.prototype获得对原型的引用,通过new和构造函数调用创建的对象的原型是构造函数的prototype属性的值,Object.create()创建对象的第一个参数为原型。Object.prototype对象没有原型,而Date.protoype对象的原型为Object.prototype。于是有原型链。
var point ={
x:0,
y:0,
author:{
firstname:"David",
surname: "Flanagan"
}
} //通过Object.prototype获得原型对象的引用
var d = new Date(); 原型为Date.prototype
var a = new Array(); //原型为Array.prototype
var o1 = Object.create({x:1,y:2}); //参数为这个对象的原型,继承了属性x和y
var o2 = Object.create(Object.prototype); //o2和{}和new Object()一样
JS对象是关联数组对象。Object["property"],这种访问属性的方式灵活度很高。
属性:包含自有属性(own property)和继承属性。属性赋值时,注意设置属性和继承无关。属性赋值要么失败(只读属性,继承属性只读;对象不可扩展且没有该属性),要么创建一个属性,要么在原始对象中设置属性。删除属性使用delete运算符(只能删除自有属性)。检测属性时,通过in运算符、hasOwnProperty()(判断是否为对象的自有属性)、propertyIsEnumerable()检测自有属性且判断是否是可枚举的类型。枚举属性使用for/in、Object.keys()、Object.getOwnPropertyNames().
存取器属性:由getter和setter定义的属性。如果一个存取器属性同时具有getter和setter方法,则这是一个读写属性。
// 通过原型继承创建一个新的对象
function inherit(p){
if(p == null) throw TypeError(); //p得是个对象
if(Object.create) return Object.create(p); //使用Object.create()创建继承对象
var t = typeof p;
if (t !== "Object" && t !== "function") throw TypeError();
function f(){}; //使用构造函数的方法创建继承对象
f.prototype = p;
return new f();
}
var unitcircle = {r:1};
var c = inherit(unitcircle);
c.x =1 ; c.y = 1;
c.r = 2; // c覆盖继承来的属性
unitcircle.r; // =》1 ,原型对象没有改变
delete book.author; // book不再有属性author
delete book["main title"] // book不再有属性“main title”
var o ={x:1} ;
"x" in o; // true
"y" in o; // false
"toString" in o; //true 继承属性
o.hasOwnProperty("toString") // false
Object.prototype.propertyIsEnumerable("toString"); //false : 不可枚举
var p = {
// x,y为普通属性
x: 1.0,
y: 1.0,
//r为可读取的存取器属性
get r(){ return Math.sqrt(this.x*this.x+this.y*this.y);},
set r(newValue){
var oldValue = Math.sqrt(this.x*this.x+this.y*this.y);
var ratio = newValue/oldValue;
this.x *= ratio;
this.y *=ratio;
},
//theta只读存取其属性
get theta(){ return Math.atan2(this.y,this.x);}
};
var q = inherit(p);
q.x =1; q.y = 1;
console.log(q.r) //可以使用继承的存取器属性
console.log(q.theta)
属性的特性:包含可写(writable)、可枚举(enumerable)、可配置的特性(configurable)(ECMAScript5中添加了设置的API),值(value)也可做为特性,查询属性特性Object.getOwnPropertyDescriptor(),设置属性特性Object.defineProperty()或Object.defineProperties()。
Object.getOwnPropertyDescriptor({x:1},"x"); //返回{value:1,writable:true,enumerable:true,configurable:true}
var o ={};
Object.defineProperty(o,"x",{value:1,writable:true,enumerable:false,configurable:true});
o.x //=>1
Object.kes(o) //=>[]属性存在,不可枚举
Object.defineProperty(o,"x",{get:function(){return 0;}}); //将x从数据属性改为存取器属性
o.x //=>0
//可写性控制着对值特性的修改,可配置性控制着其他特性(包括属性是否可删除)的修改。
对象的三个属性:每个对象都有与之相关的原型(prototype)、类(class)、可扩展性(extensible attribute)
原型属性可以通过Object.getPrototypeOf()查询。类属性是一个字符串,用以表示对象的类型信息,无法设置。可扩展性用以表示是否可以对对象添加新属性,所有内置对象和自定义对象都是显式可扩展的,可以通过Object.esExtensiblee()判断,通过Object.preventExtensions(obj)可以将对象转为不可扩展,之后不可转回可扩展。
序列化对象:将对象的状态转换为字符串,或字符串转化为对象。ES5中由JSON.Stringify()和JSON.parse()实现序列化和反序列化。
o = {x:1,y:{z:[false,null,""]}};
s = JSON.stringify(o); // '{"x":1,"y":{"z":[false,null,""]}}'
p = JSON.parse(s) //p是o的深拷贝