学习资源来自于js高程,有一部分参考犀牛。基本上是按照js高程的目录来学的。笔记记了些重点和引申。还有一些参考网站。
JavaScript简介
Javascript是ecma-262的一种实现。它由三部分组成:ecmascript、bom、dom。ecmascript本身是ecma-262定义的标准,不依赖于具体环境,也不包含输入输出定义。宿主环境提供ecmascript的具体实现和交互的扩展。比如浏览器、node、flash等。
大家可以百度一下ecma发展的时间线。
es4夭折是因为部分内容太过激进等于重新定义一门语言,缺乏实践检验,微软和雅虎反对方话语权很大。不过当年如日中天的adobe还是自己用as3.0实现了es4。es4的部分内容将在es6中体现。从es3到es6相当于15年的沉淀。
es5实际就是es3.1版本。是一个温和过度版本。
js引擎
能解析并能运行js代码的解释器
浏览器通常会有js引擎,js刚出来时就是运行在浏览器中,作为客户端语言使用。常见的js引擎有:
- chrome v8
- firefox spiderMonkey
- edge chakra
- node基于v8,只保留es核心,没有dom和bom。增加了事件驱动非阻塞I/O模型,更加轻量和高效。
DOM
dom0不算标准
Dom1
1998年成为W3C的推荐标准。同ecma262类似,dom并不止针对js。包含dom core、dom html两个模块
Dom2
2000年末发布,包含dom views、dom events、dom style、dom traversal and range
Dom3
2004年发布包含dom load and save、dom validation、dom style核心扩展
Dom级别本质上说是版本。
BOM
浏览器对象模型bom。因为作为javascript实现的一部分,没有相关标准。原来比较看宿主环境。但是html5致力于把很多bom功能写入标准,有望能改变这种现象。
在HTML中使用JavaScript
<script>标签,属性src, async,defer,这三个属性都只针对外部文档,延迟或异步执行。其他的属性基本没什么用。
在<script>嵌入的代码中,使用</script>会报错。需要用转义字符<\/script>
引用外部js尽量用标签对,别用省略写法。当浏览器遇到<script>时,便会解释运行js内容,当其中内容都解释运行完毕,才会继续呈现html中的其他内容。因此<script>的位置很重要。如果把<script>放入,有时候加载外部文件,比如被墙的google会阻塞页面的呈现。如果把<script>放入页面最末尾,当页面其他内容渲染完毕,再执行js也未必OK,因为有可能js当中也有渲染页面的代码,这样会造成闪烁。 <script>内容放置的位置要看具体情况。
需要注意的defer延迟运行,对嵌入的脚步无效。同时,多个延迟脚本不一定能按顺序执行。建议这类脚本还是放在文档的最末尾比较保险。
defer和async都是针对外部脚本。 使用defer延迟运行,多个延迟脚本不一定能按顺序执行。设置为async异步脚本,不会阻塞页面内容。要保证与其他脚本没有依赖关系,因为他们不保证执行顺序。建议异步脚本不要在加载期间修改dom。
提到<script>就需要说明一下跨域问题。<script>和都可以跨域。
可以加载其他域的图片资源。<script>则可以调用外部的js。同时可以通过get方式传递参数。远程代码可以返回任意内容。
转载:跨域问题实际测过的方法:jsonp,iframe+document.domain,cors跨域资源共享。
基本概念
js区分大小写。首字符必须为字母、下划线、$。非首字符可用数字。
标识符驼峰写法,或者$开头,或者下划线分隔写法。
"use strict"
可写在函数体内。
关键字和保留字
关键字是控制语句的开始和结束,用来执行特定操作。关键字不能用作标识符。都是现在语句里用的。
break do while this function var newcontinue typeof instanceof return void
if else case switch with try catch finallythrow for delete debugger default
保留字是一些保留下来不能作为标识符的,将来有可能作为关键字。
比如class interface longchar public private……
第5版对于以上有些变化。但尽量编程时避免雷区。
变量
Js的变量是松散类型的。Js声明变量时,分配给标识符 存储区域,并将标识符和作用域进行绑定。
数据类型
Ecmascript有五种简单数据类型:
- Null
- Boolean
- String
- Number
- Undefined
一种复杂数据类型:
- Object
只声明未初始化和未声明过的变量都会显示undefined.
学过as和js,有时候会把变量声明的方式搞混。actionscript里有一种写法。A:array=new Array();在js里不适用。js就是弱类型。没必要用冒号加类型。如果这么写会报错。
var a;
// var b; 未声明b
console.log(a);//undefined
console.log(b);//报错
但是使用typeof
var a;
// var b; 未声明b
console.log(typeof a); //undefined
console.log(typeof b); //undefined 不会报错
因此,对于没有声明的变量,typeof是唯一可执行的操作。在写程序的时候,我们应该显式初始化变量,这样我们再使用typeof时,看到undefined时,就知道这个变量是未声明的。
var c=null;
console.log(c);//null
console.log(typeof c);//object
null值表示一个空对象指针。
如果定义的变量将来要保存对象,那么可以先给其null值。因此,看到null,我们就应该知道它是干嘛的。
另外:
console.log(null==undefined);//true
var car=null;
if(car!=null){
//执行某些操作
}//这样是可以的。
这里就存在一个问题。如何判断变量是null呢?
if(car==null){}//这样是不准确的,因为undefined也可以==null。
利用typeof也不行,因为会返回object。
if(car===null){}//这样写比较简单。
Number类型
不要测试某个特定的浮点数值,比如,0.1+0.2结果不是0.3。这是基于IEEE754数值浮点计算的通病。解决这个问题,通常是把浮点数转换成整数再计算。Es6中出现了一个新的常数,Number.EPSILON,而这个值等于2^-52。类似于取极限,(0.1+0.2)-0.3小于Number.EPSILON就可以认为0.1+0.2等于0.3。 关于Number()和parseInt()的区别。
var a="22asdfs";
console.log(parseInt(a));//22
console.log(Number(a));//NaN
var a="22.5";
console.log(parseInt(a));//22 int就是整形的意思,所以会忽略小数点。
console.log(Number(a));//22.5
var a="";//空字符,加空格也如此
console.log(parseInt(a));//NaN
console.log(Number(a));//0
var a="22e-6";
console.log(parseInt(a));//22
console.log(Number(a));//0.000022
var a="0x111";
console.log(parseInt(a));//273
console.log(Number(a));// 273
var a="AF";
console.log(parseInt(a,16));//175
console.log(Number(a));//NaN
Number()可以对任意类型做转换,而parseInt()则只能对字符串做转换。parseInt有第二个参数,做基数。Number()对boolean的false转为0,true转为1。Null转换为0,undefined转换为NaN。
parseFloat只识别十进制数,忽略前导0,十六进制数0x开头,只能识别为0。第二个小数点无效。无第二个参数。
String类型
-
字符字面量 记住一些常见的转义字符,使用反斜
\开头。\n,\t,\r,\b等。使用双字节字符length可能不会返回准确字符数目。 -
字符串特点 字符串一旦创建值就不能改变!一旦想改变某变量保存的字符串,需要先销毁原来的字符串,再使用另一个包含新值的字符串填充变量。也是因为这个特点,一些旧版浏览器拼接字符串效率低。
-
转换为字符串 把一个值转换为字符串有两种方法,一种使用toString()方法,另一种使用类型转换String()函数。 null和undefined没有toString属性。所以
var chr=null chr.toString()//报错但是,使用String()转型可以。其首先查看是否有toString()方法,有则调用。如果值是null则返回” null”,是undefined则返回”undefined”。
Object类型
每个Object对象都有以下属性和方法:
constructor,hasOwnProperty,toString,valueOf,isPrototypeOf,propertyIsEnumerable,toLocalString。 可以通过下面方法看到,所有对象都继承自Object的原型对象。
console.log(Object.getOwnPropertyNames(Object.prototype))
Objecet.keys和Object.getOwnPropertyName的区别:Object.keys列举对象自有可枚举属性。 Object.getOwnPropertyName列举对象的自有属性。
可以通过propertyIsEnumerable来检查属性是否可枚举
console.log(Object.prototype.propertyIsEnumerable("toString"));
//false
另外for in可以列举对象的所有可枚举属性。包括继承和非继承的属性。
操作符
一元操作符
一元加减运算符。非数字应用一元加减运算符,可以类型转换。
var chr="10";
console.log(+chr+2);//12
console.log(chr+2);//102
位操作符
有符号整数,正负转换一律反码加一。 比如用四位表示二进制有符号整数。
0000 表示0
0001表示1 1111表示-1
0010表示2 1110表示-2
0011表示3 1101表示-3
0100表示4 1100表示-4
0101表示5 1011表示-5
0110表示6 1010表示-6
0111表示7 1001表示-7
负值=取反(正值)+1 这个方法一般用作负数求补。利用按位非的特点。~~两个按位非可以对数字下取整。可以想象,这比Math.floor效率快。
计算机中的符号数有三种表示方法,即原码(转载)、反码(转载)和补码(转载)。数值一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统一处理。
-
按位非 就是按位取反。 符号~ 用上面的例子来讲就是负值减一 取反(正值)=负值-1
-
按位与 很方便的判断奇偶,奇数&1=1,偶数&0=0。
If(数字&1){ //奇数 }else{ //偶数 } -
按位或
也可以用来取整,数字|0 ,包括不过~~感觉看起来更舒服。
关于位操作,可以结合计算机组成原理第二章运算方法和运算器来看。
- 按位异或可以用来判断乘法符号位。相同情况0,不同为1。符号求补阵列加法器。
按位异或还可以做数值交换。这种情况很少见,可以不用额外声明变量。
a^=b;
b^=a;
a^=b;
对2求补可用按位扫描技术来执行所需求补操作。从右向左找到第一个“1”,从这位到右保持不变,这位左侧的数字全部求反就OK。
直接补码阵列乘法器,符号位参与运算,所以省去对2求补和补位运算,提高效率。了解即可。
对于位操作符有更深刻直观的认识。一些运算(例如取整)使用位操作符能大大提高效率。
位运算符的妙用:转载:https://www.cnblogs.com/happy1992/p/7064114.html
布尔操作符
逻辑非,!!两次相当于类型转换Boolean(),返回所求内容对应的布尔值。
逻辑与 && 短路操作符。如果左侧能够决定结果,则不会继续对右侧求值。 基于这种原理,往往在使用上来做递进的判断。比如先判断是否有对象Car,如果有,判断这个对象下面是否有属性a,如果有,对属性a赋值。确定具备某一条件(左侧),则返回(右侧)
var me=null;
//程序某一处me={high:185,skin:"black"};
var b=me&&me.high;
console.log(b);
逻辑或 || 也是操作符。当左侧为true,返回左侧,不对右侧求值。当左侧为false则返回右侧值。经常用在给变量赋值的情况,如果没有初始化的值则返回右侧的默认值。(左侧)不符合条件,则返回(右侧)。
var me={skin:"black"};
//程序某一处me.high=180;
var b=me.high||185;
console.log(b);
乘性操作符
乘法中操作符几个特殊的结果:
Infinity*0为NaN。 //别忘了NaN!=NaN NaN与任何数都为NaN, Infinity与非0数还是(+-)Infinity。
除法中几个特殊结果:
NaN与任何数都为NaN Infinity除Infinity和0除0都为 NaN
求模中几个特殊结果:
被除数是0结果为0 被除数是有限数,除数是无限大,结果是被除数 其他凡是你认为没结果的都是NaN
加性操作符
加法当有字符串为操作数时,对于其他数据类型用toString()方法,null和undefined这两种使用String();
可用()来影响操作顺序和转换类型。
减法规则:存在除number以外简单数据类型时,先调用Number()。如果存在Object类型,先通过valueOf()转换。如果不存在则先toString()再Number()转为数字。Null直接用Number()转为0,undefined为NaN。
总结为在操作数分别为字符串和数字时,加法当字符串拼接,减法当数字相减。
关系操作符
对于null和undefined的存在,书上没有具体阐述。但是,关系操作符比较偏爱转数字,加号操作符偏爱转字符串。针对和数字的比较有:
var a=undefined;
console.log(a<1);//false ,如果转换了类型,则按照规则,undefined转为数字NaN
console.log(a>1);//false
var a=null;
console.log(a<1);//true根据规则null转成0.
console.log(a>1);//false
console.log(a<"a");//false 即便有字符串,也是转数字的,
//a变成NaN,因此始终是false
console.log(a>"a");//false
相等操作符
==操作符可能需要类型转换,null和undefined则不转换。
===不进行转换即相等才返回true。
条件操作符
也叫三目(元)运算符。在ecmascript中最灵活的一种,大神的代码中特别常见。特别类似于if…else…
条件?表达式1 :表达式2
三目运算符是可以嵌套使用的。比如:
条件1?表达式1:条件2?表达式2:条件3?表达式3:表达式4
可以将立即执行函数表达式放入三目运算符。因为这样可以封闭作用域,传参,返回值。结合赋值语句使用很强大。
在vue里很有用。
不过在后面研究label和break的时候,发现三目运算符不能带break和continue一起用,会报错。
语句
with语句
将代码的作用与设置到一个特定的对象中。在with代码块内部,每个变量首先被认为是局部变量,如果局部环境找不到变量的定义,就会查找特定对象作用域是否有同名属性。如果有,则以特定对象中属性值作为变量的值。 with严格模式会报错
函数
关于函数表达式,函数声明,匿名函数的分析,(function(){})();
何为立即执行函数Immediately-InvokedFunction Expression (IIFE)
转载:https://www.cnblogs.com/zichi/p/4401755.html
转载:https://blog.csdn.net/linshichen/article/details/78328125
这部分可以结合红皮书第四章变量、作用域和内存问题理解
Js堆栈、浅拷贝、深拷贝、基本类型、引用类型:
转载:https://www.cnblogs.com/chengguanhui/p/4737413.html