前端(JavaScript)------变量和内置对象

简介: 在编码过程中,其保存的值可以发生改变的量称为变量。我们已经对变量十分熟悉了,但是我们今天来讨论一下变量的一些使用问题。

1.变量

(1)变量提升

      在编码过程中,其保存的值可以发生改变的量称为变量。我们已经对变量十分熟悉了,但是我们今天来讨论一下变量的一些使用问题。先来看看下面的一段代码:

  console.log(num);
   var num = 1;

      很显然,上面这段代码中输出语句被写在了变量的初始化之前。按照html的规则这段代码肯定无法正常运行的,因为在输出num变量的时候变量还没有被赋初值。

 但是事实并不是如此,从浏览器中我们能够直观的看到输出结果是undefined。

原因:

  JavaScript引擎的工作方式是,先解析代码,获取所有被声明的变量,然后再一行一行地运行。这造成的结果就是所有的变量的声明语句都会被提升到代码的头部。JavaScript的这种读取变量的机制就叫做变量提升

       所以上面一段代码实际上在执行的时候是下面的过程:

        var num;
                     console.log(num);
                     num = 1;    //最后的结果是显示undefined,表示变量a已声明,但还未赋值。

ps:变量提升只对var命令声明的变量有效,如果一个变量不是用var命令声明的,就不会发生变量提升。

(2)变量作用域

  用var声明的变量:

       console.log(num);
               var num = 1;//undefined

   不用var声明的变量:

   console.log(num);
                 num = 1;//error!

 很明显的区别,不使用var声明的变量在使用时被系统识别为错误。这是因为javascript中存在一个叫做局部变量的东西:

 var声明的变量称为局部变量。

 局部变量仅在其所在的函数范围内生效,变量生效的范围被称为变量作用域。

而变量如果不适用var来声明,则表示变量在整个文件内生效。即全局变量。

(3)一等公民

     在很多传统语言(C/C++/Java/C#等)中,函数都是作为一个二等公民存在,你只能用语言的关键字声明一个函数然后调用它,如果需要把函数作为参数传给另一个函数,或是赋值给一个本地变量,又或是作为返回值,就需要通过函数指针(function pointer)代理(delegate)等特殊的方式周折一番。
 但是
JavaScript世界中函数却是一等公民,它不仅拥有一切传统函数的使用方式(声明和调用),而且可以做到像简单值一样赋值、传参、返回这样的函数也称之为第一级函数First-class Function)或一等公民。不仅如此,JavaScript中的函数还充当了类的构造函数的作用,同时又是一个Function类的实例(instance)。这样的多重身份让JavaScript的函数变得非常重要。

简化总结:

       JavaScript的函数与其他数据类型(数值、字符串、布尔值等等)处于同等地位,可以使用其他数据类型的地方就能使用函数。

     比如,可以把函数赋值给变量和对象的属性,也可以当作参数传入其他函数,或者把函数作为函数的结果返回。

     将函数赋值给变量:
    var func1 = function(){};
  将函数赋值给对象的属性:
    var frank = { ability:null };
    frank.ability = function(){console.log("吃");};
    frank.ability();//吃
  将函数作为参数传入其他函数:
    function introduce(Func){Func();} 
        function sayHello(){console.log(“hello”);}  
        introduce(sayHello);//hello
  将函数作为函数的结果返回:
    function jiSuanQi(){ return sum(4,10);} 
        function sum(num1,num2){ return num1+num2; }  
        console.log(jiSuanQi());//14

(4)函数名提升

     JavaScript引擎将函数名视同变量名,所以采用function命令声明函数时,整个函数会像变量声明一样,被提升到代码头部。

      qiuHe(1,2);
      function qiuHe(a,b) { console.log(a+b); }        //3

ps:只有function声明的函数会发生函数名提升,而如果通过赋值语句写的函数则不会。

       qiuHe(1,2);
       var qiuHe = function(a,b){ console.log(a,b); };       //qiuHe is not a function

(5)函数内的变量提升

      与全局作用域一样,函数作用域内部也会产生“变量提升”现象。var命令声明的变量,不管在什么位置,变量声明都会被提升到函数体的头部。

  function foo(x) {
        if (x > 100) {
          var tmp = x - 100;
       }
  }
  function foo(x) {
          var tmp;
          if (x > 100) {
                tmp = x - 100;
        };
  }

(6)*函数参数的默认值

function func(num){
        num = num || 1;  // num默认值为1
        return num;
  }
  func() // 1

      这种写法会对函数参数num进行一次布尔运算,只有为true时才会返回num。避免了因为忘写参数而导致的函数调用失败问题。

      可是除了undefined以外0、空字符、null等的布尔值也是false。也就是说,在上面的函数中,不能让num等于0或空字符串,否则在明明有参数的情况下,也会返回默认值1

  func('') // 1
            func(0) // 1

2.内存

   

      JavaScript内存相关的知识有太多,像内存管理内存回收内存分配等不是一两天就能够介绍完毕并掌握的,因此今天我们并不对内存本身作过多的介绍。

    我们今天主要学习的是从javascript内存总结延展出来的一些应用和规律。对于内存本身的知识,我们随着不断地深入学习会逐渐学习到。

