分享

js笔记

 司马小贼 2018-02-28

前言:js由三部分组成,1. 核心(ECMAScript),语法标准    2.文档对象模型(DOM)    3.浏览器对象模型(BOM)

JavaScript 的核心语言特性在ECMA-262中是以名为ECMAScript的伪语言的形式来定义的。ECMAScript中包含了所有基本的语法,操作符,数据类型以及完成基本的计算任务所必需的对象,但没有对取得输入和产生输出的机制作出规定。

1.在web中引入js

<script></script>    使html与js混合

defer  :  延迟到页面全部解析完后再加载js

type : mime类型, 默认"text/javascript"。可省略

引入外部js:

<script src=""></script> 可引入不用域的js,引入外部js时同时在标签内嵌入js代码会被忽略。

 注意:不要在js中出现 </script> ,会造成浏览器错误解析(以为js已经结束)。

 小tips:浏览器按照<script>标签先后顺序解析,如果将js代码放head里,浏览器会先解析js,然后呈现body中的页面元素(页面延迟,呈现空白)

2.数据类型

ECMAScript 中规定的5种基本数据类型:  Undefined,Null,Boolean,Number,String

      1种复杂数据类型:  Object   由一组无序的键值对组成

typeof操作符: 用于返回检测的变脸类型   :  undefined,object,boolean,number,string,function

typeof(null); //返回"object"  空对象指针(对空对象的引用)

Undefined类型

只有一个值  undefined,变量声明后未初始化,值就是undefined。(未声明和声明后未定义值都是undefined)
var name;
alert(name);//"undefined"
alert(age);//"undefined"

Null类型

同样只有一个值  null。
var name = null;
alert(typeof  name);//"object" 对空指针的引用
小tips:在定义一个变量用来保存对象时,初始化时最后给null,这样就只需要检查null值就可以判断变量是否保存了对象的引用.

  如:

  1. var person = null;  
  2. if(person!=null){  
  3.   
  4. }  
alert(null == undefined); //true,  undefined值是派生自null值的

Boolean类型

任何其他类型都有与Boolean等价的值
[javascript] view plain copy
print?
  1. Boolean(""); //false,   非空字符串返回true  
  2. Boolean(0);//0和NaN 返回 false ,   非零(包括无穷大)返回true  
  3. Boolean(null);//返回false  
  4. Boolean(undefined);//false  

使用if语句进行流程控制时,会自动调换用Boolean()函数进行转换

Number类型

[javascript] view plain copy
print?
  1. var num1 = 55;  //十进制  
  2. var num2 = 070; //八进制  0开头   56  
  3. var num3 = 0x1f; // 十六进制  0x开头   31  
  1. 浮点数值
由于保存浮点数值需要的存储空间是整数值的两倍,所以ECMAScript会尽可能将浮点数转成整数。
var floatNum1 = 10.0; //保存的是整数10
注意:0.1+0.2 !=0.3 浮点数精度问题(永远不要测试某个特定的浮点数值)
2. 数值范围
Number.MAX_VALUE,Number.MIN_VALUE,Number.NEGATIVE_INFINITY,Number.POSTIVE_INFINITY
Infinity正无穷, -Infinity负无穷。
isFinite()函数来判断是否在这个范围内,超出范围的数值会被自动转成相应的无穷大值
3. NaN(Not a Number)非数值
任何数值除以0返回NaN,不会抛错(不会影响后面代码的执行)
注意:任何涉及NaN的操作都会返回NaN。NaN与任何值都不相等(包括NaN)
alert(NaN == NaN); //false
isNaN();//判断是否 "不是数值"
[javascript] view plain copy
print?
  1. alert(isNaN(NaN));  // true  
  2. alert(isNaN(10));  //false  
  3. alert(isNaN("10"));  //false,可转换成数值   
  4. alert(isNaN("blue"));  //true,不可转成数值   
  5. alert(isNaN(true));    //false 可转成数值   
4. 数值转换函数 Number() ,parseInt()和parseFloat()
Number(null); // 0
Number(undefined); //NaN
Number("hehe"); //NaN
Number(""); //0

parseInt("0xAF",16); //175
parseInt("AF"); //NaN 需指定进制
parseInt("10",2); // 2 (二进制)

String 类型

由零或多个 16位 Unicode字符组成的字符序列
注意:字符串一旦创建,值就不能改变。如果改变,是先销毁原来的字符串,然后用新字符串来填充该变量
字符串转换:
toString();几乎每个值都有该方法
toString(2); //可指定数值的转换进制
null和undefined没有 toString()函数
可以使用String()函数来转换:String(null); // "null"
String(undefined); //"undefined"

Object类型 (所有对象的基础)

