一篇文章让你了解JavaScript高级


ES5的时候,我们知道的数据类型是 6种:number、 String 、Boolean 、undefind 、Null、object

ES6中新增了一种Symbol。这种类型的对象永不相等,即使创建的时候传入相同的值,可以解决属性名冲突的问题,作为标记

谷歌67版本中还出现了一种biglnt。是指安全储存、操作大整数。

所以JS的数据类型有几种?
8种。number、String、Boolean、Null、undefined、object、symbol、bigInt

js数据类型分为两类:基本数据类型和引用数据类型
基本数据类型:除Object。number、string、Boolean、Null、undefined
引用数据类型:就是Object。其中包含:function、Array、Date

了解完数据类型,我们来了解数据类型里面的对象

一.Object(对象)

1.对象使用

对象:用来储存键值对和更复杂的实体
创建空对象
1.let obj = new Object();//构造函数语法创建对象
2.let obj = {};//‘字面量’语法创建对象通常我们用花括号的这种种方式叫做字面量

let user = {     // 一个对象
  name: "John",  // 键 "name",值 "John"
  age: 30        // 键 "age",值 30
};

生成的 user 对象可以被想象为一个放置着两个标记有 “name” 和 “age” 的文件的柜子。
在这里插入图片描述
所以在这个柜子里我们可以随时添加、删除和读取文件。并且可以使用点符号访问属性值
如何访问属性值?
点符号: user.name。
方括号:user[“name”],方括号允许从变量中获取键
如何添加属性值

user.sex = '女';

如何移除属性?用delete

delete user.age;

3.使用方括号,如果我们需要一些更复杂的内容,那么就用方括号。

2.属性存在性测试

属性是否存在对象中,用“in”操作符测试

let user = { name: "John", age: 30 };

alert( "age" in user ); // true,user.age 存在
alert( "blabla" in user ); // false,user.blabla 不存在。

in 的左边必须是 属性名。通常是一个带引号的字符串。

3.如何遍历对象

可以使用一个特殊形式的循环:for…in

for (key in object) {
  // 对此对象属性中的每个键执行的代码
}

4.对象的引用和复制

在这里插入图片描述
实际上对象存放在栈中,里面的属性存放在堆内存中。
如果当一个对象变量被复制-引用被复制,而对象自身并没有被复制。

let user = { name: "John" };

let admin = user; // 复制引用

变量之间的赋值是在栈中,他们指向的都是同一个地址。这里仍然只有一个对象,但是有两个引用他们的变量
在这里插入图片描述

  • n个引用变量指向同一对象,通过一个变量修改对象内部数据,其他所有变量看到的是修改之后的数据。因为两个变量指向同一个地址,我们通过其中一个变量改变地址中的内容,其他变量指向的内容也改变
let user = { name: 'John' };
        let admin = user;
        admin.name = 'Pete';
        console.log(user.name);//输出为Pete
        user.name ='lili';
        console.log(admin.name,user.name);//输出都为lili

这就像我们有一个带有两把钥匙的柜子,使用其中一把钥匙(admin)打开柜子并更改了里面的东西。那么,如果我们稍后用另一把钥匙(user),我们仍然可以打开同一个柜子并且可以访问更改的内容。

  • 2个引用变量指向同一对象,让其中一个引用变量指向另一个对象,另一个变量依然指向前一个对象
 let a = {age:12};
    let b = a;
    a= {name: 'BOB',age:13};
    b.age = 14;
    console.log(b.age,a.name,a.age);//14 BOB 13

在这里插入图片描述

5.垃圾回收

在js中拥有自动的垃圾回收机制,会自动将这些垃圾对象从内存中销毁,垃圾回收是自动完成的,我们不能强制执行或者阻止。

我们需要做的只是将不再使用的对象设置null即可