(1)【值传递地址传递

原始数据类型(数值、字符串、布尔值)的内容传递方式是值传递(pass by value)

 而复合数据类型(数组、对象、其他函数)的内容传递是地址传递(pass by reference)

  var num1 = 123;        var num2 = num1;
  num2 = 456;               console.log(num1);           console.log(num2);

2345_image_file_copy_1.jpg

      num1num2 复制基本类型的值的时候,会在第二行创建一个新值(num2),然后把该值复制到num2上。

      两个变量可以参与任何操作而不会互相影响,因为从内存上来讲num1num2已经是两个完全不同的变量了。

var frank = { age : 18 };                传入函数的实际上是frank对象的内存地址。
function func(obj) {                     因此在函数内部修改参数,
  obj.age = 17;                         
}                                        将会影响到frank对象本身。
func(frank);
console.log(frank.age)   //17

2345_image_file_copy_2.jpg

(2)函数的同名参数

如果函数有同名的参数,则取最后出现的那个参数值。
  function func(num, num) {
    console.log(num);
  }
  func(1, 2)        // 2
  如果函数没有提供第二个参数,num的取值就变成了undefined
  function func(num, num) {
    console.log(num);
  }
  func(1)          // undefined
原则上来讲:尽量不要写同名参数,而且定义函数的时候写了几个参数,在调用的时候尽量保证和定义时一致。

(3)arguments对象

由于JavaScript允许函数有不定数目的参数,所以我们需要一种机制来在函数体内部读取所有参数。这就是arguments对象的由来。

 arguments对象包含了函数运行时的所有参数。

 arguments[0]就是函数的第一个参数,arguments[1]是第二个,以此类推。这个对象只有在函数内部才可以使用。

  var func = function(one) {
                console.log(arguments[0]);
                 console.log(arguments[1]);
                 console.log(arguments[2]);
  }
  func(1, 2, 3);

 能够看到,尽管在函数被声明的时候并没有多个参数。但是在函数运行的时候有三个参数,因此arguments对象便能够获取到这三个参数。

arguments对象除了可以读取参数,还可以为参数赋值
  var func = function(a, b) {
    arguments[0] = 3;
    arguments[1] = 2;
    return a + b;
  }
  console.log(func(1, 1)); // 5
当然也可以通过arguments对象length属性,判断函数调用时究竟带几个参数
  function func() {
    return arguments.length;
  }
  f(1, 2, 3)   // 3
  f(1)        // 1
  f()        // 0

需要注意的是,虽然arguments很像数组,但它是一个对象。

数组专有的方法(比如slice),不能在arguments对象上直接使用。

(4)eval函数

    eval() 函数可计算某个字符串,并执行其中的的 JavaScript 代码。

       (eval命令的作用是,将字符串当作语句执行。)

 语法:eval(string)

      该方法只接受原始字符串作为参数,如果 string 参数不是原始字符串,那么该方法将不作任何改变地返回。因此请不要为 eval() 函数传递 String 对象来作为参数。

  eval('var num = 100;');
  console.log(num);       // 100

ps:如果eval函数在使用的过程中发生了非法调用或者传入参数出错,则会抛出异常。

pss:虽然 eval() 的功能非常强大,但在实际使用中用到它的情况并不多。

(5)instanceof类型检测

typeof用来检测基本数据类型简直是神器,但是如果是引用数据类型,则需要使用instanceof操作符。
  instanceof 用于判断一个变量是否某个对象的实例。
  var arr = new Array();
  console.log(arr instanceof Array);     //true
  console.log(arr instanceof Object);    //true(Array 是 object 的子类)
  上面我们强调了arguments是一个对象。
  在这里我们可以用instaceof测试会发现 arguments不是一个Array对象,尽管看起来很像。
  function func() {
    console.log(arguments instanceof Array);        //false
    console.log(arguments instanceof Object);       //true
  }
  func();

(6)javascript垃圾回收机制

对于其他语言来说,如C,C++,需要开发者手动的来跟踪并管理内存。

 而JS的垃圾回收机制使得JS开发人员无需再关系内存的情况,所有的内存分配以及回收都会由垃圾回收器自动完成,执行环境会对执行过程中占有的内存负责。

 其原理就是找出那些不在被使用的变量,然后释放其所占有的内存。回收器一般是按照固定的时间间隔或者预设的时间进行处理的。

function test1(){
      var item = { name:'frank' };
  }
  function test2(){
       var item = { name:'frank' };
       return item;
  }
      var m1 = test1();
      var m2 = test2(); 
