js变量,运算符,预编译

    xiaoxiao2025-02-25  71

    JavaScript简介

    JavaScript 是一种轻量级的编程语言。JavaScript 是可插入 HTML 页面的编程代码。JavaScript 插入 HTML 页面后,可由所有的现代浏览器执行。 JavaScript 由 Brendan Eich 发明。它于 1995 年出现在 Netscape 中(该浏览器已停止更新),并于 1997 年被 ECMA(一个标准协会)采纳。因此也可以叫ECMAScript.

    变量

    在JavaScript中,变量统一用var声明。 变量的取名有要求:

    变量名必须以英文字母、下划线 ‘-’、’$'开头。可以包含数字,但是作为不能开头。不能使用关键字、保留字作为变量名。

    变量可分为原始值和引用值。 原始值包括:Number(默认浮点型)、Boolean(true/false)、String(‘’/“”)、undefined(未声明)、null(空)。 引用值包括:array、object、function、data等。 原始值存于stack栈中,赋值方式为拷贝。(先进后出)。 引用值存于heap堆中,复制的是地址。

    举个栗子:

    var a = 10; var b = a; a = 20; Document.write(b);

    毫无疑问输出b为10;

    var ar = [1,2]; var ar1 = ar; ar = [1,3];/*开辟新的空间*/ console.log(ar1);

    然而ar1的值为1,2; 这就是两种值的存储方式不同造成的结果。

    运算符

    +、-、*、/、++、–

    + 除了数学计算中的加法功能外,还能用于字符串的连接。任何数据类型 **+**字符串都等与字符串。document.write(a++)代表先输出a,在++;++a 则是先计算再赋值。

    下面看一道栗子

    var a = 10; var b = ++a - 1 + a++;

    ++a为11,此时a为11,a先给a++赋值,此时a++为11,a为12. 输出b的值为21

    <、>、==

    比较后输出布尔值。当“a”<"b"成立时,返回true。 而==代表判断是否相等,当字符串类型1与数字类型1比较时判断为正确。 而有绝对相等的符号 ===,此时只有当数据类型也相等时才能判断为相等。

    逻辑运算符

    逻辑运算符包括 && (与)、||(或)、!(非)。

    与运算的规则: 先看第一个表达式转换成布尔值的结果,如果结果为真, 那么会看第二个布尔值的结果,如果只有两个表达式, 只看到第二个表达式,就可以返回该表达式的值了。 如果第一个为假,则false。 全真才为真,一假则假。 var a = 1 && 2; document.write(a);

    a的值为2。

    或 && 可作为中断符,短路语句。&与运算 换成二进制再与运算。||遇真则返回。全假才为假。 可以用来写兼容。!取成布尔值再取反。

    这些运算符的操作数不一定是布尔型的。JavaScript会通过简单的转换规则,将一些非布尔类型的值转换成布尔型的。大多数的值都会转换成true,只有少数的是false,他们分别是:false, 0, -0, “”, NaN, null, undefined,因为存在数字和字符串以及对象的值为false,所以,直接用真值转换来判断一个函数的参数是否传进来了,这是不不太安全的。比如,有一个可以具有默认值得可选参数的函数,如下:

    function point(x, y) { if (!x) { x = 320; } if (!y) { y = 240; } return { x: x, y: y }; }

    这个函数会忽略任何的真值为假的参数的,包括0,-0;

    point(0, 0); // { x: 320, y: 240 }

    检测undefined的更加准确的方法是用typeof操作:

    复制代码

    function point(x, y) { if (typeof x === "undefined") { x = 320; } if (typeof y === "undefined") { y = 240; } return { x: x, y: y }; }

    复制代码 这种写法,可以区分开0和undefined的:

    point(); // { x: 320, y: 240 } point(0, 0); // { x: 0, y: 0 }

    数据类型

    typeof 确定数据类型 number string boolean object undefined function(函数)

    var num = true; console.log(typeof(num));

    输出得到boolean;

    也可以用如下格式 typeof 123

    不同于C语言,不同数据类型间可以进行加减运算。 如 ‘2’-1,或者‘2’-‘1’; constructor constructor 属性返回所有 JavaScript 变量的构造函数。 可以使用 constructor 属性来查看对象是否为数组 (包含字符串 “Array”),如下例:

    var fruits = ["Banana", "Orange", "Apple", "Mango"]; document.getElementById("demo").innerHTML = isArray(fruits); function isArray(myArray) { return myArray.constructor.toString().indexOf("Array") > -1; }

    可以使用 constructor 属性来查看对象是否为日期 (包含字符串 “Date”):

    var myDate = new Date(); document.getElementById("demo").innerHTML = isDate(myDate); function isDate(myDate) { return myDate.constructor.toString().indexOf("Date") > -1; }

    类型转换

    在编译过程中,经常使用到强制类型转换,常见的有:

    Number(a) :将a强制转换为数字类型。ParseInt() :转换为整形。ParseFloat(string):将字符串转化成浮点。String(mix):转换成字符串。Boolean(mix):转换成布尔值。

    ParseInt() 还能实现进制转换 ParseInt(a,2):将二进制的a转换成十进制 相似的 toString能将十进制转化成多种进制。

    隐形类型转换

    在上文中,之所以不同的数据类型之间可以做运算,是因为JavaScript引擎在运算之前会悄悄的把他们进行了隐式类型转换的,如下是数值类型和布尔类型的相加:

    3 + true; // 4

    结果是一个数值型! 如果是在C语言中,上面的运算肯定会因为运算符两边的数据类型不一致而导致报错的!但是,在JavaScript中,只有少数情况下,错误类型才会导致出错,比如调用非函数,或者读取null或者undefined的属性时,如下:

    "hello"(1); // error: not a function null.x; // error: cannot read property 'x' of null

    多数情况下,JavaScript都不会出错的,而是自动的进行相应的类型转换。比如-, *, /,和%等算术运算符都会把操作数转换成数字的,但是“+”号就有点不一样了,有些情况下,它是算术加号,有些情况下,是字符串连接符号,具体的要看它的操作数.

    JavaScript会自动把数字转换成字符的,不管数字在前还是字符串在前,字符串和数字相加结果是字符串.

    但是,隐式类型转换,有时候,会隐藏一些错误的,比如,null会转换成0,undefined会转换成NaN。需要注意的是,NaN和NaN是不相等的. 即任何值都不等于NaN,包括他自己。 因此利用这个性质,我们可以检测某个值是不是NaN。

    var a = NaN; a !== a; // true var b = "foo"; b !== b; // false var c = undefined; c !== c; // false var d = {}; d !== d; // false var e = { valueOf: "foo" }; e !== e; // false

    预编译

    js作为一种翻译性语言,编译一行,执行一行。但编译前,js还对整篇进行了一次预编译。为了了解预编译,我们需要认识js运行的大致流程。

    js运行过程

    语法分析,就是检查你的代码有没有什么低级的语法错误;预编译 ,简单理解就是在内存中开辟一些空间,存放一些变量与函数 .解释执行,顾名思义便是执行代码了;

    一般来说,预编译在script代码内执行前发生, 但是它大部分会发生在函数执行前。

    让我们找些实例分析。

    全局预编译

    <script> var a = 1; console.log(a); function test(a) { console.log(a); var a = 123; console.log(a); function a() {} console.log(a); var b = function() {} console.log(b); function d() {} } var c = function (){ console.log("I at C function"); } console.log(c); test(2); </script>

    页面产生便创建了GO全局对象(Global Object)(也就是window对象);

    第一个脚本文件加载;脚本加载完毕后,分析语法是否合法;开始预编译 查找变量声明,作为GO属性,值赋予undefined; 查找函数声明,作为 GO属性,值赋予函数体; //查找变量 GO/window = { a: undefined, c: undefined, test: function(a) { console.log(a); var a = 123; console.log(a); function a() {} console.log(a); var b = function() {} console.log(b); function d() {} } }

    接下来开始解释执行语句

    //抽象描述

    GO/window = { a: 1, c: function (){ console.log("I at C function"); } test: function(a) { console.log(a); var a = 123; console.log(a); function a() {} console.log(a); var b = function() {} console.log(b); function d() {} } }

    在执行函数语句之前,也存在预编译过程

    创建AO活动对象(Active Object);查找形参和变量声明,值赋予undefined;实参值赋给形参;查找函数声明,值赋予函数体;

    预编译之前面1、2两小步如下:

    AO = { a:undefined, b:undefined, }

    第三步

    AO = { a:2, b:undefined, }

    第四步

    AO = { a:function a() {}, b:undefined d:function d() {} }

    执行函数时

    AO = { a:function a() {}, b:undefined d:function d() {} } ---> AO = { a:123, b:undefined d:function d() {} } ---> AO = { a:123, b:function() {} d:function d() {} }

    预编译阶段发生变量声明和函数声明,没有初始化行为(赋值),匿名函数不参与预编译 ; 只有在解释执行阶段才会进行变量初始化 ; 预编译小结 预编译两个小规则

    以上用图示表示:

    函数声明整体提升-(具体点说,无论函数调用和声明的位置是前是后,系统总会把函数声明移到调用前面)变量 声明提升-(具体点说,无论变量调用和声明的位置是前是后,系统总会把声明移到调用前,注意仅仅只是声明,所以值是undefined)

    预编译前奏

    imply global 即任何变量,如果未经声明就赋值,则此变量就位全局变量所有。(全局域就是Window)一切声明的全局变量,全是window的属性; var a = 12;等同于Window.a = 12; 函数预编译发生在函数执行前一刻。

    案例分析 题1:

    //预编译:GO -> {fn: function () {}} //解释执行:{fn()} function fn (a) { //执行函数fn前预编译:AO -> {a: function () {}, b: undefined[因为函数b()为函数表达式],d: function () {}} console.log(a); //控制台显示function a () {} var a = 123; console.log(a); //控制台显示123 function a () {}; console.log(a); //控制台显示123 console.log(b); //控制台显示undefined var b = function () {}; console.log(b); //控制台显示function () {} console.log(d); //控制台显示function d () {} function d () {}; } fn(1);

    题2:

    //预编译:GO -> {test: functiong () {}} //解释执行:{test()} function test (a, b) { //执行函数test前预编译:AO -> {a: 1[因为外部实参传入], b: function () {},d:function () {}} console.log(a); //控制台显示1 a = 3; console.log(b); //控制台显示function b () {} b = 2; //解释执行函数test:{b: 2} console.log(b); //控制台显示2 function b () {}; function d () {}; console.log(b); //控制台显示2,因为b已是变量并被赋值 //解释执行函数test:{d: function () {}} console.log(d); } test(1);
    最新回复(0)