6.对象方法this

  • 为什么会有this
    当我们面向对象的时候,我们需要用不同的变量来访问同一个方法,this就可以充当任何一个变量来调用。

  • 在JavaScript中this关键字与其他大多数编程语言不同,JavaScript 中的 this 可以用于任何函数,即使它不是对象的方法。

  • this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象

1、如果一个函数中有this,但是它没有被上一级的对象所调用,那么this指向的就是window,这里需要说明的是在js的严格版中this指向的不是window,但是我们这里不探讨严格版的问题,你想了解可以自行上网查找。

2、如果一个函数中有this,这个函数有被上一级的对象所调用,那么this指向的就是上一级的对象。

3、如果一个函数中有this,这个函数中包含多个对象,尽管这个函数是被最外层的对象所调用,this指向的也只是它上一级的对象

this的不同的情况:

  1. 以函数的形式调用时,this永远都是window
  2. 以方法的形式调用时,this就是调用方法的对象
  3. 以构造函数的形式调用时,this就是新创建的对象
  4. 使用call和apply调用时,this就是指定的那个对象
  5. 在全局作用域中this代表window

改变函数内部this指向
JavaScript为我们专门提供了一些函数方法来帮我们更优雅的处理函数内部this的指向问题。常用的有bind()、call()、apply()三种方法
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

二.构造函数

1.构造函数

构造函数,或简称构造器,就是常规函数,但大家对于构造器有个共同的约定,就是其命名首字母要大写。构造器的主要目的 —— 实现可重用的对象创建代码
构造函数:是一种特殊的函数,通过new函数名来实例化对象
主要作用:用来初始化对象,添加属性和方法
注意:1.首字母大写 2.只能由 “new” 操作符来执行。
new在执行会做四件事
1.在内存中创建一个新的空对象
2.让this指向这个新对象
3.执行构造函数里面的代码,给这个新对象添加属性和方法
4.返回这个新对象(所以构造函数里面不需要return)

function User(name) {
  this.name = name;
  this.isAdmin = false;
}

let user = new User("Jack");

alert(user.name); // Jack
alert(user.isAdmin); // false

所以 new User(“Jack”) 的结果是相同的对象:

let user = {
  name: "Jack",
  isAdmin: false
};

构造函数中包含静态成员 和 实例成员
1.实例成员就是构造函数内部通过this添加的成员 uname age sing就是实例成员
实例成员只能通过实例化的对象来访问 不能通过构造函数来访问

function Star(uname,age){
       this.uname = uname;
       this.age = age;
       this.sing = function(){
           console.log('我会唱歌');
       }
   }
   var ldh = new Star('李德华',18);

2.静态成员 在构造函数本身上添加的成员 sex就是静态成员静态成员只能通过构造函数来访问

Star.sex = '男';
console.log(Star.sex);

2.构造器的return

构造器没有 return 语句。它们的任务是将所有必要的东西写入 this,并自动转换为结果。

但是,如果这有一个 return 语句,那么规则就简单了:

  • 如果 return 返回的是一个对象,则返回这个对象,而不是 this。
  • 如果 return 返回的是一个原始类型,则忽略。

换句话说,带有对象的 return 返回该对象,在所有其他情况下返回 this。
省略括号
如果没有参数,我们可以省略 new 后的括号

let user = new User; // <-- 没有参数
// 等同于
let user = new User();

三.原型

构造函数的缺陷
在这里插入图片描述
在这里插入图片描述
所以我们引入了构造函数原型prototype

1.构造函数原型prototype

构造函数通过原型分配的函数是所有对象所共享的

JavaScript规定每一个构造函数都有一个prototype属性,指向另一个对象。注意这个prototype就是一个对象,这个对象的所有属性和方法,都会被构造函数所拥有

