javascript高级程序设计读书笔记
第2章 在html中使用javascript
- 一般都会把js引用文件放在</body>前面,而不是放在<head>里, 目的是最后读取js文件以提高网页载入速度。
- 引用js文件时可以使用defer属性, 意思是延迟加载, 最后加载。 或者async属性, 意思是异步加载,不必等待其他脚本加载也不会阻塞文档加载。
- <script type='text/javascript' defer='defer' src='example.js'></script>
- <script type='text/javascript' async src='example.js'></script>
- <noscpript></noscript>
第3章 基本概念
变量
var如果定义在函数中, 那么这个变量在函数退出后就会销毁。不加var 定义变量时, 这个变量会是一个全局变量。
数据类型
ECMAscript中一共有6种数据类型:Undefined, Null, Boolean, String, Number, Object
用 typeof操作符 (typeof是操作符, 不是函数,虽然typeof(xxx)也可运行, 但不推荐 ) 来检测数据类型:
undefined -- 这个值未定义
string -- 这个值是字符串
boolean -- 这个值是布尔值
number -- 这个值是数字
object -- 这个值是对象或null (typeof null会返回object)
function -- 这个值是函数
undefined: var message;alert(message); //undefined 声明了变量但没初始化时是undefined;
alert(message2); //error 直接输出一个没声明的变量会产生错误。
null: alert(null == undefined) //true 实际上, undefined的值是派生自null
boolean: Boolean(); 用于转化任何值成boolean值
number: alert(0.1+0.2) // 0.30000000000000004
NaN(not a number) 与任何值都不等。 alert(NaN == NaN) //false。 isNaN(); 检测参数是否“不是数值”
parseInt(99, 10) 此 函数 将99转换成十进制的int数字
string: alert(text.length) 用length 属性 来计算变量text的长度
var num=10; alert(num.toString()) 用toString() 方法 来将10转化成字符串,或者toString(2):转成2进制的。但null和undefined没有此方法。
不知道值是否是null或者undefined时可以用String(num)。但这个函数没有参数。
操作符
逻辑或, str1 || str2, 当str1为true时则往下执行, 不再执行str2, 这种执行也叫短路操作符。 经常用这种特性来给下面情况赋值
var myObject = preferredObject || backupObject //优先用preferredObject的值, 如果preferredObject值为空, 则用候补值backupObject
关系操作符, 如果两个都是数值,则进行数值比较 23 < 3 //false
如果两个都是字符串,则进行字符编码值比较, "23" < "3" //true
如果两个其中一个是数值, 则把把另外一个也转成数值再比较, "23" < 3 //false
"a" < 3 //false 因为a被转换成了NaN,任何操作数和NaN比较都是false
NaN < 3 //false
NaN >=3 //false
相等操作符, 分为 相等和不相等(先转换成相近类型 再比较) ; 全等和不全等(仅比较而不转换)
null==undefined //true
null===undefined //false
switch还可以这样写:
var num=25;
switch(true) {
case num<0:
alert();break;
case num >= 0 && num <0:
alert();break;
default:
alert();
}
第4章 变量,作用域和内存问题
变量
在ECMAscript的6种数据类型中, 前5种是基本类型: undefined, null, number, boolean, string。 最后一种是引用类型:object
当复制一个变量时,基本类型是创建了一个新的变量: var num1=10; var num2=num1; 这里num1和num2定义之后, 互不干扰。
而引用类型是创建了一个新的指针: var obj1 = new Object(); var obj2=obj1; 这里接下来如果ob1发生改变, obj2也会跟着变。
ECMAscript中所有函数的参数都是按值传递的。
function addTen(num) {
num += 10;
return num;
}
var count = 20;
var result = addTen(country);
alert(country); //20, no change
alert(result); //30
上面例子中num和rcountry是2个不同的变量, num是函数内的局部变量, 所以num改变后country还是没变。
function setName(obj) {
obj.name = 'Nicho';
obj = new Object();
obj.name = 'Green';
}
var person = new Object();
setName(person);
alert(person.name); //'Nicho'
这里函数内部重写了obj时,这个变量引用的就是一个局部对象了,而这个局部对象会在函数执行完毕后销毁。
检测类型
typeof操作符是检测变量的类型,检测是否属于string, number, underfined, boolean, object(typeof null也返回object)。
instanceof操作符是检测某个变量是否属于某个类型,返回true/false
alert(person instanceof Object); //变量person 是 Object 吗?
alert(colors instanceof Array); //变量colors 是 Array 吗?
alert(pattern instanceof RegExp); //变量pattern 是 RegExp 吗?
instanceof 还可以判断某某实例是否属于某某方法:
var test = function() {};
var test_i = new Object();
alert(test_i instanceof test); //true
作用域链
每个执行环境都有一个与之关联的变量对象, 环境中定义的所有变量和函数都保存在这个变量中。
当执行环境中的所有代码执行完毕后, 该环境被销毁, 保存在其中的所有变量和函数定义也随之销毁。(全局函数直至应用程序退出-比如浏览器关闭才会被销毁)
如果是一个函数, 作用域链中第一个变量就是arguments对象, 最后一个是全局执行环境的变量对象。(从自身向上找变量)
var color = 'blue';
function getColor(){
return color;
}
alert(getColor()); //blue
这样不会报错,查找color时,先找getColor内部有没有, 如果没有, 接着往上找。 由下至上找。 如果函数里有找到color,则不再往上找。
第5章 引用类型
在ecmascript中, 引用类型是一种数据结构, 用于将数据和功能组织在一起,常被称为类, 但这种称呼不妥当, 因为它不具备传统的面向对象语言所支持的类和接口等基本结构。
Object类型
创建Object方式一, 用Object构造函数:
var person = new Object();
person.name = 'Nico';
person.age = 22;
创建Object方式二, 用对象字面量:
var person = {
name: "Nico";
age: 22;
};
Array类型
创建Array方式一, 用Array构造函数:
var colors = new Array();
var colors = new Array(20); //创建长度为20的数组
var colors = new Array('Red', 'Blue', 'Black', 'White'); //创建长度为4的数组并赋值
var colors = Array('Red'); //省略new也可以
创建Array方式二, 用数组字面量:
var colors = ['Red', 'Blue', 'Black'];
检测数组
if (value instanceof Array) { ... }
if (Array.isArray()) { ... } //只支持ie9以上
栈方法
LIFO(Last-In-First-Out)
push(), popup()
队列方法
FIFO(Fist-In-First-Out)
shift(), push()
重排序方法
reverse() 反转数组项顺序, 不是降序, 只是反转。
sort() 方法会调用每个数组项的toString()转型方法,然后比较得到的字符串。 即使数组中是数值, sort()方法比较的也是字符串
var values = [0, 1, 5, 10, 15];
values.sort();
alert(values); //0, 1, 10, 15, 10
sort() 可以传入函数作为参数来解决这个问题
function compare(value1, value2) { if (value1 < value2) { return -1; }else if (value1 > value2) { return 1; }else{ return 0; } } valuesc = values.sort(compare); alert(valuesc);
操作方法
concat() 基于当前数组的所有项创建一个新数组
var colors = ['red', 'blue', 'green']; var colors2 = colors.concat('yellow', ['black', 'brown']); alert(colors); alert(colors2);
slice() 基于当前数组中的一或多项创建一个新数组。 可以接受一或二个参数, 一个参数时, slice()方法返回从该参数指定位置到当前数组末尾的所有项。 二个参数时, 方法返回起始和结束位置之间的项, 但补包裹结束位置的项。 该方法不会影响到原数组。
var colors = ['red', 'green', 'blue', 'yellow', 'purple']; var colors2 = colors.slice(1); var colors3 = colors.slice(1,4); alert(colors2); alert(colors3);
splice() 可以删除,插入, 替换 数组中的项, 并返回一个数组。
位置方法
indexOf 和 lastIndexOf
var numbers = [1,2,3,4,5,6]; alert(numbers.indexOf(4)); //3 -表示第三位,位从0开始计算
迭代方法
every(), filter(), forEach(), some(), map() -数组中每一项都会执行
var numbers = [1,2,3,4,5,4,3,2,1]; var everyResult = number.every(functoin(item, index, array) { return (item > 2); }); alert(everyResult);
归并方法
reduce() 和 reduceRight()
var values = [1,2,3,4,5]; var sum = values.reduce(functoin(prev, cur, index, array) { return (prev + cur); }); alert(sum); //return 15
Date类型
var now = new Date();
RegExp类型
Functionle类型
第一种 function sum(num1, num2) { return num1 + num2; } 第二种 var sum = function(num1, num2) { return num1 + num2; }; 第三种, 不推荐,因为会解析两次。但是直观的反应了“函数是对象, 函数名是指针” var sum = new Function("num1", "num2", "return num1+ num2");
以上第一种和第二种的区别是解析器会先读取函数声明(第一种),而函数表达式是代码执行到此才解析
alert(sum(10, 10));
function sum(num1+num2) {
return num1+num2;
}
函数内部属性
argument.callee 指向本函数
caller 保存着调用当前函数的函数的引用。
function fs() { sum(); } function sum() { alert(arguments.callee.caller); } fs();
函数的属性和方法
函数是对象, 所以函数也有属性和方法。
每个函数包含2个属性:length和prototype。length表示函数希望接受的命名参数的个数。
每个函数包含2个非继承而来的方法: apply()和call()
ECMAscript5还定义了一个方法bind(), 这个方法会创建一个函数的实例,其this值会被绑定到传给bind()函数的值。
基本包装类型
以下是String的各种函数, 看看就好, 需要用时搜索便可。
var StringValue = 'hello world';
StringValue.length;
StringValue[1]
StringValue.concat("!");
slice()
substr()
substring()
StringValue.indexOf('o')
trim()
toLowerCase(), toUpperCase()
match()
replace()
split()
localeCompare()
Math.ceil(), Math.floor(), Math.round(), Math.random()
第6章 面向对象的程序设计
访问器属性
var book = { _year: 2004, edition:1 } book.__defineGetter__("year", function(){ return this._year; }); book.__defineSetter__("year", function(newValue){ if(newValue > 2004) { this._year = newValue; this.edtion += newValue-2004; } }); book.year = 2005; alert(book.edtion);
创建对象
工厂模式
/*工厂模式*/ function createPerson(name, age, job) { var o = new Object(); o.name = name; o.age = age; o.job = job; o.sayName = function (){ alert(this.name); }; return o; } var person1 = createPerson('Nicho', 29, 'Engineer'); var person2 = createPerson('CoWwW', 39, '1Engineer'); console.log(person1); console.log(person2);
构造函数模式
/*构造函数模式*/ function Person (name, age, job) { this.name = name; this.age = age; this.job = job; this.sayName = function(){ alert(this.name); }; } var person1 = new Person('Nicho', 29, 'Engineer'); var person2 = new Person('CoWwW', 39, '1Engineer');
和工厂模式的不同点:
1. 没有显式的创建对象
2. 直接将属性赋值给this对象
3. 没有return语句
这种方式调用的构造函数实际上会经历以下4个步骤:
1. 创建一个新对象
2. 将构造函数的作用域赋值给新对象(因此this就指向了这个新对象)
3. 执行构造函数中的代码(为这个新对象添加属性)
4. 返回新对象
创建自定义的构造函数意味着将来可以将他的实例标识为一种特定的类型;这正式构造函数胜过工厂模式的地方。
原型模式
我们创建的每个函数都有一个prototype(原型)属性。这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。
使用原型的好处的让所有对象实例共享它所包含的属性和方法。
function Person(){ } Person.prototype.name = "Nico"; Person.prototype.age = 30; Person.prototype.job = "web engineer"; Person.prototype.sayName = function() { alert(this.name); } var person1 = new Person();
继承
基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法
/*继承*/ function SuperType() { this.property = true; } SuperType.prototype.getSuperValue = function(){ return this.property; } function SubType(){ this.subproperty = false; } SubType.prototype = new SuperType(); SubType.prototype.getSubValue = function(){ return this.subproperty; } var instance = new SubType(); alert(instance.getSuperValue()); alert(instance.getSubValue());
instance的原型指向subtype, subtype原型指向supertype, supertype原型指向Objet
所有函数的默认原型都是object的实例,因此默认原型都会包含一个内部指针,指向Object.prototype。所以所有自定义类型都会继承toString(), valueOf()等默认方法
确定原型是和实例的关系用instanceof操作符:
alert(instance instanceof Object) //true
alert(instance instanceof Supertype) //true
alert(instance instanceof subtype) //true
或者isPrototypeOf()方法
不能使用对象字面量创建原型方法,会导致重写原型链。
下面的instance1改动影响到了instance2,之所以影响还有2个前提条件:
1是SubperType里是数组
2是instance1后用了push
如果SuperType里是字符串或者instance1用了赋值符“=”, 都不会影响instance2,所以主要原因在于“引用类型”(详见第4章引用类型的特性)
/*原型链问题*/ function SuperType() { this.colors = ['red', 'blue', 'yellow']; //this.colors = 'red'; } function SubType() { } SubType.prototype = new SuperType(); var instance1 = new SubType(); instance1.colors.push('black'); //instance1.colors = ['red', 'blue']; //instance1.colors = 'black'; alert(instance1.colors); var instance2 = new SubType();
寄生组合式继承
function inheritPrototype(subType, superType) { var prototype = object(superType.prototype); prototype.constructor = subType; subType.protoType = protoType; }
函数表达式
函数声明提升:执行代码之前会先读取函数声明, 意味着可以把函数声明放在调用他的语句后面
sayHi(); function sayHi() { alert("Hi!"); }
匿名函数: var functionName = function (arg0, arg1, arg2) { ...... };
递归: 递归函数是在一个函数通过名字调用自身的情况下构成的。
function factorial(num) { if (num < 1) { return 1; } else { return num*factorial(num-1); } }
arguments.callee 指向正在执行的函数的指针
function factorial(num) { if (num < 1) { return 1; } else { return num*arguments.callee(num-1); } }
闭包
闭包是指有权访问另一个函数作用域中的变量的函数。
块级作用域
块级作用域(私有作用域)
var someFunction = function() { //这里是块级作用域 }; someFunction(); (function(){ //这里是块级作用域 })(); function(){ //这里是块级作用域 } //出错
上面第三段会出错, 因为javascript将function关键字当作一个函数声明的开始,而函数声明后不能跟圆括号。然而, 函数表达式后面可以跟圆括号。所以上面第二段在外面加了圆括号, 就是把函数声明转换成函数表达式。
块级作用域用在最外部可以防止过多的像全局中添加变量, 也可以减少全局命名冲突
(function(){ var now = Date(); ... })();
第8章 BOM
设置超时调用
var timeouId = setTimeout(function() { alert("hello world"); ), 1000); //cancel it clearTimeout(timeoutId);
第8,9,10,11,12章 分别是bom, dom, dom扩展,dom2和dom3. 知识点比较零散,就写一些比较常用的吧。
document.querySelector("#myDiv"); //返回一个对象
document.querySelectorAll(".myClass"); //返回NodeList
document.getElementsByClassName();
if (document.readyState == "complete") { //执行操作 } //加载完文档
if (document.compatMode == "CSS1Compat") { //判断混杂模式
alert("Standards mode");
} else {
alert("Quirks mode");
}
document.head;
document.charset = "UTF_8";
dataset
innerHTML
myDiv.style.cssText = "width:200px;height:100px;color:red"; //cssText, 整段css
getComputedStyle/currentStyle //得出当前计算出的样式
OffsetHeight/OffsetWidth 包含边框的宽高
clientWidth/clientHeight 不包含边框的宽高
scrollTop/scrollLeft 改变元素的滚动位置
第十三章 事件
event.type //click, mouseover, mouseout
preventDefault() //阻止特定事件的默认行为
IE中的event
var event = window.event;
alert("event.type");