JavaScript 是一种面向对象的动态语言,它包含类型、运算符、标准内置( built-in)对象和方法。它的语法来源于 Java 和 C,所以这两种语言的许多语法特性同样适用于 JavaScript。需要注意的一个主要区别是 JavaScript 不支持类,类这一概念在 JavaScript 通过对象原型(object prototype)得到延续(有关 ES6 类的内容参考这里
Classes
)。另一个主要区别是 JavaScript 中的函数也是对象,JavaScript 允许函数在包含可执行代码的同时,能像其他对象一样被传递。
一 、number详解
Javascript中采用全浮点计算(双精读64位)
注意 !在某些运算中会出错 eg:0.1 + 0.2 = 0.30000000000000004
我们也可以使用JavaScript提供的Math内置对象,和 内置函数parseInt();
此外JavaScript还提供了parseFloat(),但是它只支持解析十进制数字
在parseInto("123",10) //123 -->10的含义是十进制
如何把二进制转为整数值?
parseInt("10011",2);
当第一个参数不是数字型字符串
parseInt("hello", 10); // NaNNaN是一个特殊值 用它与任何数字计算 结果都是NaN
此外 还有两个特殊值 Infinity 和 -Infinity (正无穷和负无穷)
用内置函数 isFinite()可以判断一个变量是否为Infinity -Infinity NaN
二、字符串
JavaScript中的字符串是一个Unicode字符序列
每一个编码单元由一个 16 位二进制数表示。每一个Unicode字符由一个或两个编码单元来表示。
三、其他类型(null 和 undefined)
null的本质是一个空值,必须使用null关键字才能访问
undefined是一个未定义类型的对象(也是一个对象),它表示一个未初始化的值,也就是还没有被分配值。(JavaScript允许声明变量但不对其赋值,一个未被赋值的变量就是undefined类型)
布尔型:(true / false)其他类型对其转化
flase,0,"",NaN,null,undefined都会在JavaScript需要一个布尔值变量的时候隐式转换为false (其他的都会转化为true)
四、变量
在JavaScript中声明一个变量用var
var a;
var name = "simon";
在JavaScript中的语句块中 是没有作用域的
五、运算符
JavaScript的算术操作符包括
+
、-
、*
、/
和% ——
求余(与模运算不同)。赋值使用=
运算符,此外还有一些复合运算符,如+=
和-=
,它们等价于x = x op y
。+可以用来连接字符串
六、控制结构
- if()...else if()...else()
- while()
- do...while()
- for( ; ; )/for( : )
- 短路与:var name = o && o.getName();
- 短路或:var name = otherName || "default";
- 三元运算符:var allowed = (age > 18) ? "yes" : "no";
- 多重分支时可以使用
基于一个数字或字符串的switch
语句:(在switch
的表达式和case
的表达式是使用===
严格相等运算符进行比较的:)
七、对象
对象的创建方式:
1.var obj = new Object();
2.var obj = {} --->对象字面量
- 可以用链式访问:
obj.details.color; //orange
- 可以用中括号访问:
obj[detail][color];对象原型:(像是Java中的一个类)function Person(name,age){this.name = name;this.age = age;}创建一个Person的对象:var You = new Person("zhangjiahao","23");可用You.name="ZJH"来赋值
可用var name = You.name;来取值
obj["name"] = "Simon";
var name = obj["name"];
中括号的方式的优点:中括号内都是字符串,所以可以用于运行时计算,且可以使用关键字,但在后期被解释时无法优化。
obj.for = "Simon"; // 语法错误,因为 for 是一个预留关键字
obj["for"] = "Simon"; // 工作正常
八、数组
JavaScript中的数组是一个特殊的对象。
与普通对象的区别在于,对于数组中的‘属性’(元素)只能通过中括号来访问。同时数组比普通对象多了一个length属性,该属性值始终比最大索引大一(并非等于数组中的元素个数)
数组的创建:
var a = ['dog','cat','hen']; //数组字面量
var b = new Array('dog','cat','hen'); //传统方式
如果访问了一个不存在的数组索引 会得到undefined
数组的遍历:
for(var i=0;i<a.length;i++) //传统方法--->不推荐,每次循环都会计算length,效率不高
for(var i=0,len = a.length;i<len;i++ ) //改进方法--->先循环开始前,先缓存a.length
for(var i=0,item;item=a[i++]) //有局限,每次循环都会判断item是否空值或是否定义(是否为真)但是在数组内容中出现假值 会影响循环
for(var i in a) //这种循环 不单单会遍历出元素 ,也会遍历出自定义添加的array属性(向
Array.prototype
添加了新的属性)ECMAScript 5 中添加了forEach()方法(IE暂不支持)
还有a.push(item)方法用于在数组后面添加元素a.push(item);
方法名称 描述 a.toString()
返回一个包含数组中所有元素的字符串,每个元素通过逗号分隔。 a.toLocaleString()
根据宿主环境的区域设置,返回一个包含数组中所有元素的字符串,每个元素通过逗号分隔。 a.concat(item1[, item2[, ...[, itemN]]])
返回一个数组,这个数组包含原先 a
和item1、item2、……、itemN
中的所有元素。a.join(sep)
返回一个包含数组中所有元素的字符串,每个元素通过指定的 sep
分隔。a.pop()
删除并返回数组中的最后一个元素。 a.push(item1, ..., itemN)
将 item1、item2、……、itemN
追加至数组a
。a.reverse()
数组逆序(会更改原数组 a
)。a.shift()
删除并返回数组中第一个元素。 a.slice(start, end)
返回子数组,以 a[start]
开头,以a[end]
前一个元素结尾。a.sort([cmpfn])
依据 cmpfn
返回的结果进行排序,如果未指定比较函数则按字符顺序比较(即使元素是数字)。a.splice(start, delcount[, item1[, ...[, itemN]]])
从 start
开始,删除delcount
个元素,然后插入所有的item
。a.unshift([item])
将 item
插入数组头部,返回数组新长度(考虑undefined
)。九、函数
对JavaScript的学习最重要的就是对象和函数两个部分。(函数也是对象)
函数:
一个JavaScript函数可以有0个或者多个变量,如果有return,个返回return的值;否则返回undefined。在使用函数时,函数中的变量也不一定强制与定义函数时的变量一致,如: add ( ) ;此时x,y为undefined;若add(1,2,3)此时3将会被忽略。JavaScript 允许你创建匿名函数:
闭包:递归:
闭包递归:如上所提供的函数表达式的名称的作用域仅仅是该函数自身。这允许引擎去做更多的优化,并且这种实现更可读、友好。该名称也显示在调试器和一些堆栈跟踪中,节省了调试时的时间。
ps:需要注意的是 JavaScript 函数是它们本身的对象——就和 JavaScript 其他一切一样——你可以给它们添加属性或者更改它们的属性,这与前面的对象部分一样。
十、自定义对象
首先我们了解一些面向对象的基本概念和知识。JavaScript命名空间:注意:需要认识到重要的一点是:与其他面向对象编程语言不同的是,Javascript中的普通对象和命名空间在语言层面上没有区别。这点可能会让JavaScript初学者感到迷惑。下面是用于创建命名空间和添加变量,函数和方法的代码写法:
自定义对象类JavaScript是一种基于原型的语言,它并没有类似于其他C++/JAVA中的类声明语言。在JavaScript中,我们通常使用方法(function)来当做类。定义一个类跟定义一个函数一样easy
对象(类的实例)我们使用 new obj()来创建一个新的实例。eg:
构造器在实例化时构造器被调用,在JavaScript中,初始的函数就可以作为构造器使用,而不需要额外的定义构造器方法。类中的每个声明的函数都可以在被实例化后调用执行。(构造器常用于给对象的属性赋初始值)
属性(对象属性)属性就是当前类中的变量。通常为了正确继承,属性应当为定义在原型属性中。可以使用关键字this来调用类中的属性,this是对当前对象的引用。方法(对象属性)方法和属性相似,不同的是:一个是函数,另一个是可以被定义为函数。为定义一个方法,通常需要将一个函数赋值给类的原型属性,这个赋值给函数的名称就是用来给对象在外部调用它使用的。在JavaScript中方法通常是绑定到一个对象中的普通函数,所以我们也可以在访问域之外对其调用访问。
继承创建一个或者多个类的某专门版本类方式称为继承( JavaScript只支持单继承)。 创建的专门版本的类通常称作子类。在JavaScript中通过赋予子类一个父类的实例并专门化子类来实现。封装
在上一个例子中,Student类虽然不需要知道Person类的walk()方法是如何实现的,但是仍然可以使用这个方法;Student类不需要明确地定义这个方法,除非我们想改变它。 这就叫做封装,对于所有继承自父类的方法,只需要在子类中定义那些你想改变的即可。
抽象
抽象是允许模拟工作问题中通用部分的一种机制。这可以通过继承或者组合来实现。JavaScript通过继承来实现具体化,通过让类的实例是其他对象的属性值来实现组合。
多态
就像所有定义在原型属性内部的方法和属性一样,不同的类可以定义具有相同名称的方法;方法是作用于所在的类中。并且这仅在两个类不是父子关系时成立(继承链中,一个类不是继承自其他类)。
---------------------------------------------------------------------------------总结:
在经典面向对象中,对象指的是数据以及操作数据的集合。与C++ 和 Java 不同,JavaScript是一种基于原型的编程语言,没有Class语句,而是把函数作为类。
eg:(a)显然上述方法十分麻烦,需要在全局命名空间中写很多的函数。既然函数本身就是对象,如果需要让一个函数属于一个对象,那么不难得到:(b)注意:this关键字, 当使用在函数中时,this指的是当前的对象,也就是调用该函数的对象。如果一个对象使用了.或者{}来访问其下的属性时,那么该对象就成了this。如果并不存在某个对象,那么此时this指向全局对象。所以我们可以用this来改进上述makePerson函数:但此时创建一个Person对象的时候,我们都在其中创建了两个新的函数对象。所以我们可以将里面的函数拿出来:最好的方式:Person.porotype 是一个可以被Person的所有实例共享的对象。他的名字叫做原型链(prototype chain)的查询链的一部分:当你试图访问一个Person中没有定义的属性时,解释器会先检查这个Person.porotype来判断是否存在这样一个属性。所以,在任何时候任何分配给Person.porotype的东西通过this对象构造的实例都是有用的。这也使得我们可以在任何时候改造原型中的一些东西,甚至是内置对象的原型。 给String
添加一个方法用来返回逆序的字符串:原型组成链的一部分,那条链的根节点是Object.pototype,它包括toString()方法 --> 将对象转换成字符串调用的方法。这对于调用我们的Person对象很有用。ps:apply()和call()
内部函数
JavaScript 允许在一个函数内部定义函数,如果某个函数依赖于其他的一两个函数,而这一两个函数对其余的代码没有用处,可以将它们嵌套在会被调用的那个函数内部,这样做可以减少全局作用域下的函数的数量,这有利于编写易于维护的代码。
闭包闭包是JavaScript中必须提到的功能。首先我们来看一个内部函数应用的例子:我们来观察一下,在上述代码运行过程中发生了什么:每当JavaScript执行一个函数时,都会创建一个作用域对象(Scopeobject),用来保存 在这个函数中创建的局部变量。它和被传入函数的变量一起被初始化。这与那些保存的所有全局变量和函数的全局对象类似,但有一些区别:1.每次函数被执行时都会创建一个新的,特定的作用域对象;2.与全局对象(在浏览器中当做window对象来访问的)不同的是,不能从JavaScript代码中直接访问作用域对象,也没有可以遍历当前的作用域对象里面属性的方法。
过程:当调用makeAdder时,解释器创建了一个作用域对象,它带有一个属性a(它被当做参数传入makeAdder函数中,然后makeAdder返回一个新创建的函数)。通常JavaScript的垃圾回收器会在这时候回收makeAdder创建的作用域对象,但是返回的函数却保留了一个指向那个作用域对象的引用。结果是这个作用域对象并不会被垃圾回收器回收。直到指向makeAdder 的那个函数对象的引用计数为零。
作用域对象组成了一个名为作用域链(scope chain)的链.它类似于原形(prototype)链一般,被JavaScript的对象系统使用。
那么 : 一个闭包就是一个函数 和 在这个函数中被创建函数的作用域对象的组合。
闭包允许你保存状态--所以他们通常可以替代对象来使用。
内存泄漏使用闭包的一个缺点就是容易造成浏览器内存泄漏。JavaScript 是一种具有垃圾回收机制的语言——对象在被创建的时候分配内存,然后当指向这个对象的引用计数为零时,浏览器会回收内存。宿主环境提供的对象都是按照这种方法被处理的。IE 浏览器有自己的一套垃圾回收机制,这套机制与 JavaScript 提供的垃圾回收机制进行交互时,可能会发生内存泄露。
在 IE 中,每当在一个 JavaScript 对象和一个本地对象之间形成循环引用时,就会发生内存泄露。这段代码的循环引用会导致内存泄露:IE 不会释放被el
和o
使用的内存,直到浏览器被彻底关闭并重启后。
解决方式