我们可以把不变的方法,直接定义在prototype对象上,这样所有对象的实例就可以共享这些方法

 function Star(uname, age) {
            this.uname = uname;
            this.age = age;
            //    this.sing = function(){
            //        console.log('我会唱歌');
            //    }如果对象引用太多会开辟很多新的内存空间,会浪费资源
        }
        Star.prototype.sing = function () {
            console.log('我会唱歌');
        }
        var ldh = new Star('李德华', 18);
        var zxy = new Star('张学友', 20);
        ldh.sing();//我会唱歌
        zxy.sing();//我会唱歌

一般情况下,我们的公共属性定义到构造函数里面,公共的方法我们放到原型对象身上

2.对象原型__proto__

对象都会有一个属性__proto__指向构造函数prototype原型对象,之所以我们对象可以使用构造函数prototype原型对象的属性和方法,就是因为对象有__proto__原型存在
在这里插入图片描述
在这里插入图片描述

  • __proto__对象原型和原型对象prototype是等价的
  • __proto__对象原型的意义就是在于为对象的查找机制提供一个方法,或者说一条线路,但是它是一个非标准属性,因此实际开发中,不可以使用这个属性,它只是内部指向原型对象prototype

在这里插入图片描述

3.constructor构造函数

对象原型(proto)和构造函数(prototype)原型对象里面都有一个属性constructor属性,constructor我们称为构造函数,因为它指回构造函数本身

constructor主要用于记录该对象引用哪个构造函数,它可以让原型对象重新指向原来的构造函数
在这里插入图片描述
构造函数、实例、原型对象三者之间的关系:
在这里插入图片描述

4.原型链

  1. 只要是对象就有__proto__原型,指向原型对象
  2. Star构造函数里面的原型对象(prototype)里面的__proto__原型指向的是object.prototype
    在这里插入图片描述

所以这就构成了原型链:
在这里插入图片描述