Obejct属性和方法
Constructor:构造函数(用于创建当前对象的函数)
hasOwnProperty(propertyName):检索当前对象实例中的属性(不是实例原型)是否存在,参数必须是字符串
isPrototypeOf(object):传入的对象是否是另一个对象的原型
propertyIsEnumerable(propertyName):属性是否能用for-in 遍历
toLocalString():返回对象的字符串表示
toString():
valueOf():返回对象的字符串,数值或布尔值表示。通常与toString()返回相同

3.操作符

1.位操作符

32二进制表示整数,第32位为符号位
~ 按位非(NOT)
& 按位与(AND)
| 按位或(OR)
^ 按位异或(XOR)
<< 左移,不影响符号位
>> 有符号右移,保留符号位,不影响正负
<<< 无符号右移,连着符号位一起右移

2.关系操作符

4.语句

1.for-in 精准的迭代语句,可以用来枚举对象的属性

[javascript] view plain copy
print?
  1. for(var propName  in window){  
  2.       document.write(propName);  
  3. }  
输出BOM中 window对象的所有属性
迭代前最好先检测对象是否为null或undefined。(ECMAScript5中不执行循环体,以前会报错)

2.label语句,给代码添加标签

3.break和continue语句(break跳出循环,直接执行循环后的代码。continue跳出当前循环,接着进入下一次循环)

[javascript] view plain copy
print?
  1. var num =0;  
  2. outer:  
  3.       for(var i=0;i<10;i++){  
  4.            for(var j=0;j<10;j++){  
  5.                 if(i == 5 && j==5){  
  6.                       continue   outer;  
  7.                 }  
  8.                 num++;  
  9.            }  
  10.       }  
  11. alert(num);    //95  

4.  with语句(不建议使用,可读性差)

5. switch语句

[javascript] view plain copy
print?
  1. var num = 15;  
  2. switch (true){  //输出  Between 10 and 20,如果是false就输出  Less than 0  
  3.     case num<0:  
  4.     alert("Less than 0");  
  5.     break;  
  6.     case num>=0&&num<=1:  
  7.     alert("Between 0 and 1");  
  8.     break;  
  9.     case num>10&&num<=20:  
  10.     alert("Between 10 and 20");  
  11.     break;  
  12.     default:  
  13.         alert("More than 20");  
  14. }  

6.函数

function关键字来定义函数,
注意:函数无所谓传进来多少个参数。因为在内部是用一个数组来表示的,在函数体内可以通过arguments来访问这个数组。
arguments对象只是与数组类似(并不是array的实例)
[javascript] view plain copy
print?
  1. function doAdd(num1,num2){  
  2.       arguments[1] = 10;    //会同步影响 num2的值,这种影响是单向的,反过来修改num2并不会影响arguments中的值  
  3.       alert(arguments[0]+num2);  
  4. }  
注意:arguments对象长度由传入的参数个数决定,不由定义函数时声明的参数个数决定,没有传值的参数自动赋值undefined

5.变量,作用域,内存

5.1  基本类型和引用类型

基本类型值指的是简单的数据段,而引用类型值指那些可能由多个值构成的对象。
基本类型是按值访问,所以可以操作保存在变量中的实际的值。
引用类型的值是保存在内存中的对象,js不允许直接 访问内存中的位置(不能直接操作对象的内存空间),实际操作的是对象的引用。
[javascript] view plain copy
print?
  1. var person = new Object();  
  2. person.name = "张三";  //给引用类型变量动态添加属性并赋值  
  3. alert(person.name);//  张三  
  4. //无法给基本类型变量添加属性,不报错但是无效。  

变量复制:  基本类型

[javascript] view plain copy
print?
  1. var num1 = 5;  
  2. var num2 = num1;// num1和num2是两个独立的值,在进行任何操作时不会相互影响。  
引用类型:

[javascript] view plain copy
print?
  1. var obj1  = new Object();  
  2. var obj2 = obj1;  
  3. obj1.name = "张三";  
  4. alert(obj2.name);  // 张三    
  5. //obj1和obj2指向的是堆内存中的同一个对象  

参数传递:

ECMAScript中所有函数的参数都是按值传递的。在传递基本类型值是,被传递的值会赋给一个局部变量(命名参数,arguments对象中的一个元素)

注意:传递引用类型时,会把这个值在内存中的地址赋值给一个局部变量(对堆内存中对象的引用),所以指向的还是同一个内存空间,因此对参数的修改会影响到函数外。

[javascript] view plain copy
print?
  1. function setName(obj){  
  2.      obj.name = "张三";//obj引用指向堆中的person对象,person.name = "张三"  
  3.      obj = new Object();//给obj(参数,局部变量)  指向新的对象(该对象在setName函数中创建,是局部的,函数结束,对象销毁)  
  4.      obj.name = "李四";//给obj引用的局部变量动态添加name属性赋值为"李四"  
  5. }  
  6. var person = new Object();  
  7. setName(person);  
  8. alert(person.name); //张三  
