JavaScript 权威指南第6版 - [阅读笔记]

时间:2022-01-04 16:32:16
JavaScript 基础   Page 13
(1)<script> 的属性:async,charset,defer='defer',language已废,src,type
(2)null 是一个空值,是一个特殊对象; undefined 表示空值,它不是对象 是未定义的意思;undefined==null 返回true; 
(3)全局变量:
全局属性:undefined、Infinty、Nan
全局函数:isNaN()[Not a Number不是数字返回true]、parseInt()、eval()
构造函数:Date()、RegExp()、String()、Object()
全局对象:Manth、JSON
(4)JavaScript 中的原始值:undefined,null,布尔值,数字,字符串与对象(数组和函数)不一样,是不可改变的;
(5)delete o.x 可以删除对象的一个属性;
(6)复合语句:用{} 把几个语句括起来组成一个复合语句;  
        空语句: ; 直接用分号结尾; 例如: for(var i=0; i<a.length; a[i++]=0);
(7)with:用于临时扩展作用域链;缺点:非常难于优化,并且运行得更慢;
         例如:with(object); statement  将语句 object 添加到作用域链的头部,然后执行 statement 最后把作用域链恢复到原始状态;
(8)“use strict” 是 ECMASript 5 引入的一条指令,它只能出现在代码的开始或者函数体的开始;
        在脚本或函数中,后续的代码将会解析为严格的代码,严格代码以严格模式执行;ECMAScript 5中的严格模式是该语言的一个受限制的子集,它修正了该语言的重要缺陷,并提供健壮的查错功能和增强的安全机制,它与非石桥模式之间的区别:
1)严格模式下禁止使用with; 
2)严格模式下所有变更都要行声明,如果未声明就用会引出一个错误,(非石桥模式下,隐式声明的全局变量会给全局对象添加一个属性)
3)严格模式下调用的函数中的this值是 undefined (非严格中this值总是全局对象)
 4)严格模式下在一个对象直接量中定义两个或多个同名属性将会产生一个语法错误,非严格下则不会;
 5)严格模式下函数声明中存在两个或多个同名的参数将产生一个语法错误(非严格下则不会)
(9)对象是可变的,是通过引用来操作的;常对对象操作的方法:create,set,query,delete,test,enumerate
        每个对象除了属性之外还有三个相关的特性:
        对象的原型prototype:  指向另外一个对象,本对象的属性继承自它的 原型对象;
        对象的类class:是一个标识对象类型的字符
        对象的扩展标记extensible flag:指明了是否可以向该对象添加新属性
(10)对象直接量:var a = {x:1,y:2};
        对象直接量是一个表达式,每次运算都创建并初始化一个新的对象,如果在一个重复调用的函数中的循环体内使用了对象直接量,它将会创建很多新对象;
(11)静态函数:Object.create() 方法创建一个新对象 作用防止意外修改对象的属性。P134
        通过原型继承创建一个新对象
function inherit(p){
    if(p==null) throw TypeError();
    if(Object.create)    //如果p是一个对象但不能是null
        return Object.create(p);    //如果 Object.create() 存在 
    var t = typeof p;
    if(t !=='object' && t !=='function') throw TypeError();
    function f(){};    //定义一个空构造函数
    f.prototype = p;    //将原型属性设置成 p
    return new f();    //使用f()创建p的继承
}
(6.2)属性的设置和查询
关联数组对象:数组元素是通过字符串索引而不是数字索引的数组是关联数组,或叫散列,映射或字典。 js 对象都是关联数组;
继承:JS只有在查询属性时才会体会到继承的存在,设置属性则和继承无关;
查询一个并不存在的属性不会报错,如果对象 o 自身的属性或者继承的属性中都未找到属性x 则 o.x 返回 undefined;
如果查询一个不存储的对象,就会报错;
(6.3)删除属性  delete 可以删除属性  用法: delete book.subtitle
注意:delete只是断开属性和宿主对象的联系,不会去操作属性中的属性;
          delete 只能删除自有属性,不能删除继承属性;要删除继承属性必须从定义这个属性的原型对象上删除它[会影响到所有继承自这个原型的对象];
          如果 delete删除不存在的属性时也会返回true; 
          delete 不能删除那些可配置属性为 false 的属性;比如 声明变量和函数声明创建的全局对象的属性,
                如: delete Object.prototype  返回 false
                var x=1; delete this.x  不能删除; function f(){}; delete this.f; 也不能删除全局函数;