正因为有了原型链,我们有了JavaScript的成员查找机制(规则):

  1. 当访问一个对象的属性(包括方法)时,首先查找这个对象自身有没有该属性
  2. 如果没有就查找它的原型(也就是__proto__指向的prototype原型对象
  3. 如果还没有就查找原型对象的原型(object的原型对象)
  4. 依次类推一直找到object为止(null)
  5. __proto__对象原型的意义就在于为对象成员查找机制提供一个方法,或者说一条路线
    在这里插入图片描述
    在这里插入图片描述

5.原型对象中的this指向

原型对象函数里面的this指向的是实例对象
在这里插入图片描述

6.扩展内置对象

可以通过原型对象,对原来的内置对象进行扩展自定义方法。比如给数组增加自定义求偶数和的功能

注意:数组和字符串内置对象不能给原型对象覆盖操作Array.prototype = {},只能是Array.prototype.xxx = function(){}的方式

原型对象的应用

Array.prototype.sum = function(){
           var sum = 0;
           for (var i = 0; i < this.length; i++){
               sum += this[i];
           }
           return sum;
       }
       var arr = [1,2,3];
       console.log(arr.sum());//6
       console.log(Array.prototype);//就可以看到sum方法被加到Array原型上

在这里插入图片描述

7.继承

ES6之前并没有给我们提供extends继承,我们可以通过构造函数+原型对象模拟实现继承,被称为组合继承

  • 我们首先需要了解call()

call函数最主要的作用:调用这个函数,并且修改函数运行时的this指向

fun.call(thisArg,arg1,arg2....)

thisArg:当前调用函数this 的指向
arg1,arg2:传递的其他参数
在这里插入图片描述

  • 借用构造函数继承父类型属性

核心原理:通过call()把父类型的this指向子类型的this,这样就可以实现子类型继承父类型的属性
在这里插入图片描述
在这里插入图片描述
原型题目:
在这里插入图片描述

四.执行上下文

js执行上下文:js代码在执行前,js引擎总要做一番工作,这份工作其实就是创建对应的执行上下文
执行上下文有且只有三类:全局执行上下文、函数上下文、与eval上下文
1.全局执行上下文

  • 在执行全局代码前将window确定为全局执行上下文
  • 对全局数据进行预处理:
    var定义的全局变量:window为其赋值为undefined
    function声明的全局函数:window为其赋值为fun
    this:window为其赋值
  • 开始执行全局代码

全局对象window上预定义了大量的方法和属性,我们在全局环境的任意处都能直接访问这些属性方法,同时window对象还是var声明的全局变量的载体。我们通过var创建的全局对象,都可以通过window直接访问。
2.函数执行上下文

函数执行上下文可存在无数个,每当一个函数被调用时都会创建一个函数上下文;需要注意的是,同一个函数被多次调用,都会创建一个新的上下文。
在这里插入图片描述
说到这你是否会想,上下文种类不同,而且创建的数量还这么多,它们之间的关系是怎么样的,又是谁来管理这些上下文呢,这就不得不说说执行上下文栈了。

3.执行上下文栈
执行上下文栈(下文简称执行栈)也叫调用栈,执行栈用于存储代码执行期间创建的所有上下文。

  • 在全局代码执行前,js引擎就会创建一个栈来存储管理所有的执行上下文对象
  • 在全局执行上下文(window)确定后将其添加到栈中(压栈)
  • 在函数执行上下文创建后,将其添加到栈中(压栈)
  • 在当前函数执行完后,将栈顶的对象移除(出栈)
  • 当所有的代码执行完后,栈中只剩下window
    在这里插入图片描述

五.作用域

1.作用域

1.什么是作用域
就是一块独立“地盘”,一个代码段所在的区域
它是静态的(相对于上下文对象),在编写代码时就确定了
2.作用域分为:全局作用域、函数作用域、没有块作用域(ES6有了)
3.作用域的作用:隔离变量,不同作用域下同名变量不会有冲突
在这里插入图片描述
定义几个函数+1(全局作用域) = 几个作用域

2.作用域和上下文的区别

  • 区别1:
    1.全局作用域之外,每个函数都会创建自己的作用域,作用域在函数定义时就已经确定了。而不是在函数调用时
    2.全局执行上下文环境是在全局作用域确定之后,而作用域是js代码马上执行之前创建
    3.函数执行上下文是在调用函数时,而作用域是函数体代码执行之前创建
  • 区别2
    1.作用域是静态的,只要函数定义好了就一直存在,且不会再变化
    2.执行上下文是动态的,调用函数时创建,函数调用结束时就会自动释放
    两者之间的联系:
    1.上下文环境(对象)是从属于所在的作用域
    2.全局上下文环境->全局作用域
    3.函数上下文环境->对应的函数使用域

3.作用域链

多个上下级关系的作用域形成的链,它的方向是从下向上的(从内到外),并且查找变量时就是沿着作用域链来查找的
向上一级一级的查找

六.闭包

高阶函数:是对其函数进行操作的函数,它接收函数作为参数或将函数作为返回值输出
在这里插入图片描述
在学习闭包之前,先看下变量作用域
变量作用域的不同分为两种:全局变量和局部变量
1.函数内部可以使用全局变量
2.函数外部不可以使用局部变量
3.当函数执行完毕,本作用域内的局部变量会销毁

什么是闭包
闭包指有权访问另一个函数作用域中变量的函数
简单理解就是,一个作用域可以访问另外一个函数内部的局部变量
闭包的主要作用:延伸了变量的作用范围
在这里插入图片描述
在这里插入图片描述
闭包的生命周期
产生:在嵌套内部函数定义执行完时就产生了(不是在调用)
死亡:在嵌套的内部函数称为垃圾对象时
闭包的应用:定义js模块
1.具有特定功能的js文件
2.将所有的数据和功能都封装在一个函数内部(私有的)

七.正则表达式

什么是正则表达式:是用于匹配字符串中字符组合模式。在JavaScript中,正则表达式也是对象
可以用正则表达式完成表单验证
创建正则表达式
在这里插入图片描述

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值