js笔记—— 基础部分一

来源:互联网 发布:oppor9root软件 编辑:程序博客网 时间:2024/06/14 00:04

前言: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值就可以判断变量是否保存了对象的引用.

  如:

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

Boolean类型

任何其他类型都有与Boolean等价的值
Boolean(""); //false,   非空字符串返回trueBoolean(0);//0和NaN 返回 false ,   非零(包括无穷大)返回trueBoolean(null);//返回falseBoolean(undefined);//false

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

Number类型

var num1 = 55;  //十进制var num2 = 070; //八进制  0开头   56var 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();//判断是否 "不是数值"
alert(isNaN(NaN));  // truealert(isNaN(10));  //falsealert(isNaN("10"));  //false,可转换成数值 alert(isNaN("blue"));  //true,不可转成数值 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 精准的迭代语句,可以用来枚举对象的属性

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

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

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

var num =0;outer:      for(var i=0;i<10;i++){           for(var j=0;j<10;j++){                if(i == 5 && j==5){                      continue   outer;                }                num++;           }      }alert(num);    //95

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

5. switch语句

var num = 15;switch (true){  //输出  Between 10 and 20,如果是false就输出  Less than 0case num<0:alert("Less than 0");break;case num>=0&&num<=1:alert("Between 0 and 1");break;case num>10&&num<=20:alert("Between 10 and 20");break;default:alert("More than 20");}

6.函数

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

5.变量,作用域,内存

5.1  基本类型和引用类型

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

变量复制:  基本类型

var num1 = 5;var num2 = num1;// num1和num2是两个独立的值,在进行任何操作时不会相互影响。
引用类型:

var obj1  = new Object();var obj2 = obj1;obj1.name = "张三";alert(obj2.name);  // 张三  //obj1和obj2指向的是堆内存中的同一个对象

参数传递:

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

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

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

通常用typeof来检测基本类型

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

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

5.2 执行环境及作用域

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

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

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

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

作用域链(scope chain)。保证对执行环境有权访问的所有变量和函数的有序访问
 
var color = "blue";function changeColor(){      var anotherColor = "red";      function swapColors(){               var  temColor = color;               color = anotherColor;               anotherColor = temColor;      }}
上面代码作用域链,如图:三个作用域,内部环境可以通过作用域链访问所有的外部环境
延长作用域链:

1.try-catch 中的catch块

2.with语句

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

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

5.3 垃圾收集

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

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

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

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

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

引用计数

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

function createPerson(name){var localPerson  = new Object(); //localPerson局部变量,不用手工解除localPerson.name = name;return localPerson;}var globalPerson = createPerson();//手动解除globalPerson的引用globalPerson = null;

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

小结:

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

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

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