javaScript核心概念总结
1.数据类型
2.操作符、语句
3.变量,作用域和内存问题
4.引用类型
4.原型、原型链
5.作用域、作用域链
6.闭包、垃圾回收机制
7.this指向
8.类和模块
9.继承
10.函数式编程
11.同步异步
12.JS正则表达式
13.事件模型
14.Ajax、跨域访问
15.DOM
16.BOM
一、数据类型
1.js常用的数据类型:
基础类型:字符串、布尔型、数字、null、undefined、symbol(es6新增)、BigInt(和number相比不会失去精度)
复杂类型:Object、array、function
Object.prototype.toString.call可在控制台用这个方法精确判断数据类型
Number 类型的精度丢失
Number 类型的取值范围 -2^53+1 ------ 2^53-1 具体值9007199254740991 共16位
BigInt
1,BigInt 是 JavaScript 中的一个新的原始类型,可以用任意精度表示整数。使用BigInt,即使超出 JavaScript Number 的安全整数限制,也可以安全地存储和操作大整数。
2,要创建一个 BigInt,在数字后面添加n后缀即可,例如,123变成123n。全局 BigInt(number) 函数可以用来将 Number 转换成 BigInt。换句话说,BigInt(123) === 123n。
3,BigInt 是 JavaScript 语言中的一个原始类型。因此,可以使用typeof操作符检测到这种类型:
4,因为 BigInts 是一个单独的类型,所以 a BigInt永远不会等于 a Number,例如 42n !== 42。要比较 a BigInt 和 a Number ,在比较之前将其中一个转换为另一个的类型或使用==
Symbol
应用场景1:使用 Symbol 来作为对象属性名( key )
Symbol 类型的key是不能通过 Object.keys() 或者 for...in 来枚举的,它未被包含在对象自身的属性名集合 (property names) 之中。所以,利用该特性,我们可以把一些不需要对外操作和访问的属性使用 Symbol 来定义。
也正因为这样一个特性,当使用 JSON.stringify() 将对象转换成JSON字符串的时候,Symbol 属性也会被排除在输出内容之外:
应用场景2:使用 Symbol 定义类的私有属性/方法
const PROP_NAME = Symbol()
const PROP_AGE = Symbol()
let obj = {
[PROP_NAME]: "小七"
}
obj[PROP_AGE] = 18
obj[PROP_NAME] // '小七'
obj[PROP_AGE] // 18
let obj = {
[Symbol('name')]: '小七',
age: 18,
title: 'Engineer'
}
Object.keys(obj) // ['age', 'title']
for (let p in obj) {
console.log(p) // 分别会输出:'age' 和 'title'
}
Object.getOwnPropertyNames(obj) // ['age', 'title']
JSON.stringify(obj) // {"age":18,"title":"Engineer"}
定义一个构造函数
const PASSWORD = Symbol()
class Login {
constructor(username, password) {
this.username = username
this[PASSWORD] = password
}
checkPassword(pwd) {
return this[PASSWORD] === pwd
}
}
export default Login
使用这个类
import Login from './a'
const login = new Login('admin', '123456')
login.checkPassword('123456') // true
login.PASSWORD // oh!no!
login[PASSWORD] // oh!no!
login["PASSWORD"] // oh!no!
// 由于Symbol常量PASSWORD被定义在a.js所在的模块中,外面的模块获取不到这个Symbol,也不可能再创建一个一模一样的Symbol出来(因为Symbol是唯一的),因此这个PASSWORD的Symbol只能被限制在a.js内部使用,所以使用它来定义的类属性是没有办法被模块外访问到的,达到了一个私有化的效果。
二.操作符、语句
1.while 循环
while语句属于前测试循环语句,在循环体内的代码被执行之前,就会对出口条件求值。因此循环体内代码有可能永远不会被执行。
例1:
var i = 0;
while ( i < 10 )
{
i+=2;
}
2.do-while循环
do-while 语句是后测试循环语句,即只有在循环体中的代码执行之后,才会测试出口条件。换句话说,在对条件表达式求值之前,循环体内的代码至少被执行一次。
例2:
var i = 0;
do {
i+=2;
}while( i < 10 );
alert(i);
3.for循环
for循环是一种前测试循环语句,但它具有在执行循环之前初始化变量和定义循环后要执行的代码的能力。
例3:
var count =10;
for(var i=0;i<count;i++){
alert(i);
}
4.break 和continue语句
1>break语句会立即退出循环,强制继续执行循环后面的语句。
2>continue语句虽然也是立即退出循环,但退出循环后会从循环的顶部继续执行。
例4:
var num = 0;
for(var i=1; i<10;i++){
if(i%5==0){
break;
}
num++;
}
alert(num);
//4
例5:
var num = 0;
for(var i=1; i<10;i++){
if(i%5==0){
continue;
}
num++;
}
alert(num);
//8
5.for ...of 循环
数组原生具备iterator接口(即默认部署了Symbol.iterator属性),for...of循环本质上就是调用这个接口产生的遍历器,可以用下面的代码证明。
例6:
const arr = ['red', 'green', 'blue'];
for(let v of arr) {
console.log(v); // red green blue
}
const obj = {};
obj[Symbol.iterator] = arr[Symbol.iterator].bind(arr);
for(let v of obj) {
console.log(v); // red green blue
}
6.for... in 循环
for ... in 循环中的代码每执行一次,就会对数组的元素或者对象的属性进行一次操作
例7:
JavaScript 原有的for...in循环,只能获得对象的键名,不能直接获取键值
var arr = ['a', 'b', 'c', 'd'];
for (let a in arr) {
console.log(a); // 0 1 2 3
}
例8
Object.prototype.bar = 10;// 修改Object.prototype
var obj={"name":"wjy","age":26,"sex":"female"};//定义一个object对象
var keys=[];//定义一个数组用来接受key
var values=[];//定义一个数组用来接受value
for(var key in obj){
keys.push(key);
values.push(obj[key]);//取得value
}
alert("keys is :"+keys+" and values is :"+values);
7.map 1.每一次执行匿名函数都支持3个参数,(item,index,input)item:当前项,index:当前项的索引,input:原始数组 例子
var ary = [12,23,24,42,1];
var res = ary.map(function (item,index,input) {
return item*10;
})
console.log(res);//-->[120,230,240,420,10]; 原数组拷贝了一份,并进行了修改
console.log(ary);//-->[12,23,24,42,1]; 原数组并未发生变化
8.forEach 无法中途跳出forEach循环,break命令或return命令都不能奏效。
例9:遍历数组
myArray.forEach(function (value) {
console.log(value);
});
等同于
for (var index = 0; index < myArray.length; index++) {
console.log(myArray[index]);
}
例10:遍历对象
var obj = {'0':'a','1':'b','2':'c'};
Object.keys(obj).forEach(function(key){
console.log(key,obj[key]);
});
9.switch语句
多个判断条件时使用
例11:
switch(i){
case (i===1):
alert('i===1');
break;
case (i===2):
alert('i===2');
break;
case (i===3):
alert('i===3');
break;
default:
alert('other');
}
三.变量,作用域和内存问题
1.传递参数
1.所有的参数都是按值传递的。在向参数传递引用类型的值时,会把这个值在内存中的地址复制给一个局部变量,因此这个局部变量的变化会反应在函数外部
2.当在函数内部重写obj时,这个变量引用的就是一个局部对象。而这个局部对象会在函数执行完毕后立即被销毁。
2.垃圾收集
js最常用的垃圾收集机制为“标记清除”,另一种不常用的是“引用计数”。
原理:找出不再继续使用的变量,然后释放其内存空间。垃圾收集器会在固定的时间间隔周期性的执行这一操作。
3.管理内存 解除引用:数据不再有用,将其值设置为null
四、引用类型
1.数组
// 检测数值ES5方法
Array.isArray(value) // 检测值是否为数组
// 转换方法
toString() 将数组转化为以逗号分隔的字符串
valueOf() 返回的还是数组
// 栈方法
push() 可以接收任意数量的参数,把他们逐个添加到数组的末尾,返回修改后数组的长度
pop() 从数组末尾移除最后一项,返回移除的项
// 队列方法
shift() 移除数组的第一项并返回该项
unshift() 向数组前端添加任意个项并返回新数组的长度
// 排序
sort(compare)
compare函数接收两个参数,如果返回负数,则第一个参数位于第二个参数前面;如果返回零,则两个参数相等;如果返回正数,第一个参数位于第二个参数后面
// 降序,升序相反
(a,b) => (b-a)
// 操作方法
concat(数组 | 一个或多个元素) // 合并数组,返回新数组
slice(起始位置 ,[结束位置]) // 切分数组,返回新数组,新数组不包含结束位置的项
splice(起始位置,删除的个数,[插入的元素]) // 删除|插入|替换数组,返回删除的元素组成的数组,会修改原数组
// 位置方法
indexOf(查找的项,[查找起点位置]) // 使用全等操作符,严格相等
lastIndexOf()
// 迭代方法,都接收两个参数,一个是要在每一项上运行的函数,一个是作用域(可选)
1.every 对数组中每一项运行给定函数,如果函数对每一项都返回true,则返回true
every(fn(value,index,array){return ...},[this])
2.some 对数组中每一项运行给定函数,如果函数对任一项都返回true,则返回true
3.filter 对数组中每一项运行给定函数,返回该函数会返回true的项组成的数组
4.forEach 对数组每一项运行给定函数,无返回值
5.map 对数组每一项运行给定函数,返回每次函数调用返回结果组成的数组
// 归并方法 reduce和reduceRight(和前者遍历的方向相反),构建一个最终返回的值
reduce(fn(prev,cur,index,array){ return ... },initValue)
1.fn返回的值会作为第一个参数传递给下一项
2.initValue做为归并基础的初始值
五、原型、原型链
关于原型链:
原型链作为实现继承的主要方法,其基本思想是利用原型让一个引用类型继承另一个引用继承的属性和方法。
function A(name) {
var instance = this
this.name = name
//重写构造函数
A = function () {
return instance
}
A.prototype = this
// 直接指向旧的原型
A.prototype = this.constructor.prototype
instance = new A()
// 调整构造函数指针,这里实际上实现了一次原型链继承,如果不想这样实现,也可以直接指向原来的原型
instance.constructor = A
return instance
}
var a1 = new A()
var a2 = new A()
function Person(name, age, job) {
this.name = name;
this.age = age;
this.job = job;
this.lessons = ['Math', 'Physics'];
}
Person.prototype = {
constructor: Person, // 原型字面量方式会将对象的constructor变为Object,需要强制指回Person
getName: function () {
return this.name;
}
}
var person1 = new Person('Jack', 19, 'SoftWare Engneer');
person1.lessons.push('Biology');
var person2 = new Person('Lily', 39, 'Mechanical Engneer');
console.log(person1.lessons); // ["Math", "Physics", "Biology"]
console.log(person2.lessons); // ["Math", "Physics"]
console.log(person1.getName === person2.getName); // true
class A {
fun = () => {
}
}
class B extends A {
constructor(props) {
super(props);
}
fun1 = () => {
}
}
var a = new A()