类型检测:

通常用typeof来检测基本类型

instanceof来检测引用类型,根据它的原型链来识别。

所有引用类型都是Object的实例,用instanceof检测所有基本数据类型,都会返回false。基本类型 不是对象。

5.2 执行环境及作用域

说明:执行环境定义了变量或函数有权访问的其他数据,决定了他们各自的行为。每个执行环境都有一个与之关联的变量对象(variable object),环境中定义的所有变量和函数都保存在这个对象中。虽然我们编写的代码无法访问这个对象,但解析器在处理数据是会在后台使用它。

全局执行环境是最外围的一个执行环境。在web浏览器中,全局执行环境就是window对象,因此所有全局变量和函数都是作为window对象的属性和方法

创建的。某个执行环境中的所有代码执行完后,保存在其中的变量和函数定义也随之销毁。

每个函数都有自己的执行环境。当执行流进入一个函数时,函数环境会被推入环境栈。执行完后弹出栈,控制权交给之前的执行环境

作用域链(scope chain)。保证对执行环境有权访问的所有变量和函数的有序访问
 
[javascript] view plain copy
print?
  1. var color = "blue";  
  2. function changeColor(){  
  3.       var anotherColor = "red";  
  4.       function swapColors(){  
  5.                var  temColor = color;  
  6.                color = anotherColor;  
  7.                anotherColor = temColor;  
  8.       }  
  9. }  
上面代码作用域链,如图:三个作用域,内部环境可以通过作用域链访问所有的外部环境
延长作用域链:

1.try-catch 中的catch块

2.with语句

[javascript] view plain copy
print?
  1. function buildUrl(){  
  2.     var qs = "?debug=true";  
  3.     with(location){  
  4.         var url = href + qs;  //location.href,url添加到最近的环境(buildUrl函数中)  
  5.     }  
  6.     return url;   
  7. }  
with语句接收的是location对象,因此其变量对象中就包含了location对象的所有属性和方法,而这个变量对象被添加到了作用域链的前端,所以在函数内部可以访问。

没有块级作用域:
js没有块级作用域,不像java等语言,if(){},for(){}语句中定义的都是局部变量
[javascript] view plain copy
print?
  1. for(var i=0;i<10;i++){  
  2.      doSomething(i);  
  3. }  
  4. alert(i);   // 10     
js中会将if,for中声明的变量添加到当前的执行环境中
变量声明:
使用var声明的变量会自动被添加到最接近的环境中。在函数内部,最接近的就是当前函数的局部环境;在with语句中,最接近的环境是函数环境。如果初始化变量时没有var声明,则自动添加到全局环境。
[javascript] view plain copy
print?
  1. function(num1,num2){  
  2.         sum = num1+num2; //sum未声明,添加到全局环境  
  3.         return sum;  
  4. }  
  5. var result = add(10,20); //30  
  6. alert(sum);    //30,可访问到  
查询标识符:同名变量,从最近环境开始搜索,优先取最近环境中的值然后停止搜索。

5.3 垃圾收集

说明:JavaScript具有自动垃圾收集机制,执行环境会负责管理代码执行过程中使用的内存

局部变量只在函数执行的过程中存在。在这个过程中,会为局部变量在栈(或堆)内存上分配相应的空间,以便存储它们的值。在函数执行结束,局部变量就没有存在的必要,因此可以释放它们的内存。

标记清除
JavaScript中最常用的垃圾收集方式是标记清除(mark-and-sweep)。当变量进入环境时(如:在函数中声明一个变量),就将这个变量标记为"进入环境",当变量离开环境时,则将其标记为"离开环境"。

垃圾收集器在运行的时候会给存储在内存中的所有变量加上标记,然后会去除环境中的变量以及被环境中的变量引用的变量的标记。

在此之后再被加上标记的变量将被视为准备删除的变量(环境中变量已经无法访问这些变量了)。最后,垃圾收集器完成内存清除工作,销毁带标记的值并回收内存空间。

引用计数

说明:引用技术会跟踪每个值被引用的次数。当声明了一个变量并将一个引用类型值赋给该变量,则这个值的引用次数就是1。如果该值又被赋给另外一个变量,则该值的引用次数加1。相反,如果对这个值引用的变量取得了另外一个值,则这个值的引用次数减一。当这个值的引用次数变成0的时候,就说明没法再访问这个值了,就可以将其占用的内存回收。当垃圾收集器下次再运行的时候就会释放这些空间。
问题:对象之间循环引用会造成内存无法回收
[javascript] view plain copy
print?
  1. function problem(){  
  2.     var objectA = new Object();  
  3.     var objectB = new Object();  
  4.     objectA.someOtherObject = objectB;  
  5.     objectB.anotherObject = objectA;  
  6. }  