(6.4) 检测属性  
JavaScript 的对象可以看做是属性的集合;
检查属性是否属于某个对象:
in :"x" in o 返回 true 则是o的属性,false则不是;也可以用  o.x !== undefined 判断是不是它的属性;
hasownProperty():检查给定的名称是否是对象的自有属性,如果是继承属性则返回 false;
propertyIsenumerable() :只有检测到属性是自有属性并且可枚举性,才返回true;通常Js创建的属性都是可枚举的;
(6.5)枚举属性 通常使用for/in进行循环遍历  
注:对象继承的内置方法不可枚举
除了for/in外还提供一两个枚举对象属性的两个方法[ECMAScript 5]:
Object.keys(o)  返回一个数组,由对象中可枚举的对象的名称组成;
Object.getOwnPropertyNames(o)  返回对象所有的自有属性的名称,不仅仅是可枚举属性;
(6.6)getter 和 setter 定义属性存取器,注:存取器属性是可以继承的
var o={
    data_prop:value;
    get accessor_prop(){/*函数体*/},
    set accessor_prop(){/*函数体*/}
}
(6.7)属性的特性:它的值:value,可写性:writalbe,可枚举性enumberable,可配置性:configurable
通过 Object.getOwnPropertyDiscriptor({x:1},"x") 可以获取某个对象特定属性的属性描述符;
对于继承的属性与不存在的属性直接返回:undefined
获取继承属性的特性需要遍历原型链:Object.getPropertyOf()
设置属性的特性,或者让新建属性具有某种特性:Object.defineProperty(o,"x",{value:1,writable:true,enumerable:false,configurable:true})   
结果属性存在但不能枚举;注意:这个方法可以修改已有属性值和新建立属性值,但不能修改继承属性;
同时修改多个属性:Object.defineProperty(o,映射表{x:{value:1,writable:true},y{enumerable:false,configurable:true},z:{}})
(6.8)每个对象都有与之相关的原型(prototype),类 class 和可扩展性 extensibleattribute
对象的原型是用来继承属性的,原型属性是在实例对象创建之初就设置好的;
通过对象直接量创建的对象,用Object.prototype 做为它的原型;
通过 new 表达式创建的对象使用构造函数的 prototype 做为它的原型;
通过 Object.create()创建的对象 使用第一个参数做为它的原型(也可以是null);
要想检测一个对象是否是另一个对象的原型(或者处于原型链中)要使用 isPrototypeOf()  方法 例如:
可能通过 p.isPrototypeOf(o) 来检测p是否是o的原型;
var p={x:1};   //定义一个原型对象
var o=Object.create(p);       //使用这个原型创建一个对象
p.isPrototypeOf(o);    //true o 继承自P
Object.prototype.isPrototypeOf(p);      // true p继承自 prototype
对象的类属性(class attribute)是一个字符串,用以表示对象类型的信息;
ECMAS3和5都没有提供设置这个属性的方法,但有一种间接的方法可以查到它:P151
Object.prototype.toString().call(obj).slice(8)
对象的可扩展性用于表示是否可以给对象添加新属性,所有内置对象和自定义对象都是显式可扩展的,宿主对象的可扩展性是由 JS 引擎定义的,除非将他们转换为不可扩展的;
ECMAS5中可以使用 Object.isExtensible(o) 检查对象是否可扩展;
Object.preventExtensions(o); 将对象做为参数传进去把对象变成不可扩展;一旦转为不可扩展就转不回来了;
如果给一个不可扩展的对象的原型添加属性,那么这个不可扩展的属性会继承这些新的属性;
可扩展性的目的是将对象锁定,不受外界的干扰;
Object.seal(); 除了将对象设置成不可扩展外,还可以将对象所有的自有属性设置成不可配置,也就是说不能给这个对象添加新属性,而且已经有的属性也不能删除或者配置,不过它已有的可写属性依然可以设置;对于那些已经封闭的对象是不能解封的,可以使用 Object.isSealed(o); 来检查对象是不是被封闭;
Object.freeze(o) 将更严格的锁定对象(冻结):除了将对象设置成不可扩展和将其属性设置成不可配置之外,还可将它自有的所有数据属性设置成只读;如果对象具有存取器 setter 方法则存取器则不受影响;
使用Object.isFrozen(o) 判断对象是否冻结;
(6.9)对象序列化:指将对象的状态转成字符串,也可以将字符串还原为对象
ECMAS5 提供了 JSON.stringify() 与  JSON.parse() 来序列化和还原js对象;这两个方法可以接受第二个可选参数,通过传入要序列化或者还原的属性列表来定制自定义序列化或还原操作;
json 语法是 JS 的一个字集,支持对象,数组,字符串,无穷大数字,true,false,null,并且它可以序列化和还原;
(6.10)对象方法
toString() 方法没有参数 :数组转换成字符串时每个元素都转成了字符串,函数转换成字符中时,将得到函数的源代码;
toLoaleString()  返回这个对象本地化字符串  P154
toJson()  Object.prototype实际上没有toJson()方法,如果对象要执行序列化可以使用 JSON.stringify(obj) 此方法会调用 toJSON()方法
valueOf() js 将对象转换成某种原始值而非字符串才会用到它 
第七章 数组
数组是值的有序集合,js数组是无类型的,数组元素可以任意类型,同一数组中的不同元素也可以是不同类型;数组最大索引:2^32-2 最大容量:4294967295
用数组索引访问数组元素一般来说比访问常规的对象属性要快很多
数组继承 Array.prototype中的属性
7.1 创建数组:
var a=[];     var b=[1,2,3];    var c=[a,1,1.1,"a",]; c的最后一个值为 undefined ; 
var a=[,,] a.length =2 只有两个元素;
构造函数创建数组:var a= new Array();     var b=new Array(10);    var c=new Array(5,3,2,1,"string");
7.2 读写  a[0];  
数组是对象的特殊形势:使用方括号访问数组的元素就像用方括号访问对象的属性一样,JS将指定的数字索引值转换成字符串将1转换成“1”然后将其做为属性名来使用;
可以使用负数与非整数来索引数组; a[-2.13] = true;   a[1.0]=10 与a[1] 相等   a["1000"]=a[1000]的值;
数组索引没有越界概念:a[100]不会报错,但会返回 undefined 
7.3 稀疏数组 就是包含从0开始不连续索引的数组 如果数组是稀疏的,那么length值大于元素个数
稀疏数组通常比稠密的慢,内存占用要多,这样的数组查找元素的时间和对象的属性查找的时间一样长;
7.5 给数组添加元素   
a.push("ab","cd") 在数组末尾添加两个元素,也可以更多;
a.unshift("a") 在数组的头部添加元素;
delete a[1]  删除数组元素 不会改变数组的.length属性,索引也不会自动补齐,它会变成稀疏数组;
pop()方法 与 push() 一起使用,使长度减少1并返回删除的数组值;
shift()方法与 unshift() 一起使用,从数组头部删除一个元素;shif() 当前所有元素的索引下移到比当前索引低1的值;
splice() 通用的方法插入删除或者替换数组;它会根据需要修改length属性并移动元素到更高或更低的索引处;
7.6 数组遍历   var a = Object.keys(o);  获取o对象属性名组成的数组
for 循环 遍历;
arr.forEach(function(x){操作x元素值});
7.8 
Array.join() 方法  var a=[1,2,3]  是 string.split() 的逆向操作;
a.join()  "1,2,3"        a.join("")  输出 "123"            a.join(" ") 输出 "1 2 3"
Array.reverse()  将数组中的元素颠倒顺序;它不是重新排列创建新的数组而是在原来数组上中重新排列它;
Array.sort()  将原数组排序并将排完后的数组返回;不带参数时数组与字母表排序为准;如果有 undefined 会排到最尾处;
Array.sort(function(a,b){比较大小})  可以传一个方法进去来比较值大小;
Array.concat() 方法创建并返回一个新数组;它的元素包括调用 concat()的原始数组的元素和concat()和每个参数 
Array.slice(starIndex,endIndex) 返回指定数组的一个片段或者子数组;  包含第一个参数的位置但不到第二个参数位置的所有元素;
        它不会修改调用的数组; 出现负数表示最后一个索引 -1 -3是倒数第三个索引;
