【JavaScript】 基础知识 重点 必看

浏览器本身不会执行JS代码,而是通过JS引擎解释为机器语言后执行(逐行解释)。

目录

数据类型

① 种类

② 判断

数据类型转换

① 隐式转换

② 显式转换

三元运算符(表达式)

数组

① 创建数组

② 增加元素

③ 删除元素

④ 返回元素索引号

⑤ 数组转换为字符串

伪数组

对象

① 创建对象

② 遍历对象

JSON 

浅拷贝和深拷贝 ⭐

① 浅拷贝 

② 深拷贝 

函数

 ① 命名函数

 ② 匿名函数

 ③ 构造函数new Function()

 ④ 立即执行函数

 ⑤ 箭头函数( ES6新增)

 ⑥ fn() 和 fn 的区别  ⭐

 ⑦ argument函数内置对象

 ⑧ 内置函数Math

预解析⭐

this指向问题 ⭐

① 默认指向

② call

③ apply

闭包Closure ⭐

① 闭包的概念 

② 闭包的作用

③ 闭包的应用

正则表达式

① 构造函数

② 利用字面量

③ 两种方式对比

④ 全局匹配g

⑤ 常用符号 

⑥ 典型案例(判断字符串是否为电子邮件)

原型和原型链 ⭐

① 原型 prototype

② constructor

③ 原型链

④ 对象成员查找规则

继承 

内存泄漏

严格模式


数据类型

① 种类

一般数据类型:Number、String、Boolean、Undefined、 Null;(NaN也属于Number)

引用数据类型:Object,Function、Array。(Function和Array是特殊的对象)

② 判断

typeof:返回字符串类型的数据类型值

let num=1;
console.log(typeof(num))  -> 'number'
console.log(typeof(num)===number))  -> false
console.log(typeof(num)==='number'))  ->true

let fn=function(){}
console.log(typeof(fn)==='function'))  ->true
console.log(typeof(fn)==='object'))  ->false

可以判断的数据类型: undefined、string、number、function;

不可以判断的数据类型:null和object、array和object。(null、array都会输出'object')

//会把array也判断为object
let arr=[];
console.log(typeof(arr)==='object');  ->true

let temp=null;
//会把null也判断为object
console.log(typeof(temp))  ->'object'
解决方法:
console.log(temp!=null&&typeof(temp)==='object');  ->true

instanceof:判断对象的具体类型

let obj={
    str1:'直接生成',
    str2:new String('用new生成'),
    arr:[],
    fn:(a,b)=>a+b
}
console.log(obj instanceof Object)  -> true
//在判断字符串的时候,如果不是通过new 方式创建的字符串,得到的结果为false
console.log(obj.str1 instanceof String)  ->false
console.log(obj.str2 instanceof String)  ->true 
console.log(obj.arr instanceof Array,obj.arr instanceof Object)  -> true true
console.log(obj.fn instanceof Function,obj.fn instanceof Object)  -> true true

===:可以判断undefined和null

let n=null;
let m;
console.log(n===null,m===undefined) -> true true

数据类型转换

① 隐式转换

1、‘+’两边只要有一个是字符串,都会把另一个也转为字符串。
let str = 'string' + 1;
console.log(typeof(str));   → String

2、‘+’作为正号时,可将字符串类型的数字转为数字类型。
let num = +'11';
console.log(typeof(num));   →  Number

3、除‘+’外的运算符,如‘-’、‘*’等会把字符串类型的数字转为数字类型。
let str1 = '1';
let str2 = '2';
let num = str1 * str2;
console.log(typeof(num));   →  Number;

② 显式转换

Number() ,parseInt() ,paraseFloat() 可以过滤px单位 ,String() ,str.toString()

三元运算符(表达式)

条件?满足 : 不满足

let num1=1;
let num2=2;
num1>num2 ? alert('num1>num2') : alert('num1<num2');

数组

数组的概念在多种语言中都有涉及,例如C、C++、Java、Python,所以想必大家对它都不陌生。

① 创建数组

创建方式有两种:字面量创建[ ] 、newArray()。

② 增加元素

增加元素的方式也有两种:array.push(...) 、array.unshift(...)。

① array.push(...) :元素添加至末尾,返回新数组长度。⭐

② array.unshift(...) :元素添加至开头,返回数组新长度。

③ 删除元素

删除元素的方式有三种:array.pop()、array.shift()、array.splice(start , delete_number [, element])

