/*
第三章
对象
javacript 的简单数据类型包括数字、字符串、布尔值、null、undefined 值。
其他所有的值都是对象。
数字】字符串、和布尔值 “貌似” 是对象,因为它们拥有方法,
但它们是不可变的。
javascript 中的对象是可变的键控集合,在 javascript 中,数组是对象,函数是对象,正则表达式是对象,当然,对象自然也是对象。
对象是属性的容器,其中每个属性都拥有名字和值。属性的名字可以是包括空字符串在内的任意字符串。属性值可以是除undefined 值之外的任何值
javascript 里的对象是无类型的。它对新属性的名字和属性的值没有限制。对象适合用于汇集和管理数据。
对象可以包含其他对象,所以它们可以轻易地表示成树状或图形结构
javascript 包含一种原型链的特性,允许对象继承另一个对象的属性。正确地使用它能减少对象初始化时消耗的时间和内存
*/
/*
对象字面量
对象字面量提供了一种非常方便地创建新对象值的表示法。一个对象字面量就是包围在一对花括号中的零或多个 “名/键” 对。
对象字面量可以出现在任何允许表达式出现的地方。
属性名可以是包括空字符串在内的任何字符串。在对象字面量中,如果属性名是一个合法的 jascript 标识符且不是保留字,
则并不强制要求用引号包括属性名。
*/
/*
检索
要检索对象里包含的值,可以采用在 [] 后缀中括住一个字符串表达式的方式。
如果字符串表达式是一个字符串字面量,而且它是一个合法的 javascript 标识符且不是保留字,那么也可以用 . 表示法代替。
优先考虑使用 . 表示法,因为它更紧凑且可读性更好。
如果尝试检索一个并不存在的成员属性的话,将返回 undefined
|| 运算符可以用来填充默认值
尝试从 undefined 的成员属性中取值将会导致 TypeError 异常,这时可以通过 && 运算符来避免错误
*/
/*
更新
对象里的值可以通过赋值语句来更新,如果属性名已经存在于对象中,那么这个属性的值就会被替换
如果对象之前没有拥有那个属性名,那么该属性就被扩充到对象中,
*/
/*
引用
对象通过引用来传递。它们永远不会被复制
*/
var x = stooge
x.nicename = 'Curly'
var nick = stooge.nicename
console.log(nick)
/*
原型
每个对象都连接到一个原型对象,并且它可以从中继承属性。所有通过对象字面量创建的对象都连接到 Object.prototype,它是 javascript 中的标配对象
当你创建一个新对象时,你可以选择某个对象作为它的原型。javascript 提供的实现机制杂乱而复杂,但其实可以被明显地简化。
我们将给 Object 增加一个 create 方法。这个方法创建一个使用原对象作为其原型地新对象。
*/
// ======================================================================================================================================
/*
第五章
继承:
在大多数编程语言中,继承都是一个重要的主题
在那些基于类的语言(比如 java),继承(inheritance 或 entends)提供了两个有用的服务。
首先,它是代码重用的一种形式。
如果一个新的类与一个已存在的类大部分相似,那么你只需具体说明其不同点即可。代码重用的模式极为重要,因为它们可以显著地减少软件开发的成本。
类继承的另一个好处就是引入了一套类型系统的规范。
由于程序员无需编写显示类型转换的代码,它们的工作量将大大减轻,这是一件很好的事情,因为类型转换会丧失类型系统在安全上的优势。
js 是一门弱类型语言,从不需要类型转换。对象继承关系变得无关紧要。
对于一个对象来说重要的是它能做什么,而不是它从哪里来。
js 提供了一套更为丰富的代码重用模式。它可以模拟那些基于类的模式,同时它也可以支持其他更具表现力的模式。
在 js 中可能的继承模式有很多。我们将研究几种最为直接的模式。当然还有很多更为复杂的构造模式,但保持简单通常是最好的。
在基于类的语言中,对象是类的实例,并且类可以从另一个类继承。js 是一门基于原型的语言,这意味着对象直接从其他对象继承。
*/
/*
伪类:
js 的原型存在着诸多矛盾。
它的某些复杂的语法看起来就像那些基于类的语言,这些语法问题掩盖了它的原型机制。它不直接让对象继承,反而插入了一个多余的间接层:通过构造器函数产生对象。
当一个函数对象被创建时,Function 构造器产生的函数对象会运行类似这样的一些代码:
this.prototype = {constructor:this}
新函数对象被赋予一个 prototype 属性,它的值是一个包含 constructor 属性且属性值为该新函数的对象。
这个 prototype 对象是存放继承特征的地方。
因为 js 语言没有提供一种方法去 确定哪个函数是打算用来做构造器的,所以每个函数都会得到一个 prototype 对象。constructor 属性没什么用,重要的是 prototype 对象。
*/
/*
原型:
在一个纯碎的原型模式中,我们会摒弃类,转而专注于对象。基于原型的继承相比基于类的继承在概念上更为简单:
一个新对象可以继承一个旧对象的属性。
也许你对此感到陌生,但它真的很容易理解。你可以通过构造一个有用的对象开始,接着可以构造更多和那个对象类似的对象。
这就可以完全避免把一个应用拆解成一系列嵌套抽象类的分类过程。
*/
/*
函数化:
迄今为止,我们所看到的继承模式的一个弱点就是没法保护隐私。
对象的所有属性都是可见的。我们无法得到私有变量和私有函数。有时候这样没关系,但有时候却是大麻烦。
遇到这些麻烦的时候,一些无知的程序员接受了一种伪装私有的模式。
如果想构造一个私有属性,他们就给它起一个怪模怪样的名字,并且希望有一个更好的选择,那就是应用模块模式。
我们从构造一个生成对象的函数开始。
我们以小写字母来命名它,因为它并不需要使用 new 前缀。该函数包括 4 个步骤
1. 创建一个新对象。有很多的方式去构造一个对象。
它可以构造一个对象字面量,或者它可以和 new 前缀连用去调用一个构造器函数,或者它可以使用 Object.create 方法去构造一个已经存在的对象的新实例,
或者它可以调用任意一个会返回一个对象的函数。
2. 有选择地定义私有实例变量和方法。这些就是函数中通过 var 语句定义地普通变量。
3. 给这个新对象扩充方法。这些方法拥有特权去访问呢参数,以及在第 2 步中通过 var 语句定义的变量。
4. 返回那个新对象。
*/
// =============================================================================================================================
/*
第六章
数组
长度:
每个数组都有一个 length 属性。和大多数其他语言不同,js数组的 length 是没有上届的。
如果你用大于或等于当前 length 的数字作为下标来存储一个元素,那么 length 值会被增大以容纳新元素,不会发生数组越界错误。
*/
// length 属性的值是这个数组的最大整数属性名加上 1 。它不一定等于数组里的属性的个数
var myArray = []
console.log(myArray.length)
myArray[100001] = true
console.log(myArray) // Array(100002)
console.log(myArray.length) // 100002 myArray只包含一个属性
// 你可以直接设置 length 的值。设置更大的 length 不会给数组分配更多的空间。而把 length 设小将导致所有下标大于等于新 length 的属性被删除。
var array1 = []
array1.length = 3
console.log(array1) // (3) [empty × 3]
// 通过把下标指定为一个数组的当前 length,可以附加一个新元素到该数组的尾部。
var array2 = [1, 2, 3]
array2[array2.length] = 4
console.log(array2) // (4) [1, 2, 3, 4]
// 有时用 push 方法可以更方便地完成同样的事情
var array3 = [11,22, 33]
console.log(array3.push(44)) // 4
console.log(array3) // (4) [11, 22, 33, 44]
/*
删除:
由于 js 的数组其实就是对象,所有 delete 运算符可以用来从新数组中移除元素:
*/
var array4 = [1, 2, 3, 4]
console.log(delete array4[2]) // true
console.log(array4) // (4) [1, 2, empty, 4]
/*
不幸的是,那样会在数组中留下一个空洞。这是因为排在被删除元素之后的元素保留着它们最初的属性。
而你通常想要的是递减后面每个元素的属性。
幸运的是,js 数组有一个 splice 方法。
它可以对数组做个手术,删除一些元素并将它们替换为其他的元素。
第 1 个参数是数组中的一个序号,第 2 个参数是要删除的元素个数。
任何额外的参数会在序号那个点的位置被插入到数组中:
*/
console.log(array4.splice(2,1)) // [empty]
console.log(array4) // (3) [1, 2, 4]
/*
注意:push delete splice 方法都会改变原来数组
*/
/*
枚举:
因为 js 的数组其实就是对象,所以 for...in 语句可以用来遍历一个数组的所有属性,
遗憾的是:for...in 无法保证属性的顺序,而大多数要遍历数组的场合都期望着按照阿拉伯数字顺序来产生元素。
此外,可能从原型链中得到意外的属性的问题依旧存在。
幸运的是,常规的 for 语句可以避免这些问题。
js 的 for 语句和大多数类 c 语言类似。它被 3 个从句控制 ——— 第 1 个初始化循环,第 2 个 执行条件检测,第 3 个执行增量运算:
var i;
for (i = 0; i < myArray.length; i++) {
document.writeln(myArray[i])
}
*/
/*
容易混淆的地方:
在 js 编程中,一个常见的错误是在必须使用数组时使用了对象,或者在必须使用对象时使用了数组。
其实规则很简单:当属性名是小而连续的整数时,你应该使用数组。否则,使用对象。
js 本身对于数组和对象的区别是混乱的。
typeof 运算符报告数组的类型是 'object',这没有任何意义。
*/
// js 没有一个好的机制来区别数组和对象。我们可以通过定义自己的 is_array 函数来弥补这个缺陷:
var is_array = function (value) {
return value && typeof value === 'object' && value.constructor === Array
}
// 遗憾的是,它在识别从不同的窗口(window)或 帧(frame)里构造的数组时会失败。有一个更好的方式会判断一个对象是否为数组
var is_array = function (value) {
return Object.prototype.toString.apply(value) === '[object Array]'
}
/*
方法:
js 提供了一套数组可用的方法。这些方法是被储存在 Array.prototype 中的函数。
在前面的章节里,我们看到 Object.prototype 是可以被扩充的。
同样,Array.prototype 也可以被扩充。
*/
// 举例来说,假设我们想要给 array 增加一个方法,它允许我们对数组进行计算:
Array.method('reduce', function (f, value) {
var i;
for (i = 0; i < this.length; i+= 1) {
value = f(this[i], value)
}
return value
})
/*
通过给 Array.prototype 扩充一个函数,每个数组都继承了这个方法。
在这个例子里,我们定义了一个 reduce 方法,它接受一个函数和一个初始值作为参数。
它遍历这个数组,以当前元素和该初始值为参数调用这个函数,并且计算出相加之和。
*/
11-22
687
“相关推荐”对你有帮助么?
-
非常没帮助
-
没帮助
-
一般
-
有帮助
-
非常有帮助
提交