Array.splice(para1,para2)  能够从数组中删除元素,插入元素到数组中或者同时完成这两项操作。它会修改调用的数组,会根据需要增加或者减少数组的索引值;
para1:指定插入或者删除的起始位置,para2 指定了应该从数组中删除元素的个数,如果省了第二个参数将从开始点一直删除到结尾;它返回由删除元素组成的数组;没有删除返回空;
paraN 指定任意N个参数是需要插入到数组中的元素,从第一个参数的位置开始插入;
push() 与 pop() 允许数组当栈来使用:psuh()在数组的尾部添加一个或多个元素,并返回数据的新长度,pop() 删除数组的最后一个值,并减小数组的长度,返回删除值;注意这两上方法都会修改原数组并不是创建新数组;能够使用数组实现行进后出的栈操作;
unshift() 与 shift() 与 上面两个相反,是在数组的头部进行插入与删除操作;
toString() 与 toLoalString() 把数组变成字符串;
7.9 ECMAS 5 中的数组方法:提供了9个新的数组方法来遍历,映射,过滤,检测,简化,搜索数组;function(数组元素,索引,数组本身){操作}; 将做为第2-4个参数传给函数
forEach(function(value){value操作}) 从头至尾遍历数组,不能使用break停止循环,但可以用try,cache来停止;
var b = a.map(function(x){retun x*x}) 将调用数组的每个元素来传递给指定函数,并返回一个数组,它函该函数的返回值;它的返回值是新数组不会修改原数组;它不会路过稀疏数组,返回的也会是稀疏数组;
var a =b.filer(function(x){x>3}) 方法返回的数组元素是调用数组的一个子集,传递的函数是用来逻辑判断的;返回当前数组>3的所有的值的一个数组;它会跳过稀疏数组中缺少的元素总会返回稠密数组;可以使它来压缩稀疏数组的空缺: var b = a.filer(function(){return ture}); 还可以删除 undefined 和 null 元素  return x!==undefined && x!==null
every() 和 some() 是对数组的逻辑判定:它们对数组应用指定的元素进行逻辑判定返回 true 或 false;两个方法一但确认返回什么值,就立即停止遍历数组;
var a=[1,2,3]; a.every(function(x){return x<10}) 返回 true 里面所有的值都小于10才会返回 true ;针对所有值判定都返回 true 最后才返回 true 否则返回 fasle
var a=[1,2,3,11]; a.some(function(x){return x>10}) 返回 true 里面只有一项值大于10就会返回 true;所有的值对比都返回 flase 时才会返回 false;
reduce() 与 reduceRigth() 方法使用指定的函数将数组元素进行合并,生成单个值;也被称为"注入"和"折叠"; 
var a=[1,2,3,4,5]; var sum = a.reduce(function(x,y){return x+y;},0)  数组求和;(function(x,y){return x*y},1) 数组求积,(function(x,y){return (x>y)?x:y}) 示最大值; 0,1 第二个参数其实是初始值;
空数组不能调用 reduce() 否则会报异常错误;reduceRight() 与 reduce原理一样只不过索引从高到低,从右到左开始工作,例如数组的乘方操作是从右到左的;
indexOf() 与 lastIndexOf() 搜索修整数组中具有给定值的元素,返回找到的第一个元素的索引如果没找到返回-1
7.10 数组的类型  判断是否为数组:Array.isArray() 来判定 ECMAS5; 
[] instanceof Array 返回 true ,但它不是一个可靠的数组检测方法
7.11 类数组对象:检测方法 P174  我理解类数组就是一个json串;
7.12 做为数组的字符串: string a='abcd'; charAt(1) 返回b  a[1] 返回b 注:使用数组的方法来修改字符串会报错,但没的错误提示;
第八章 函数
形参:函数中传入的变量,实参:运行时的函数调用传入时的参数;
this 本次调用的上下文
JS里函数就是对象,可以把函数赋值给一个变量或者做为参数传给其它函数;
函数可以互相嵌套,这样它们就可以访问它们定义时的做用域内的任何变量这就构成了一个闭包;
构成主体的代码在定义时不会直接执行,只有调用该函数时才会执行;
调用函数有四种方法:
做为函数,做为方法,做为构造函数,通过他们的call() 和 apply() 方法间接调用 ;
确定当前角本是否是严格模式:var static = (function(){return !this;}());
方法链:当方法的返回值是一个对象,这个对象还可以调用其它的方法,这种方法调用序列(通常称为连或者级联)每次的调用结果都是另外一个表达式的组成部分;
【当方法并不需要返回值时最好直接返回this,在这种编程风格中只要指定一次调用的对象即可如:shap.setx(100).setY(100).setSize(50).draw();】
this 没有作用域的限制,并且不能赋值,不是变量也不是属性;   p183 this的详细使用;
如果函数或者方法调用之前都带有new关键字,它就构成构造函数调用;
8.3 形参和实参
a=a||[]; 等同于 if(a===undefined){a=[]};
实参对象arguments:函数f实参只有一个x,调用时传了两个实参可以用 x 或 arguments[0] 来调用 第一个,可以用 arguments[1] 来调用 第二个参数,并且只能这样获得;
实参对象还定义了 callee 与 caller 属性 非严格模式下 callee 指定了当执行的函数,caller 是非标准的,它指定当前执行的函数的函数; 通过 caller 属性可以访问调用栈;在某些匿名函数中 callee可以递归调用自身 P188
可以将对象属性当做实参: function(arg){arg.a,arg.b,arg.c}  这样调用
8.4 作为值的函数
函数可以赋值给一个变量:var a = square; square是个函数;
也可以赋值给对象的一个属性:var o={add:function(x,y){return x+y;}};
还可以直接赋值给数组元素:var a[function(x){return x*x},20]
函数可以有自定义属性: a.count = 0;function a(){return a.count++;};调用一次a 属性值就会+1;
8.5 作为命令空间的函数  P194
8.6 闭包  P196
8.7 函数属性、方法和构造函数:函数也可以有属性和方法
函数的length属性【如:a.length】是只读的表示函数的实参的个数[参数是指形参,就是在函数定义时给出的实参的个数]
function a(arg) {
    var a = arg.length;
    var b = arg.callee.length;
    if (a !== b) {
        throw Error("两个参数不一样多哈");
    }
};
function f(x, y, z) {
    a(arguments);
    return x + y + z;
}
f(1,2,3) 与 f(1,2,3,4) 对比一下
prototype 属性:每个函数都包涵一个 prototype 属性,这个属性是指向一个对象的引用,这个对象叫做原型对象;(prototype object);每个函数都包含不同的原型对象,当函数用做构造函数的时候,创建新的对象会从原型对象上继承属性;
检查一个对象是否是真真正的函数:(并且具有函数方法)可以检测它的classn属性:
function() IsFunction(x){return Objet.prototype.toString.call(x) ==='[object Function]'}
8.8 函数式编程:
可以用数组的map()与reduce()来实现数组平均值与标准差的计算;
var sum = function(x,y){return x+y;};data=[1,2,3,4,5,6,7,8,9];var aaa=data.reduce(sum)/data.length;  aaa为平均值;
高阶函数:操作函数的函数,它接收一个或多个函数做为参数,返回一个新的函数; P209
第九章  类和模块   类的实现是基于原型继承机制的;
9.1 类和原型:类的所有实例对象都从同一个原型对象上继承属性;原型对象是类的核心;
9.2 类和构造函数: P216
定义构造函数就是定义类,并且类名首字母要大写,而普通函数和方法的首字母都小写;
定义类: function Run(){}  类(构造函数调用必须用 new关键词来调用) 
原型对象的命名: Run.prototype={fun1:function(){},fun2:functioni(){},...}  这样 Run() 构造函数的调用会自动使用 Run.prototype作为新 Run对象的原型;
9.3 javascript 中的类继承
构造函数对象:为JS对象定义了类的名字,任何添加到这个构造函数对象中的属性都是这个类的字段和方法,如果属性值是函数的话就是类方法;
原型对象:原型对象的属性被类的所有实例所继承,如果原型的属性是个函数的话,这个函数就做为类的实例的方法来调用 ;
实例对象:类的每个实例都是一个独立的对象,直接给这个实例定义的属性是不会为所有实例对象所共享,定义在实例上的非函数属性则是实例的字段;
JS定义类步骤:P220
1、先定义一个构造函数,并设置初始化新对象的属性;
2、给构造函数的 prototype 对象定义实例的方法;
3、给构造函数定义类字段与类属性;
类的实例方法定义为原型对象的函数值属性;
注意:JS的实例方法必须使用this关键字;类的方法通常不使用this关键字,它们指对其参数操作;P222
9.4  类的扩充 P223
JS中基于原型的继承机制是动态的:对象从其他原型继承属性,如果创建对象之后原型的属性发生改变,也会影响到继承这个原型的所有实例对象,我们可以通过给原型对象添加新方法来扩充JS类
9.5 类与类型
instanceof 运算 左侧是待检测其他类的对象,右操作数是定义类的构造函数:如果o继承自c.prototype 则表达式 o instanceof c 返回值为 ture 
这里的继承是累计继承的;实际上是检测了对象的继承关系,而不是检测创建对象的构造函数;
另一种识别对象是否属于某个类的方法是使用 constructor 属性;
第十章 正则表达式
10.1 正则表达式的定义: 可以使用 RegExp() 构造函数来创建 RegExp 对象;
不过更多的是通过五种特殊的直接量语法来创建,包含在一对斜杠/之间 :var parttern =/s$/   匹配所有以 s 结尾的字符串
 ----后续有时间再补
JavaScript 权威指南第6版 - [阅读笔记]JavaScript 权威指南第6版 - [阅读笔记]