JavaScript 发展历程:
1.网景公司95年发布JavaScript
2.ECMAScript 是标准,JavaScript是具体实现
3.ES6 15年六月发布
快速入门
1.将代码放到网页的任何地方,用<script> … </script>包含JavaScript的代码
2.将JS代码放在单独的JS文件中,<script src=“”> … </script>引入文件
3.JS区分大小写
数据类型和变量
number;字符串:’abc’ “abc”;布尔值;&& ;||;!;
1.== 和=== ;==会先进行数据类型的转换,===数据类型不同直接返回false,尽量使用===
2.NaN与所有值都不相等,包括他自己
NaN === NaN; //false
isNaN(NaN); //true
3.浮点数的比较,通过差值的绝对值小于某个阀值
4.null和undefined
5.数组,对象,变量:变量名是大小写英文、数字、$和_的组合,且不能用数字开头。变量名也不能是JavaScript的关键字,如if、while等。
6.不用var申明的都是全局变量,var申明的是局部变量,范围别限制在该变量神明的函数题内
7.使用严格模式:’use strict’
字符串
1.转义符\:\n表示换行,\t表示制表符,\\表示\自身
ASCII字符用\x##形式的十六进制表示 ‘\x41’ //等同于’A’
Unicode字符用\u###表示: ‘\u4e2d\u6587’ //等同于’中文’
2.多行字符串用\n表示费事,ES6新的字符串的表示方法:
反引号` … `表示
3.使用+比较麻烦,ES6新增模板字符串,表示方法和上边一样,用` … `包起来
如: var message = `你好, ${name}, 你今年${age}岁了!`;
字符串的操作:
var s = “Hello World!”;详见’JS字符串操作’文档
1.s.length取长度,s[0];//‘h’,需要注意的是,字符串是不可变的,如果对字符串的某个索引赋值,不会产生错误但是也不会产生结果
2.JavaScript为字符串提供了一些常用方法,注意,调用这些方法本身不会改变原有字符串的内容,而是返回一个新字符串:
* toUpperCase()把一个字符串全部转换成大写;
* toLowerCase()把一个字符串全部转换成小写;
* indexOf(str)从首位检索指定字符串出现的位置;没有返回-1
* lastIndexOf(str)从末尾检索指定字符串出现的位置;没有返回-1
* substring(start, end)返回指定索引区间的子串;
* slice(start, end)提取一个字符串的一部分,返回新的字符串;
* substr(start, length)返回字符串的一个子串;
* split(“”)将一个字符串转换成一个字符串数组;
* concat(str)将两个或多个字符的文本组合起来,返回新的字符串;
* charAt(index)返回指定位置的字符:
a = ‘hello’;
var get_char = a.charAt(0); //get_char = ‘h’;
* match(正则表达式)检查以恶搞字符串匹配一个正表达式内容,没有匹配返回null
数组
1. 数组长度length
2. 数组搜索:indexOf()返回元素的索引(位置)
3. 数组截取:slice(start, end)对应string的substring,可以没有任何参数,相对于复制了数组
4. push()向数组的末尾添加若干元素,pop()删除数组的最后一个元素;
5. unshift()向数组的头部添加若干元素,shift()将数组的第一个元素删除;
6. sort()对当前数组排序,按照默认顺序排序;
7. reverse()反转数组元素;
8. splice()方法是修改数组的万能方法,它可以从指定索引删除若干元素,然后再从改位置添加若干元素
12345678910
var arr = ['Microsoft', 'Apple', 'Yahoo', 'AOL', 'Excite', 'Oracle'];// 从索引2开始删除3个元素,然后再添加两个元素:arr.splice(2, 3, 'Google', 'Facebook'); // 返回删除的元素 ['Yahoo', 'AOL', 'Excite']arr; // ['Microsoft', 'Apple', 'Google', 'Facebook', 'Oracle']// 只删除,不添加:arr.splice(2, 2); // ['Google', 'Facebook']arr; // ['Microsoft', 'Apple', 'Oracle']// 只添加,不删除:arr.splice(2, 0, 'Google', 'Facebook'); // 返回[],因为没有删除任何元素arr; // ['Microsoft', 'Apple', 'Google', 'Facebook', ‘Oracle’]
9. concat([other array])把当前数组和另一个数组链接起来,并返回新的数组
10. join(‘-’)把数组当前的元素都用指定的字符串链接起来,并且返回连接后的字符串,array中元素不是字符串,会先进行转换
对象
1. JS对象是一种无序的集合数据类型,由若干键值对组成
2. 属性的访问,.或者[‘’]或者[“”],没有的属性返回undefined
3. JS对象是动态类型,可以给对象添加或者删除属性
4. 检测对象是否拥有某一属性,可以用in操作符,但是in判断属性会检查对象的父类,有可能是对象继承而来的属性
5. 判断一个属性是否是对象本身拥有,使用hasOwnProperty()方法
判断条件
1.if{ …. } else{ …. }
2.JS把null,undefined,0,NaN和空字符串’’视为false,其他一律为true
循环
1. for(初始条件;判断条件;递增条件){ … },for循环常用来利用索引遍历数组
2. for … in循环,把一个对象的所有属性依此循环出来,要过滤掉对象继承的属性,使用hasOwnProperty()来实现
for … in 对数组循环得到的是String而不是Number
3. while(){ … }; do{ … }while();
Map和Set
1. Map是一组键值对的结构,具有极快的查找速度 map的方法有get()和set();
2. Set和Map类似,也是一组key的集合,但不存储value。在Set中没有重复的key。重复元素在Set中被自动过滤。
add(key)方法可以向Set中添加元素,可以重复添加,但是没有效果。
delete(key)方法删除元素。
iterable
1. Array,Map,Set都属于iterable类型
2. iterable类型集合可以通过for...of循环来遍历
for … of 与for … in的区别:
for ... in循环由于历史遗留问题,它遍历的实际上是对象的属性名称。一个Array数组实际上也是一个对象,它的每个元素的索引被视为一个属性
var a = ['A', 'B', 'C'];
a.name = 'Hello';
for (var x in a) {
alert(x); // '0', '1', '2', 'name'
}
for ... in循环将把name包括在内,但Array的length属性却不包括在内。
for ... of循环则完全修复了这些问题,它只循环集合本身的元素:
var a = ['A', 'B', 'C'];
a.name = 'Hello';
for (var x of a) {
alert(x); // 'A', 'B', 'C'
}
3. iterable 的内置forEach()方法,它接受一个函数,每次迭代久自动回调该函数。
for example:
var a = [‘a’, ‘b’, ‘c’];
a.forEach(function(element, index, array)){
//element: 指向当前元素的值
//index: 指向当前索引
//array: 指向Array对象本身
alert(element);
}
Set没有索引,因此回调函数的前两个参数都是元素本身
s.forEach(function(element, sameElement, set){ … });
Map的回调函数参数依次是value,key, 和map本身
m.forEach(function(value, key, map){ … });
函数
1. JS中的函数是头等公民,具有强大的抽象能力
2. 函数的定义
function abc(){
if(x>=0){
return x;
}
else return -x;
}
• function指出这是一个函数定义;
• abs是函数的名称;
• (x)括号内列出函数的参数,多个参数以,分隔;
• { ... }之间的代码是函数体,可以包含若干语句,甚至可以没有任何语句。
JS 函数也是对象,因此abc()函数实际上是一个函数对象,函数名可以看成指向该函数的变量
var abc = function(x){ … };与上边的等价
3.函数的调用abc(90); abc(); abc(1,90,x);
4.arguments只在函数的内部起作用,并且永远指向当前函数的调用者传入的所有参数。
变量作用域
1. 在函数内部声明的变量,该变量的作用域为整个函数体,函数体外不可引用该变量
2. 不同函数内部的同名变量相互独立,互不影响
3. 在嵌套函数中,内部函数可以访问外部函数的变量,反过来不行
4. 函数在查找变量是从自身函数开始,由内向外查找,如果函数内部定义了与外部函数同名的变量,内部函数的变量将屏蔽外部函数的变量
5. 变量提升:把所有声明的变量提升到函数顶部,JS引擎提升变量的声明,但是不会提升变量的赋值。
因此在JS中,请严格遵守“在函数内部首先声明所有的变量”这一规则,常用的方法是用
一个var申明函数内部用到的所有变量
全局作用域
1. 不在任何函数内定义的变量就具有全局作用域,JS有一个默认的全局对象Window,全局作用域的变量实际上被绑定到window的一个属性
2. 顶层函数的定义被视为一个全局变量,并绑定到window对象
3. JS实际上只有一个全局作用域,任何变量(函数也视为是变量),如果在当前作用域中没有找到,就会继续向上查找。在全局作用域也没找到,则报ReferenceError错误。
名字空间
1. 全局变量会绑定到window上,不同JS文件如果使用了相同的全局变量,就会造成命名冲突。
2. 减少冲突的方法是把自己的所有变量和函数全部绑定到一个全局变量中
局部作用域
1.JS变量的作用域是函数内部,因此在for循环等语句块无法定义具有局部作用域的变量
2.为了解决块级作用域,ES6引入关键字let,用let可以声明一个块级作用域的变量
常量
1.在ES6之前用大写的变量表示这是一个变量
2.ES6引入新的关键字const定义变量,const与let都具有块级作用域
方法
1. 方法其实就是函数,但是一般称绑定在对象上的函数称为方法
2. 在方法内部,this是一个特殊变量,指向对前对象,就是方法绑定的那个对象
3. 以对象的方法形式调用,函数的this指向被调用的对象,如果单独调用,this指向全局变量即window。在strict模式下,this指向undefined的,因此在strict模式下,会得到一个
错误
12345678910111213'use strict';var xiaoming = { name: '小明', birth: 1990, age: function () { function getAgeFromBirth() { var y = new Date().getFullYear(); return y - this.birth; } return getAgeFromBirth(); }};
xiaoming.age(); // Uncaught TypeError: Cannot read property 'birth' of undefined
结果又报错了!原因是this指针只在age方法的函数内指向xiaoming,在函数内部定义的函数,this又指向undefined了!(在非strict模式下,它重新指向全局对象window!)
修复的办法也不是没有,我们用一个that变量首先捕获this:
apply
1. 在单独的函数调用时,this指向window或者undefined,不过我们可以控制this的指向
2. 调用函数的apply方法,指定函数的this指向。apply接受两个参数,第一个参数是需要绑定的this变量,第二个参数是Array,表示函数本身的参数getAge.apply(xiaoming, []);
3. call()跟apply一样,只是apply把参数打包成Array再传入,call()把参数顺序传入
4. 对普通函数的调用,我们可以把this绑定为null
装饰器
1. 利用apply(),可以动态改变函数的行为
高阶函数
1. 高阶函数:higher-order function。函数可以接受另一个函数作为参数,这样的函数就是高阶函数,下边的都是一些高阶函数
2. map()方法,map()方法定义在JS的Array中,我们调用Array的map()方法,传入我们自己的函数,就得到一个新的Array作为结果。对数组中每一个元素调用我们的方法
3. reduce()方法,Array的reduce()方法把一个函数作用在Array的[x1,x2,x3..]上,这个函数必须接受两个参数,reduce()把结果和序列的下一个元素做累积计算。
4. filter()方法,Array的filter()方法接受一个“筛选”函数,把该函数作用与数组的每个元素,然后根据返回值的true和false决定保留还是丢弃该元素。filter()接受回调函数,可以有多个参数,第一个元素表示Array的某个元素,第二个参数表示元素的位置,第三个表示数组本身
5. sort()方法,数组的sort()方法默认把所有元素转化成String,然后在排序。sort()也是高阶函数,它可以接受一个比较函数来实现自定义排序。忽略大小比较字符串,要将字符串都变成小写或者大写。sort()方法直接对Array进行修改。
闭包
1. 高阶函数除了可以接受函数参数外,还可以将函数作为结果返回。
2. 返回闭包时牢记返回函数不要引用任何循环变量,或者后续会发生变化的变量
3. 创建一个匿名函数并立即执行 (function(x){return x * x;}) (3);
4. 闭包就是携带状态的函数,并且他的状态完全对外隐藏
箭头函数
1. 箭头函数相当于匿名函数,(参数)=> { 函数体 }
2. 当只有一个函数参数跟一条语句时简写为 x => x*x; return 都可以省略
如果想要返回一个对象,函数体的{}跟对象的{}有冲突,可以用()扩起来:
x => ({foo: x })
3. 箭头函数与匿名函数的区别,箭头函数内部的this是词法作用域,由上下文确定
4. 由于this在箭头函数中已经按照词法作用域绑定了, 所以用call()和apply() 调用箭头函数时,无法用this进行绑定。即第一个传入的参数将被忽略。
generator
1. generator(生成器)时ES6引入的新的数据类型,看上去是一个函数,但是可以返回多次。
2. generator和函数的不同是:generator由function* (注意*)定义,除了return语句,还可以用yield返回多次。
3. 直接调用generator,仅仅是创建了一个generator对象,而没去执行它,调用generator对象有两个方法:
一个是不断的调用generator对象的next()方法,next方法会执行generator的代码,然后每次遇到yield x; 就会返回一个对象{value: x, done: true/false},value就是yield的返回值,done表示这个generator是否执行结束。如果done为true,value就是return的返回值。
一个是直接调用for … of 循环迭代generator对象,这种方式不需要自己判断done
4.generator看上去是一个可以记住状态的函数,generator可以写出需要面向对象才能实现的功能,generator就是把异步回调变成同步代码
标准对象
1. 在JS世界中,一切都是对象,为了区别对象的类型,用typeof操作符获取对象的类型,他总是返回一个字符串。null 和array的类型也是object,使用typeof无法区分出null,Array和通常意义上的对象{}
2. 包装对象 遵守:
• 不要使用new Number()、new Boolean()、new String()创建包装对象;
• 用parseInt()或parseFloat()来转换任意类型到number;
• 用String()来转换任意类型到string,或者直接调用某个对象的toString()方法;
• 通常不必把任意类型转换为boolean再判断,因为可以直接写if (myVar) {...};
• typeof操作符可以判断出number、boolean、string、function和undefined;
• 判断Array要使用Array.isArray(arr);
• 判断null请使用myVar === null;
• 判断某个全局变量是否存在用typeof window.myVar === 'undefined';
• 函数内部判断某个变量是否存在用typeof myVar === 'undefined'。
** 任何对象都有toString()方法吗?null和undefined就没有!确实如此,这两个特殊值要除外,虽然null还伪装成了object类型。 **
Number对象调用toString()报错,123.toString(); // 错误
正确的: 123..toString(); 或者 (123).toString();
Date
1.要获取系统当前时间,用var now = new Date(); 可以使用now.getFullYear();获得月份;使用now.getMonth();获得月份等等
2.当前时间是浏览器从本机的操作系统获取的时间,因此不一定准确。创建一个指定日期:var d = new Date(2015, 5, 19, 20, 15, 30, 123);
3.在JS中,0表示一月份,一次类推。
RegExp 正则表达式
- \d 匹配一个数字, \w匹配一个字符或者数字
- . 匹配任意一个字符
- * 表示任意个字符(包括0个),+ 表示至少一个字符, ?表示0个或者1个字符, {n} 表示n个字符,{n,m} 表示n-m个字符
- \s匹配一个空格(也包括Tab等空格符)
- A|B 可以匹配A也可以匹配B
- ^ 表示行的开头,$表示行的结束 ^\d 表以数字开头 \d$表示以数字结尾
- []表示范围 [0-9a-zA-Z\_]可以匹配一个数字字符或者下划线
javaScript中正则表达式的创建
1. /正则表达式/flags
2. new RegExp(‘正则表达式’)
RegExp对象的test() 方法用于测试给定字符串是否符合条件
使用:
切分字符串:
‘a b c’.split(‘ ’); // [‘a’, ‘b’, ‘’, ‘’, ‘’, ‘c’]
‘a b c’.split(/\s+/); // [‘a’, ‘b’, ‘c’]
‘a,b, c d’.split(/[\s\,]+/);
分组:
正则表达式可以提取子串,用()表示要提取的分组
如:^(\d{3}) - (\d{3,8})$ 定义的组,就可以再RegExp对象上用exec()方法提取子串
exec()方法匹配成功后,会返回一个Array,第一个元素是匹配到的整个字符串,后边的字符串表示匹配成功的子串
3. 贪婪匹配:
\d+ 贪婪匹配 \d? 非贪婪匹配
4. flags
g 表示全局匹配
i 表示忽略大小写
m 表示多行匹配
JSON
JSON的字符集必须是UTF-8,JSON必须用双引号“”
1. 将JS对象序列化成JSON格式的字符串:
JSON.stringify(obj, null, ‘ ‘);
第二个参数用于控制筛选对象的键值,只输出制定的属性, 可以传入Array:
JSON.stringify(obj, [‘name’, ‘skill’], ‘’);
也可以传入一个函数,对象的每个键值对都被函数先处理
可以将一个JSON对象添加一个toJSON方法,直接返回JSON应该序列化的数据
2. 反序列化
JSON.parse()将JSON格式的字符串变成JS对象
JSON.parse(‘{“name”: “小明”, “age”:14}’, function(key, value) { 用来解析属性})
面向对象
obj._proto_改变对象的原型
Object.create()方法可以传入一个原型对象,并创建一个基于该原型的新对象
1. 创建对象
JS对每个创建的对象设置一个原型,只想他的原型对象
arr—-> Array.prototype —-> Object.prototype —-> null
2. 构造函数
定义一个函数,通过new 关键字来调用这个函数,并默认返回this
通过new Student()创建的对象还从原型上获得一个constructor属性, 它指向函数Student本身
3. 原型继承
#### class继承
class从ES6引入
class Student(name) {
constructor(name) {
this.name = name;
}
hello() {
alert(‘Hello’);
}
}