A,B对象通过各自的属性相互引用。它们之间的引用次数永远不会是0。如果这个函数被重复多次调用,就会导致大量内存无法回收。
问题:IE中有一部分并不是原生JS对象,BOM和DOM中的对象就是使用C++以COM(Component  Object  Model,组件对象模型)对象的形式实现的,而COM对象的垃圾收集机制采用的就是引用计数策略。所以,即使IE的JS引擎是使用标记清除策略,但JS访问的COM对象依然是基于引用计数策略的。这就照成只要在IE中涉及COM对象就会存在内存引用的问题。
[javascript] view plain copy
print?
  1. var element = document.getElementById("some_element");  
  2. var myObject = new Object();  
  3. myObject.element = element;  
  4. element.somObject = myObject;//DOM元素和JS对象相互引用,循环引用照成即使DOM从页面中移除,它也不会被回收。  

可以通过赋值为null来手动断开这两个元素间的引用。如:
myObject.element =null;
element.somObject = null;
IE9中把BOM和DOM对象都转成了JS对象,也可以避免两种垃圾回收算法并存的问题(消除常见的内存泄漏现象)。

性能问题

说明:垃圾收集器是周期性运行的,原IE7策略问题:根据内存分配量运行,达到256个变量,4096个对象(或数组)或者64KB其中任一标准,垃圾收集器就会运行,这就导致如果一个脚本中包含这么多变量,那么这个脚本在器生命周期中很可能会一直保有这么多变量。这样一来,垃圾收集器就会频繁运行,导致性能急剧下降。

解决方法:如果回收的内存分配量低于15%,则临界值加倍。如果到了回收85%的内存分配量,就将临界值重置回默认值。这样循环往复,看似简单,实则极大提升了IE在运行包含大量JS的页面时的性能。

5.4 内存管理

说明:出于安全考虑,浏览器的可用内存数量比较少(防止运行JS的网页耗尽全部系统内存而导致系统崩溃)。内存限制不仅影响给变量分配内存,同时还会影响调用栈以及在一个线程中能够同时执行的语句数量。

tips:一旦数据不再有用,最好通过将其值设置为null来释放其引用(解除引用dereferencing)。该做法适用大多数全局变量和全局对象属性。局部变量会在它们离开执行环境时自动被解除引用

[javascript] view plain copy
print?
  1. function createPerson(name){  
  2.     var localPerson  = new Object(); //localPerson局部变量,不用手工解除  
  3.     localPerson.name = name;  
  4.     return localPerson;  
  5. }  
  6. var globalPerson = createPerson();  
  7. //手动解除globalPerson的引用  
  8. globalPerson = null;  

解除globalPerson的引用,让值脱离执行环境,以便垃圾收集器下次运行时将其回收

小结:

  • 基本类型值在内存中占据固定大小的空间,被保存在栈内存中
  • 从一个变量向另一个变量复制基本类型的值,会创建这个值的一个副本
  • 引用类型的值是对象,保存在堆内存中
  • 包含引用类型值的变量实际上包含的并不是对象本身,而是一个指向该对象的指针
  • 从一个变量向另一个变量复制引用类型的值,复制的其实是指针,因此两个变量最终都指向同一个对象
  • 确定一个值是哪种基本类型使用typeof(),确定值是哪种引用类型使用instanceof()

所有变量都存在于一个执行环境(作用域)中,这个执行环境决定了变量的生命周期,以及哪一部分代码可以访问其中的变量。

  • 执行环境有全局执行环境和函数执行环境之分;
  • 每次进入一个新执行环境,都会创建一个用于搜索变量和函数的作用域链;
  • 函数的局部环境不仅有权访问函数作用域中的变量,而且有权访问其父环境,乃至全句环境中的变量;
  • 全局环境只能访问在全局环境中定义的变量和函数,而不能直接访问局部环境中的任何数据;
  • 变量的执行环境有助于确定应该何时释放内存
JavaScript是自动进行垃圾回收的,开发人员不必关心内存分配和回收问题。
  • 离开作用域的值将被自动标记为可以回收,因此将在垃圾收集期间被删除。
  • "标记清除"是目前主流的垃圾收集算法,思想就是给当前不使用的值加上标记,然后再回收其内存
  • "引用计数"的思想是跟踪记录所有值被引用的次数,JS引擎目前都不使用这种算法
  • 在代码中循环引用时,"引用计数"算法会出现问题(内存泄漏)
  • 解除变量引用不仅有助于消除循环引用现象,而且对垃圾收集也有好处。为了确保有效地回收内存,应该及时解除不再使用的全局对象,全局对象属性及循环引用变量的引用。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多