Javascript DOM 编程艺术(第二版),英Jeremy Keith、加Jeffrey Sambells著,杨涛、王建桥等译,人民邮电出版社。
学到这的时候,我发现一个问题:学习过程中,相当一部分东西的概念在初学时是无法完全弄懂的,很多时候都是学到很多东西后,串起来才能更进一步。而我的博客目地是自学与交流,所以我只能是暂时地用红字标注这些东西,以后弄懂了会补全这些(相应的,有些东西会删除)。所以虽然说是某本书的读书笔记,但是写到后面绝对是不仅仅是局限于这本书了。所以不要指望着只看读书笔记学,还是要自己亲自把所有坑都踩一遍,把原书弄懂。
1.由P9“script标签放到html文档最后能使浏览器更快地加载页面”一段延伸而学到的东西
1.为什么把 Script 标签放在 body 结束标签之后 html 结束标签之前?
2.浏览器的渲染全过程?
2.程序语言分解释型和编译型两大类(但是现代语言以及不能如此简单粗暴地划分了,每种语言中都或多或少部分是解释部分是编译)。Javascript在某种意义上和英语一样是一种解释型语言。
3.Javascript语法的变量与语法命名
不允许变量名包含空格或标点符号(美元符号“$”、下划线“_”除外);
变量和其它语法元素的名字是区分大小写的;
变量第一个字符不允许是数字。
驼峰格式是函数名、方法名、对象属性名命名的格式——还有什么东西需要命名(我想不出了)?
4.必须明确类型声明的语言是强类型语言;不需要的,比如Javascript就是弱类型语言。
这意味着程序员可以在任何阶段改变变量的数据类型。
必须注意到,最近新出的Typescript,在我简单查阅了一些资料后,我认为其比Javascript多了一些东西:
可选择地变成强类型语言————这个好在让代码能更有可能地被写得更健壮,差在我觉得又向C++这种语言进化了,违背了初衷:DSL(虽然是可选择的)
需要编译——增强了跨平台的能力?
5.几种重要的数据类型
1.字符串
必须包含在引号里,至于是单引号还是双引号,根据所包含的字符来选择吧:包含字符有单引号,则用双引号包含,反之亦然;想用双引号包含双引号,就需要对该引号进行转义(escaping)(单引号同理),例如:
<script>
var test="Just a \"test\" "
</script>
不管用哪个,要保持一个作为风格。
2.数值
可以直接用整数、浮点数、负数。
3.布尔值
只有两个数值可选:true或者false。
4. 数组
前面的1、2、3都是标量(scalar)。如果某个变量是标量,它在任意时刻就只能有一个值。如果要用一个变量存储一组值,就要用数组(array)。
我注意到,对象和数组的声明中有时候会加入关键字new,即var test = new Array()和var test = Object()。这里的new是什么意思,加不加有什么区别?这似乎牵扯到Javascript中是没有类这个说法的,详细可以知乎搜索“Javascript new”
//声明一个长度(length)为4的数组
var beatles = Array(4)
//声明一个无法预知元素个数的数组
var test = Array();
//填充数组·1
var test = Array();
test[0] = "html";
test[1] = "CSS";
test[2] = "Javascript"
//取值
alert(test[2]);
//填充数组·2
var test = Array("html","CSS","Javascript");
//填充数组·3
var test = ["html","CSS","Javascript",1997,false];
可以看到,出现Array关键字时用(),没有的时候用【】。
这三个方法对开发人员很是麻烦和痛苦——毕竟是从0开始计数,值得庆幸的是我们还有其它方法填充数组:
//填充数组·关联数组法,这个方法用字符串代替数字值,使代码更具可读性。
//如果在填充数组时只给出了元素的值,这个数组就是一个传统的数组(第一个元素下标是0,第二个是1....etc);关联数组则是在填充时为每个新元素给出一个字符串的下标。
var test = Array();
test["dom"] = "html";
test["CSSOM"] = "CSS";
console.log(test["dom"]);
但我们不推荐这个做法,而是推荐用“5.对象”中的方法来填充数组,因为:
1.本质上,在创建关联数组时,你创建的是Array对象的属性(比如关联数组法的例子里,实际上是给test数组添加了dom、CSSOM两个属性);而有时候你想做的其实不是创建某个对象的属性,而是创建新的、通用的对象(Object)————为什么?请参考本文“12.对象”中的“1.属性与方法”。
2.用对象来代替传统数组的做法意味着可以通过元素的名字而不是下标数字来引用它们,这大大提高了脚本的可读性。
//右值可以是变量
var testVarOne = 2;
var test = [1,testVarOne];
//右值可以是数组的元素
var testVarTwo = [3,4,5];
var test = [1,testVarTwo[2]];
//右值可以是数组
var testVarTwo = [3,4,5];
var test = [1,testVarTwo];
//取数组中的数组元素,下面的例子取出的是“4”
alert(test[1][1]);
注意,当直接输出一个数组时,会用逗号区分这个数组的各个元素,然后当作字符串输出(使用alert()输出的情况)。
5.对象
Javascript里,所有变量实际上都是某种类型的对象。比如,一个布尔值是一个Boolean类型的对象,一个数组是一个Array类型的对象。
alert可以直接输出整个数组的值。对象就不可以了,只能输出一个唯一的值。(为什么会这样?输出数组的值是按什么顺序输出?)参考文章:
http://bbs.csdn.net/topics/390115408 https://zhidao.baidu.com/question/517805230.html http://blog.csdn.net/ideality_hunter/article/details/58603423
通用对象则是一种不属于某个特定类型的对象。
//通用对象创建·法一
var test = Object();
test.dom = "html";
test.CSSOM = "css";
test.year = 2018;
//对通用对象取值
alert(test.dom);
//通用对象创建·法二
var test = {dom:"html",CSSOM:"css",year:"2018"};
//推荐的填充数组方法
//不能把赋值语句放在声明语句后面,错误的顺序会导致赋值失败。
var test = Array();
var testVar = {dom:"html",CSSOM:"css",year:"2018"};
test[0] = testVar;
//不用数组,用对象的对象保存数据
var student = {};
var number = {
li:"00";
wang:"01";
mei:"10";
lei:"11"
};
student.phone = number;
6.操作
1.算术操作符
//拼接
//如果想显示的字符串之间有空格区分,就要在每个字符串后面加空格(这样能保证你每添加一个新的变量,都会有一个空格去区分它们)
var test = "I'm " + "king! "
//int+string与int+int的拼接结果是不一样的
var stringVar = "10",intVar = 10;
var out = Object();
//输出字符串“1010”
out.one = stringVar + stringVar;
//输出字符串“1010”
out.two = stringVar + intVar;
//输出整型20
out.three = intVar + intVar; alert(out.three);
7.条件语句
if(1 > 2){
alert("The world has gone mad!");
}
else{
alert("All is well with the world");
}
注意,条件语句的条件是布尔值——这意味着条件处的语句无论你写什么,最后都是要转换成true或者false。
8.比较操作符
1.要分辨“==”与“===”("!="与"!=="同理)的区别,参考:https://www.zhihu.com/question/31442029/answer/77931120?utm_source=qq&utm_medium=social
在这里暂时先记住一点:写“==”的时候要加注释,说清楚这里的意图(比如允许强制类型转换,为什么允许),举个例子:
var testVarOne = "";
var testVarTwo = false;
if(testVarOne == testVarTwo){
alert("Is true");
}
else{
alert("Is false");
}
这段代码的结果是弹窗输出"Is true"——因为相等操作符"=="认为空字符串与false的含义相同。要想进行严格比较,就要使用全等操作符"===",这个操作符会执行严格的比较(不仅比较值,还比较类型),虽然false与空字符串具体相同含义,但是Boolean与String不是一种类型,就好认为if为false。
这种错误经常会有,比如字符串1与数字1含义就是相等的!
2.不要把"=="写成"="
一般来说,赋值运算都是返回真值(因为赋值操作一般都会“成功”),所以写成"="就会让if始终为true:
var testVarOne = "1";
var testVarTwo = 1;
if(testVarOne = testVarTwo){
alert("Is true");
}
else{
alert("Is false");
}
但是也有例外,比如下面的例子就会让if始终为false:
var testVarOne = "1";
if(testVarOne = false){
alert("Is true");
}
else{
alert("Is false");
}
9.逻辑操作符
//逻辑与操作符,操作对象是布尔值(1 < test和test < 5的结果都是布尔值)
//当都为true时,if才为true
var test = 2;
if(1 < test && test < 5){
alert("Is true");
}
else{
alert("Is false");
}
//逻辑或操作符,只要有一个是true,if为true
var test = -2;
if(test < -1 || test > 5){
alert("Is true");
}
else{
alert("Is false");
}
/*
逻辑非操作符,只能作用于单个逻辑操作数(不是指单个对象或者单个数字之类,而是指单个布尔值结果,比如下面的例子——一般需要一个括号来辅助)。
其作用是把某个布尔结果颠倒过来。
*/
if( !(1 < 2) ){
alert("Is true");
}
else{
alert("Is false");
}
10.循环语句
1.while循环与do...while循环
//while循环
//与if语句很像,唯一的区别是:只要while为true,则花括号里的代码会反复执行下去
//test最终值为"10"。
var test = 1;
while(test < 10){
test++;
}
alert(test);
//do...while循环
//与while循环很像,但又一个区别:即使循环控制条件的首次求值结果是false,包含在花括号里的语句也至少会被执行一次。
//test最终值为"10"。
var test = 1;
do{
test++;
}while(test < 10);
alert(test);
只要判断条件和执行语句一样,do...while和while的循环次数和结果都是一样的。
2.for循环与array.length属性
//for循环
//其实和while本质上是一样的,只不过是把与循环有关的语句全部放到了括号里(确定循环次数的变量test、确定循环次数的test < 10和test++)。
//相比于while,让循环控制结构更加清晰。
for(var test = 1;test < 10;test++){
alert(test);
}
for循环最常见的用途是对某个数组里的全体元素进行遍历处理:
//aeeay.length的用法与简单数组的遍历
//test数组有四个元素,但是下标是1~3.
var test = ["html","CSS","Javascript","node.js"];
for(var count = 0;count < test.length;count++){
alert(test[count]);
}
11.函数
1.良好的习惯是先定义再调用。
//函数的定义与调用·1·有参数实现某个操作
function test(testVarOne,testVarTwo){
count = testVarOne + testVarTwo;
alert(count);
}
test(1,2);
//函数的定义与调用·2·无参数实现某个操作
//函数可以是不需要参数的。
最好自己实现一个完整的alert()函数。
//函数的定义与调用·3·有参数返回一个值
function testFunction(testVarOne,testVarTwo){
var count = testVarOne + testVarTwo;
return count;
}
alert( testFunction(1,3) );
返回一个值,则我们可以决定怎么用这个值——用来参与加法运算?当作if的判断条件?etc。
实现某个操作则是更广泛的意义了,比如弹窗输出(alert()函数就是这样)等。
按书里说的:函数的真正价值体现在,我们可以把它们当作一种数据类型来使用,这意味着可以把一个函数的调用结果赋给一个变量。
2.变量的作用域
全局变量(global variable)可以在脚本的任何位置被引用。
局部变量(local variable)只存在于声明它的那个函数内部。
这里有一些暂时不需要了解的知识点:
1.命名提升?函数提升?
2.JS编译器、运行期都在干嘛?
3.函数里出现同名的全局变量会发生什么——如果在函数内部不小心使用了某个全局变量的名字,即使本意是想用一个局部变量,也会被当成全局变量——还好,我们可以用var关键字明确地为函数变量设定作用域,目前来看这一点只适用于函数变量:
function square(num){
total = num * num;
}
var total = 50;
var number = square(20);
//输出“400”
alert(total);
函数在行为方面应该像一个自给自足的脚本,如果你总是在函数里用var关键字来定义变量,就能避免任何形式的二义性隐患。
12.对象
1.属性与方法。
数组(Array)也是一个对象,包含在对象里的数据可通过两种形式访问——属性(property)与方法(method)。
属性是隶属于某个特定对象的变量;方法是只有某个特定对象才能调用的函数——对象就是由一些属性和方法组合在一起构成的数据实体。
(学到这,可以试着解答之前的一个疑问了——为什么不建议给数组增加属性:数组是有自己的属性的,这篇文章有提到。所以一般来说,我们为了分类地存某些数据,用新的对象的属性来存更好。新的对象还能定义方法,更方便让我们把一系列的操作和数据绑定在一个清晰的对象里而不是数组。)
对象的创建方法在数组那部分已经说过了,这里只有伪代码简单回顾与深入一点:
//调用对象的属性
person.mood;
//调用对象的方法
person.walk();
/*创建对象的实例
对象=属性+方法,实例(instance)是对象的具体个体,比如有一个“人类”对象,那么“小明”等就是这个对象的具体实例。
*/
var ming_xiao = new person;
//现在可以通过这个实例调用相应的person对象中存在的属性和方法
ming_xiao.age;
在创建内建对象的新实例时,Javascript解释器会把实例的属性、方法等与对象同步(通过原型链的方式?)。
2.内建对象
Array、Date等由语言定义的对象就是内建对象,它们本身具有一些属性、方法可以让我们直接调用,比如array.length会得到数组有几个元素的信息。
对于内建对象,new加不加都一样,因为默认地,语言自己会补全这个关键字——但是自定义的就不行了,更多的东西目前就算学了也是一知半解,所以先到此为止,留下这篇参考,以后补全。
3.宿主对象
宿主对象不是由开发者或者语言定义的,而是根据运行环境,由浏览器提供的预定义对象,比如Form、Image等,最关键和重要的就是document对象,即文档模型——这也是为什么定义对象名的时候不要用form、image这种名字的原因(虽然浏览器提供的是大写开头)。
document对象
主要功能就是处理网页内容,详见下一篇文章。
window对象
对应浏览器窗口本身,这个对象的属性和方法通常称为BOM(浏览器对象模型) 。