对象的属性名可加上引号,下面三行代码所定义的内容是完全相同的
var hero = { occupation : 1 };var hero = { "occupation" : 1 };var hero = { 'occupation' : 1 };
通常情况下不建议在属性名上加引号,但以下情境就必须加引号:
- 属性名是JS的保留字之一
- 属性名包含了除字母数字下划线$以外的字符
- 属性名以数字开头
总而言之,若属性名不符合JS的变量命名规则就必须加上引号
对象的属性值可以是函数,因为函数本身也是一种数据,在这情况下,称该属性为对象的方法
var person = { name : 'Sam', say : function(){ alert('Hi~'); }};
一些程序设计语言中,通常会有索引型数组(键名为数字)和关联型数组(通常以字符串为键值),也叫哈希表或字典
JS中用数组表示索引型数组,用对象表示关联型数组访问对象的属性可用点号也可用中括号的方式,若访问的属性名不符合变量命名规则或属性名通过变量获取的,就必须使用中括号
对象属性名尽量别加引号,对象属性和方法的访问尽量使用点号JS是动态类型语言,对象在任何时候都可进行增删改属性,但一些内建对象的一些属性不可改变如(Math.PI)
空对象本身会继承一些属性,ES5中才可以创建一个不继承任何属性的对象当处于某个对象的方法内部时,可用this关键字访问该对象的属性或方法
JS程序所在的宿主环境一般都会为其提供一个全局对象,而所谓的全局变量不过是该对象的属性罢了
但宿主环境是Web浏览器时,它提供的全局对象是window,另一种获取全局对象的方法(此方法在浏览器外的大多数其他环境也同样有效)是在函数之外使用this关键字创建对象时,实际同时赋予了该对象一种特殊的属性,即构造器属性,该属性实际上是一个指向用于创建该对象的构造器函数的引用
由于构造器属性所引用的是一个函数,因此我们也可以利用它来创建一个其他新对象function Hero(name){ this.name = name;}var h = new Hero('Sam');> h.constructor //ƒ Hero(name){this.name = name;}var h2 = new h.constructor('May');> h2.name //May
若对象是通过“对象文本标识法”(字面量形式)创建的,那实际上它就是由内建构造器Object()函数所创建
var obj = {};> obj.constructor //function Object(){ [native code] }
通过instanceof操作符,可测试一个对象是否由某个指定的构造器函数创建
function Hero(){}var h = new Hero()var obj = {}> h instanceof Hero //true> h instanceof Object //true> o instanceof Object //true
改变构造器的默认行为
function Fn(){ this.a = 1; return { b:2; }}> var obj = new Fn()> typeof obj.a //undefined> obj.b //2
在这里,构造器返回的不再是包含属性a的this对象,而是另一个包含属性b的对象
但这也只有在函数返回值是一个对象时才会发生,若返回的是非对象类型时,该构造器会照常返回this关于对象在构造器函数内如何创建出来,可设想在函数开头有个叫this的变量,这个变量会在函数结束时被返回,像这样
function C(){ // var this = {}; this.a = 1; //return this;}
对对象进行比较时,当且仅当两个引用指向同一个对象,结果才为true
JS中内建构造器(内建对象)大致可分为三类:
- 数据封装类对象,Object、Array、Boolean、Number和String
- 工具类对象,Math、Date、RegExp等
- 错误类对象
不要去纠结什么是内建对象,什么是内建构造器,实际上它们是一回事,无论函数还是构造器函数,最后都是对象
Object是JS中所有对象的顶级父对象
var o = {}; var o = new Object(); 是等价的o.constructor :返回构造器函数的引用
o.toString : 返回对象的描述字符串 o.valueOf : 返回对象的单值描述信息,通常返回的就是对象本身toString()方法会在需要用字符串来表示对象的时候被JS内部调用,如alert()或用+拼接时,该对象会调用自身的toString()方法
Array()是个用来构建数组的内建构造函数
var a = []; var a = new Array(); 是等价的 既然数组是由构造器创建,这意味着数组实际上也是对象,所以也继承了Object的所有方法和属性可以手动设置数组的length属性,若设置的值大于当前数组长度,剩下的会被undefined自动填充,若小于则多出的部分会被移除
a.push("Hi")就相当于 a[a.length] = 'Hi',而 a.pop()则与 a.length--的结果相同。函数是一种特殊的数据类型,实际上它也是对象,函数对象的内建构造器是Function(),此为创建函数的第三种方式但不推荐
函数的constructor属性也是其构造器函数的引用 length属性记录函数声明时参数列表里的参数个数 toString()方法返回的是该函数的源代码,用此方法查看那些内建函数的源码时,只会得到一个字符串[native code] 所以可用此来区分本地方法和自定义方法JS中每个函数都会有call()和apply()两个方法,可让一个对象“借用”另一对象的方法,这也是种非常简单而实用的代码复用
var obj = { job:'singer', say:function (name) { console.log('my name is ' + name +',I\'m a ' + this.job); }}obj.say('Sam');var obj2 = { job:'teacher'}obj.say.call(obj2,'May');obj.say.apply(obj2,['May']); //apply工作方式和call基本相同,唯一不同的是apply要传递数组
调用say()函数的对象方法call()时传递了两个参数,obj2对象和参数
这样一来,当say()被调用时,其中的this就被自动设置成obj2对象的引用 若没有传对象给call()的首参数或传递null,则调用对象将会被默认为全局对象函数中的arguments是类似数组的对象,和数组的相似之处仅在于也包含了索引和length属性,而sort()、push()等数组方法却没有
但可把arguments转换成数组,这样就可使用各种各样的数组方法了function f(){ var args = [].slice.call(arguments); //也可使用Array.prototype.slice来调用同一个函数 return args.reverse();}> f(1,2,3,4); //[4,3,2,1]
推断对象类型
数组的 typeof 返回值也为"object",那么如何区分对象与数组? 答案是使用 Object 对象的 toString()方法。这个方法会返回所创建对象的内部类名> Object.prototype.toString.call({});"[object Object]"> Object.prototype.toString.call([]);"[object Array]"
在这里,toString()方法必须要来自于 Object 构造器的 prototype 属性,直接调用Array 的 toString()方法是不行的,因为在 Array 对象中。这个方法已经出于其他目的被重写
这种推断方法也适用于DOM元素> Object.prototype.toString.call(document.body); //"[object HTMLBodyElement]"
var b = new Boolean()
所创建的b是一个对象而不是基本数据类型的布尔值 Boolean()构造器创建的对象没有多少实用性,除了来自继承的,自身没有任何属性和方法不使用new操作符而单独作为一般函数使用时,Boolean()可将一些非布尔值转换为布尔值(效果相当于两次取反操作)创建的Number对象有三种方法,toFixed()、toPrecision()和toExponential()
var n = new Number(123.45);n.toFixed(1);
在事先未创建Number对象的情况下也可使用这些方法,因为Number对象会在后台自动被创建和销毁
(1234).toExponential(); //"
Number对象自己的toString()方法可带一个参数表示用多少进制
b.toString(16)基本类型的字符串不是对象,所以不含有任何属性和方法,但当我们将一个基本字符串当作对象使用时,后台会相应的创建String对象,在调用完后又把String对象立即销毁
> 'potato'.length // 6> 'tomato'[0] // "t"
Math.random() 返回 [0,1) 间的某个数,若想获取min和max范围的值,可通过公式
((max - min) * Math.random()) + min
Math.round() 返回最靠近指定值的整数
内建构造器RegExp()来创建正则表达式对象
var reg = new RegExp('J.*t'); //匹配J开头,t结尾,中间包含一个或以上任意字符的字符串var reg = /J.*t/; //字面量形式,正则文本标记法
正则表达式对象拥有的属性:
- global:默认false,即找到第一个匹配时就停止
- ignoreCase:是否区分大小写,默认false,区分
- multiline:是否跨行搜索,默认false,不跨行
- lastIndex:搜索开始的索引位,默认0
- source:用于存储正则表达式匹配模式 前三个属性可用regex修饰符表示,即g、i、m 除了lastIndex,其他属性在对象创建后都不能再被修改
var reg = new RegExp('J.*t','gmi'); //修饰符无序,传递给构造器后相应的属性就被设为truevar reg = /'J.*t'/gi;
RegExp对象有两种可用于查找匹配内容的方法:test()和exec()
test()返回布尔值 exec()返回数组,匹配的字符串组成的数组/j.*t/i.exec('Javascript')[0]; //"Javascript"
String对象的IndexOf()和lastIndexOf()方法只能用于纯字符串式子的搜索,若想获得更强大的文本搜索能力就需要使用正则表达式
但String对象也有此能力 String对象的这些方法都能以正则作为参数 match():返回数组,包含匹配内容的数组 search():返回索引,第一个匹配内容所在的索引 replace():将匹配内容替换成指定字符串 split():返回数组,根据字符串或正则,将字符串切割成数组这四个方法不但能接收正则,也包括字符串,它们会把接收到的字符串参数自动转换成regex对象,就像我们直接传递new RegExp()一样
"test".replace('t', 'r');"test".replace(new RegExp('t'), 'r'); //两者等价
使用字符串的话就不能使用修饰符igm,而且replace()中global修饰符的值将为false,也就是只有第一个匹配的字符串才会被替换,剩下的不会
若正则表达式中分了组(即带括号),则可用$1表示匹配分组的第一组,$2表示第二组,以此类推
var email = 'Jay@qq.com';var name = email.replace(/(.*)@.*/,'$1');> name; //Jay
回调式替换
通过回调,可在替换操作之前实现一些处理逻辑
function replaceCallback(str){ console.log(arguments); //若arguments赋值给一个全局变量,这就能得到replace()传来的参数 return "_" + str.toLowerCase(); //而return的值又会作为替换值}var s = 'JavaScript';s.replace(/(J)(a)/g, replaceCallback);在这里,回调接收到的参数实际有四个 首参数是正则匹配到的内容,尾参数是被搜索的字符串,尾参数之前的一个参数是所匹配内容的索引 剩下的参数则是各个分组 str是形参,replace()函数内部传给replaceCallback函数的参数是实参
Error
程序出现错误时,会抛出一个Error对象,该对象可能由以下几个内建构造器中的一个产生
它们包括EvalError、RangeError、ReferenceError、SyntaxError、TypeError和URIError等,所有这些构造器都继承自Error对象 错误捕获很容易,只需要使用 try 语句后接一个 catch 语句即可try(){ iDontExist(); //iDontExist()是个未定义的函数} catch (e){ //这里写修复错误的代码或将错误进行反馈}
try 语句及其代码块
catch 语句及其参数变量和代码块catch 语句的参数 e 实际上是一个 Error 对象,跟其他对象一样,它也
提供一系列有用的方法与属性。遗憾的是,不同的浏览器对于这些方法与属性都有着各自 不同的实现,但其中有两个属性的实现还是基本相同的,那就是 e.name 和 e.message e.name 是构造当前 Error 对象的构造器名称也可以用 new Error()或者其他 Error 对象构造器来自定义一个 Error 对象,然后告诉 JS 引擎某个特定的条件,并使用 throw 语句来抛出该对象
try { var total = maybeExists(); if (total === 0) { throw new Error('Division by zero!'); } else { alert(50 / total); }} catch (e){ alert(e.name + ': ' + e.message);} finally { alert('Finally!'); //finally是可选的,无论错误是否发生,这里的代码都会执行}
这里抛出的是一般性的错误提示,使用的是 throw new Error('Division by zero!')语句
也可以根据自身的需要来明确错误类型,例如可以利用 throw new RangeError('Division by zero!')语句来抛出该错误 或者不用任何构造器,直接定义一个一般对象抛出:throw { name: "MyError", message: "OMG! Something terrible has happened"}
这样一来,就可以使用自定义的 Error 名,从而解决了浏览器之间由于抛出错误不相同所导致的问题
五种基本数据类型,除了 undefined 和 null 外,其他三个都有相应的构造器 函数
分别是 Number()、String()以及 Boolean(),通过它们我们可以创建出相应的对象,通过将这些基本类型封装成对象,我们就可以在其中集成一些有用的工作方法 Number()、String()以及 Boolean()的调用可分为两种形式:- 使用 new 操作符调用 — 用于新建对象。
- 不使用 new 操作符调用 — 用于将任意值转换成基本数据类型