① array.pop() :删除数组最后一个元素,返回该元素。

② array.shift() :删除数组第一个元素,返回该元素。

③ array.splice(起始位,删除数目,添加/替换的元素)。 ⭐

④ 返回元素索引号

1、返回第一个满足的索引号: array.indexOf(要找的内容);
2、返回最后一个满足的索引号:array.lastIndexOf(要找的内容);  

⑤ 数组转换为字符串

两种方式:
1、 .toString()
2、 .join(分隔符) //默认为逗号

伪数组

伪数组和数组类似,都有长度length、有索引index,但是伪数组没有方法。

获取dom元素集合的返回的都是伪数组类型:

document.getElementsByTagName()、document.getElementsByClassName()、document.querySelectorAll()

对象

对象Object:一组无序的相关属性和方法的集合,引用数据类型,存地址。

① 创建对象

创建对象有三种方式:利用对象字面量、new Object()、构造函数。

 对象字面量:

let obj={ 
    属性名 :属性值,
    方法名 :function(){}
}
调用:obj.属性名/obj['属性名'] ; obj.方法名()

 new Object():

let obj=new Object();
obj.属性名=属性值;
obj.方法名=function(){};
调用:obj.属性名/obj['属性名'] ;obj.方法名()

 构造函数:

把对象里一些相同的属性和方法抽象出来封装到函数里,提高代码的重复利用率。

function Obj(){  //构造函数命名规范:首字母大写
    this.属性名=属性值;
    this.方法名=function(){}
    //不用return!
}
调用:let obj=new Obj(); //对象实例化
      obj.属性名/obj['属性名'] ;obj.方法名()
    

new的过程(对象实例化):

在内存中创建一个新对象 → this指向该对象 → 执行构造函数里的代码,给该新对象添加属性和方法 → 返回这个新对象(所以不需要写return)

② 遍历对象

for( let k in obj ) { } 

let obj={
    name:'huahua',
    age:18,
    move:function(){
        alert('1')
    }
}

for(let k in obj){
    console.log( k,obj[k]);
}

输出:name huahua 
      age 18 
      move ƒ (){
          alert('1')
      } 

JSON 

 JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,在与后端的数据交互中有较为广泛的应用。

json和对象字面量很相似,但json的属性名必须加双引号,而对象字面的量的可以省略。json的遍历方法和对象一样,用 for...in...

let j={
    "name":'hua',
    "age":18,
//注,json中很少写方法
    "fn":function(){}     
}
//遍历
for(let k in j){
    console.log(k,j[k]);  //属性名 属性值
}
//name hua
//age 18
//fn ƒ (){}

浅拷贝和深拷贝 ⭐

  •  浅拷贝:只拷贝最外面一层的数据;更深层次的对象,只拷贝引用。
  •  深拷贝:会把对象里所有的数据重新复制到新的内存空间,是最彻底的拷贝。

① 浅拷贝 

let obj={
    name:"hua",
    second:{sex:'women'}
}
let copy={
    name:"123",
    age:18,
    second:{sex:"both",weight:100}
}
console.log(JSON.stringify(copy));
//{"name":"123","age":18,"second":{"sex":"both","weight":100}}
for(let k in obj){
    copy[k]=obj[k]
}
//JSON.stringify()转为JSON字符串
console.log(JSON.stringify(copy),'---',JSON.stringify(obj));
//{"name":"hua","age":18,"second":{"sex":"women"}} --- {"name":"hua","second":{"sex":"women"}}
obj.name="aaa";
obj.second.sex='man';
console.log(JSON.stringify(copy),'---',JSON.stringify(obj));
//{"name":"hua","age":18,"second":{"sex":"man"}} --- {"name":"aaa","second":{"sex":"man"}}
copy.name='bbb'
copy.second.sex='unkonw';
console.log(JSON.stringify(copy),'---',JSON.stringify(obj));
//{"name":"bbb","age":18,"second":{"sex":"unkonw"}} --- {"name":"aaa","second":{"sex":"unkonw"}}
  • 第一层的数据两个对象互不影响,但第二层的数据由于两个对象指向同一个地址所以会互相影响。
  • copy对象中,同名的属性会被拷贝对象里的数据覆盖,copy对象里有而拷贝对象中没有的第一层数据会保留。