目录
相关文章
|
12月前
|
JavaScript 前端开发 API
|
12月前
|
前端开发 JavaScript 数据可视化
58K star!这个让网页动起来的JS库,前端工程师直呼真香!
Anime.js 是一款轻量级但功能强大的JavaScript动画引擎,它能够以最简单的方式为网页元素添加令人惊艳的动效。这个项目在GitHub上已经获得58,000+星标,被广泛应用于电商页面、数据可视化、游戏开发等场景。
445 8
|
资源调度 JavaScript 前端开发
前端开发必备!Node.js 18.x LTS保姆级安装教程(附国内镜像源配置)
本文详细介绍了Node.js的安装与配置流程,涵盖环境准备、版本选择(推荐LTS版v18.x)、安装步骤(路径设置、组件选择)、环境验证(命令测试、镜像加速)及常见问题解决方法。同时推荐开发工具链,如VS Code、Yarn等,并提供常用全局包安装指南,帮助开发者快速搭建高效稳定的JavaScript开发环境。内容基于官方正版软件,确保合规性与安全性。
12773 23
|
JSON 自然语言处理 前端开发
【01】对APP进行语言包功能开发-APP自动识别地区ip后分配对应的语言功能复杂吗?-成熟app项目语言包功能定制开发-前端以uniapp-基于vue.js后端以laravel基于php为例项目实战-优雅草卓伊凡
【01】对APP进行语言包功能开发-APP自动识别地区ip后分配对应的语言功能复杂吗?-成熟app项目语言包功能定制开发-前端以uniapp-基于vue.js后端以laravel基于php为例项目实战-优雅草卓伊凡
675 72
【01】对APP进行语言包功能开发-APP自动识别地区ip后分配对应的语言功能复杂吗?-成熟app项目语言包功能定制开发-前端以uniapp-基于vue.js后端以laravel基于php为例项目实战-优雅草卓伊凡
|
JavaScript 前端开发 开发者
JavaScript基础——JavaScript变量名称命名规范
JavaScript变量命名规范是编写高质量代码的重要部分。通过遵循基本规则、使用常见命名约定并应用最佳实践,可以提高代码的可读性和可维护性。希望本文能帮助开发者在日常编程中更好地理解和应用JavaScript变量命名规范,从而编写出更清晰、更可靠的代码。
845 11
|
前端开发
【2025优雅草开源计划进行中01】-针对web前端开发初学者使用-优雅草科技官网-纯静态页面html+css+JavaScript可直接下载使用-开源-首页为优雅草吴银满工程师原创-优雅草卓伊凡发布
【2025优雅草开源计划进行中01】-针对web前端开发初学者使用-优雅草科技官网-纯静态页面html+css+JavaScript可直接下载使用-开源-首页为优雅草吴银满工程师原创-优雅草卓伊凡发布
654 1
【2025优雅草开源计划进行中01】-针对web前端开发初学者使用-优雅草科技官网-纯静态页面html+css+JavaScript可直接下载使用-开源-首页为优雅草吴银满工程师原创-优雅草卓伊凡发布
|
JavaScript 前端开发 容器
盘点JavaScript中所有声明变量的方式及特性
本文详细介绍了JavaScript中变量定义的多种方式,包括传统的`var`、`let`和`const`,以及通过`this`、`window`、`top`等对象定义变量的方法。每种方式都有其独特的语法和特性,并附有代码示例说明。推荐使用`let`和`const`以避免作用域和提升问题,谨慎使用`window`和`top`定义全局变量,不建议使用隐式全局变量。掌握这些定义方式有助于编写更健壮的JS代码。
389 11
|
JavaScript 前端开发 Java
springboot解决js前端跨域问题,javascript跨域问题解决
本文介绍了如何在Spring Boot项目中编写Filter过滤器以处理跨域问题,并通过一个示例展示了使用JavaScript进行跨域请求的方法。首先,在Spring Boot应用中添加一个实现了`Filter`接口的类,设置响应头允许所有来源的跨域请求。接着,通过一个简单的HTML页面和jQuery发送AJAX请求到指定URL,验证跨域请求是否成功。文中还提供了请求成功的响应数据样例及请求效果截图。
313 3
springboot解决js前端跨域问题,javascript跨域问题解决
|
缓存 前端开发 JavaScript
JavaScript前端路由的实现原理及其在单页应用中的重要性,涵盖前端路由概念、基本原理、常见实现方式
本文深入解析了JavaScript前端路由的实现原理及其在单页应用中的重要性,涵盖前端路由概念、基本原理、常见实现方式(Hash路由和History路由)、优点及挑战,并通过实际案例分析,帮助开发者更好地理解和应用这一关键技术,提升用户体验。
679 1
|
JavaScript 前端开发
揭开JavaScript变量作用域与链的神秘面纱:你的代码为何出错?数据类型转换背后的惊人秘密!
【8月更文挑战第22天】JavaScript是Web开发的核心,了解其变量作用域、作用域链及数据类型转换至关重要。作用域定义变量的可见性与生命周期,分为全局与局部;作用域链确保变量按链式顺序查找;数据类型包括原始与对象类型,可通过显式或隐式方式进行转换。这些概念直接影响代码结构与程序运行效果。通过具体示例,如变量访问示例、闭包实现计数器功能、以及动态表单验证的应用,我们能更好地掌握这些关键概念及其实践意义。
129 0