浅拷贝的实现方式:

  1. for ... in  ,比较繁琐(例子见上方代码) ;
  2. Object.assign(B,A) ⭐对象 A 复制(拷贝)给对象 B(ES6新增)
let copy={};
//三种方式
1、copy=Object.assign(obj);
2、copy=Object.assign({},obj);
3、Object.assign(copy,obj)//可以有多个源对象
  • 只有第三种方式,copy对象里有而拷贝对象中没有的第一层数据会保留。另外两种都不会保留。

② 深拷贝 

 深拷贝其实就是将浅拷贝进行递归。

// 方法:深拷贝
function deepCopy(newObj, oldObj) {
    for (let k in oldObj) {
        // 获取属性值 oldObj[k]
        let item = oldObj[k];
        // 判断这个值是否是数组
        if (item instanceof Array) {
            newObj[k] = [];
            deepCopy(newObj[k], item);
        } 
         // 判断这个值是否是对象
        else if (item instanceof Object) {           
            newObj[k] = {};
            deepCopy(newObj[k], item);
        } 
        else {
            // 简单数据类型,直接赋值
            newObj[k] = item;
        }
    }
}

函数

 函数function:一些功能或语句的封装。在需要的时候,通过调用的形式,执行这些语句。实现代码复用。函数也是一个对象。

 ① 命名函数

使用函数声明来创建一个函数。

function 函数名(形参,...){

}
调用:函数名(实参,...);

 ② 匿名函数

使用函数表达式来创建一个函数。所谓的“函数表达式”,其实就是将匿名函数赋值给一个变量。因为,一个匿名函数终究还是要给它一个接收对象,进而方便地调用这个函数。

let fn=function(形参){}

后续的DOM里的绑定事件函数和BOM里的定时器函数也是匿名函数。 

 ③ 构造函数new Function()

let fn=new Function('形参','函数体');

 ④ 立即执行函数

立即执行函数:函数定义完,立即被调用,无需额外调用,这种函数叫做立即执行函数。

两种写法
1、( function (形参) {} (实参) )
2、( function (形参) {} ) (实参)

 ⑤ 箭头函数( ES6新增)

 相当于匿名函数且简化了函数定义

let fn=(形参)=>{函数体}

箭头函数不会自己创建this,只会从自己的作用域链的上一层继承this

 ⑥ fn() 和 fn 的区别 

  •  fn():调用函数。调用之后,获取了函数的返回值。
  •  fn:函数对象。相当于直接获取了整个函数对象。
  • 判断数据类型时,函数、方法不加(),判断的是整个函数对象而不是返回值。

 ⑦ argument函数内置对象

 以伪数组的形式存储所有传递过来的实参

function fn(a,b){
    console.log(argument);
    console.log(argument.length);
}
fn(1,'b')
输出:Argument{0:1 , 1:'b'}  2

 ⑧ 内置函数Math

获取随机数:Math.random()   //范围是[0,1)

给定范围取随机值:[min,max] , random()*(max-min+1)+min

取整:floor向下取整,ceil向上取整,round四舍五入,±x.5的取大

预解析⭐

分为变量提升函数提升

通过例子理解更清晰,下面的代码会输出什么呢?

fn();
console.log(a);
console.log(b);
var a=10;
function fn(){
    console.log(a);
    console.log(b);
    var a=b=9;
    console.log(a);
    console.log(b);
}
console.log(a); 

 预解析后: 

//变量提升
var a;
//函数提升
function fn(){
    //变量提升
    var a;
    console.log(a);     //undefined
  //console.log(b);     //报错
    a=9;
    b=9;                //全局变量
    console.log(a);     //9
    console.log(b);     //9
}
fn();
console.log(a);        //undefined
console.log(b);        //9
a=10;
console.log(a);        //10

this指向问题 ⭐

① 默认指向

一般指向调用它的对象

  • 全局作用域、普通函数、定时器函数、立即执行函数中,指向window
  • 方法调用中,谁调用this就指向哪个对象;
  • 构造函数中,this指向构造函数的实例;
  • 箭头函数中,this继承作用域链的上一层;
  • 事件绑定中,this指向绑定的对象。

② call

call(this指向,参数) 两种应用

  • 调用函数
  • 改变this指向 
  • 主要用于实现继承
function fn(a){
    console.log(111,a);
    console.log(this);
}
let arr=[];
fn(2);              //111 2 window
fn.call(arr,2);     //111 2 []

③ apply

apply(this指向,[数组(伪数组)形式传参])  也是两种应用

  • 调用函数
  • 改变this指向 
  • 主要运用于数组,如Math.max(math,arr)返回最大值
function fn(a){
    console.log(111,a);
    console.log(this);
}
let arr=[];
fn(2);                  //111 2 window
fn.apply(arr,[2]);     //111 2 []

闭包Closure ⭐

① 闭包的概念 

如果外部作用域有权访问另外一个函数内部局部变量时,那就产生了闭包。这个内部函数称之为闭包函数

再次执行fn2后输出4,这说明了闭包里的数据没有消失,而是保存在了内存中。如果没有闭包,代码执行完倒数第三行后,变量a就消失了。闭包对象的个数取决于外部函数的调用次数,与内部函数无关。

被访问的局部变量所在的函数就是一个闭包函数。还不确定到底哪个是闭包函数的,可以通过浏览器调试设置断点查看。上图中, Local 指的是局部作用域,Global 指的是全局作用域;而 Closure 则是闭包,fn1 是一个闭包函数。 

② 闭包的作用

  • 延长局部变量的生命周期

  • 让函数外部可以操作(读写)到函数内部的数据(变量/函数)

③ 闭包的应用

  • 高阶函数
  • 封装JS模块:定义特色JS模块,将所有数据和功能都封装在一个函数里(私有的),外部调用者只能调用暴露的方法或对象。在C++、Python、Java等语言中有私有属性的概念,但在JS中只能通过闭包模拟实现。⭐

正则表达式

定义:用于定义一些字符串的规则。

作用:计算机可以通过正则表达式检查一个字符串是否符合指定规则,或将字符串中符合规则的部分提取出来。

创建方式:

① 构造函数

  • let 变量 = new RegExp("正则表达式" [, "匹配模式"] ); //可以传一个参数也可以传两个参数,参数是字符串。
  • 变量.test(字符串);//判断是否符合指定的正则表达式

匹配模式可以是 'i':忽略大小写,也可以是 'g':全局匹配模式,会保留lastIndex

let my=new RegExp('a');
let myReg=new RegExp('A','i');
let str='H';
let myR=new RegExp(str,'i');
console.log(my.test('hello'),myReg.test('hello')); // false false
console.log(my.test('hallo'),myReg.test('hallo')); // true true
console.log(my.test('hello'),myReg.test('hallo')); // true true

② 利用字面量

  • let 变量 = /正则表达式/[模式匹配];  //注意没有引号
  • 变量.test(字符串);
let my=/a/;
let myReg=/a/i;
console.log(my.test('hello'),myReg.test('hello')); // false false
console.log(my.test('hallo'),myReg.test('hallo')); // true true

③ 两种方式对比

  • 方法一更灵活,参数可以传递变量;
  • 方法二更简单。

④ 全局匹配g

const s='huao_huaphua';
//let my=new RegExp('hua','g');
let my=/hua/g;
    
console.log(my.test(s),my.lastIndex); // true 3
console.log(my.test(s),my.lastIndex); // true 8
console.log(my.test(s),my.lastIndex); // true 12
console.log(my.test(s),my.lastIndex); // false 0

匹配成功返回true,同时把 lastIndex 属性的值设置为上次匹配成功结果之后的下一个字符所在的位置,下次匹配将从 lastIndex 指示的位置开始;匹配不成功时返回 false,同时将 lastIndex 属性的值重置为 0。 

  • 全局匹配模式一般用于 exec()match()replace()等方法。

  • g模式会生成一个lastindex参数来存储匹配最后一次的位置。

⑤ 常用符号 

  • |或,[]或。/[ab]/=/a|b/;/[0~9]/任意数字;/[A-z]/任意字母;/[a-z]/任意小写字母;
  • ^起始符
  • [^]除了
  • $结束符
  • [内容]{数量}

⑥ 典型案例(判断字符串是否为电子邮件)

let reg=/^\w{3,}(\.\w+)*@[A-z0-9]+(\.[A-z]{2,5}){1,2}$/;
^以什么开头,\w表示字母数字下划线,\.转义字符加点表示小数点(没\就表示任意字符),+表示前面的至少一个,*表示前面的有0个或多个。
故这一整句表示:以三个以上的字母或数字或下划线为开头,然后(.一个或多个字母或数字或下划线)0个或多个,@,任意一个字母或数字,(.(任意字母)两个到五个)一个到两个结束。

原型和原型链 ⭐

① 原型 prototype

  • 实例成员就是通过实例化对象生成的属性和方法,只能通过实例化对象访问;
  • 静态成员就是直接通过构造函数生成的,只能通过构造函数访问。
  • 在实例成员的方法中,每生成一个实例对象,就会为方法开辟一个新的内存空间,而静态成员则不会,这样就能节省空间。
function fn(){
    this.name='hua',//实例成员,只能通过实例化对象访问
    this.sing=function(){}
}
let obj_fn=new fn();//实例化对象
console.log(obj_fn.name);
obj_fn.sing();

fn.age=18;//静态成员,只能通过构造函数访问

每一个构造函数都有一个prototype属性,指向另一个对象。这个对象的所有属性和方法都会被构造函数所共享。

function fn(){
    //this.sing=function(){} //obj_fn.sing===obj_fn2.sing false
}
let obj_fn=new fn();
let obj_fn2=new fn();
fn.prototype.sing=()=>'singing';
console.log(obj_fn.sing===obj_fn2.sing) //true
console.log(fn.prototype.sing(),obj_fn.sing()); //singing singing
console.log(obj_fn.__proto__===fn.prototype) //true

对象都会有一个__proto__属性(每边两个下划线)指向构造函数的prototype原型对象,所以 对象可以调用原型对象的成员。

② constructor

 原型对象prototype和对象原型__proto__里都有一个constructor属性,它指回构造函数本身。

function fn(name){
    this.name=name;
}
let obj_fn=new fn('hua');
//fn.prototype.sing=function(){}//与下面等价
//fn.prototype.dance=function(){}
fn.prototype={
//给原型对象赋值了一个对象,则必须给它手动利用constructor指向原来的构造函数
    constructor:fn,  
    sing:function(){},
    dance:function(){}
}
console.log(obj_fn.__proto__.constructor); //都指向构造函数fn
console.log(fn.prototype.constructor);

给原型对象赋值了一个对象,则必须给它手动利用constructor指向原来的构造函数。此时不能通过实例对象调用prototype里的内容,得用构造函数名.prototype.属性/方法来调用。

③ 原型链

function fn(){}
let obj_fn=new fn();
console.log(obj_fn.__proto__.constructor);                      //fn
console.log(fn.prototype.constructor);                          //fn
console.log(fn.prototype===obj_fn.__proto__);                   //true
console.log(fn.prototype.__proto__.constructor);                //Object
console.log(Object.prototype.constructor);                      //Object
console.log(Object.prototype===fn.prototype.__proto__);         //true                   
console.log(Object.prototype.__proto__);                        //null

④ 对象成员查找规则

按照原型链的顺序:实例对象 -> 构造函数原型对象 -> Object原型对象 -> null

function fn(){
    this.age=16;
}
let obj_fn=new fn();
fn.prototype.age=18;
Object.prototype.age=20;
console.log(obj_fn.age); //16

继承 

 运用call和原型对象、对象原型。

function Father(name){
    this.name=name;
}
function Son(name){
    Father.call(this,name);  //简单继承
}
let son=new Son('hua');
console.log(son.name);                        //hua
Father.prototype.age=()=>18;
son.prototype=new Father(); //将父亲赋值给实例对象的原型对象
son.prototype.constructor=Son;//指回实例对象的构造函数
console.log(son.prototype.__proto__.age());  //18

内存泄漏

概念:占用的内存没有及时释放 。注意,内存泄露的次数积累多了,就容易导致内存溢出。

  • 闭包(一般不会,但如果滥用闭包则会)
  • 没有及时清理的定时器或回调函数
  • 意外的全局变量

内存溢出:当程序需要的内存大于剩余的内存空间时,就会抛出内存溢出的错误。 

严格模式

即在严格的条件下运行(ES5新增)。严格模式通过在脚本或函数的头部添加"use strict"; 表达式来声明。

为什么使用严格模式?

  • 消除代码运行的一些不安全之处,保证代码运行的安全;
  • 提高编译器效率,增加运行速度;
  • 为未来新版本的js做铺垫。

限制:

  • 不能使用未声明的变量;
  • 不能删除变量;
  • 变量不能重名;
  • 不能使用转义字符\;
  • 不能对只读属性赋值;
  • 禁止this只想全局对象;
  • 变量名不能使用'eval'、'arguments';
  • ……
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值