专栏首页前端与Java学习JavaScript高级语法补充(函数参数传递、in delete关键字、比较运算符隐式转换)
原创

JavaScript高级语法补充(函数参数传递、in delete关键字、比较运算符隐式转换)

01-js高级语法补充

1.1-值类型与引用类型复习

1.值类型 (5种):  栈中存储的是数据,赋值时拷贝的也是数据。修改拷贝后的数据对原数据没有影响。

2.引用类型(2种) : 栈中存储的是地址,数据在堆中,赋值时拷贝的也是地址。修改拷贝后的数据对原数据有影响的。

<script>
        //1.值类型
        var num1 = 10;
        var num2 = num1;
        num2 = 20;
        console.log(num2);//20
        console.log(num1);//10

        //2.引用类型
        var arr1 = [10,20,30];
        arr2 = arr1;
        arr2[0] = 100;
        console.log(arr2);//[100,20,30]
        console.log(arr1);//[100,20,30]
</script>

==1.2-参数传递==

ECMAScript中所有的函数的参数都是按值传递的,也就是说,把函数外部的值复制给函数内部的参数,就和把值从一个变量复制到另一个变量一样。基本类型值的传递如同基本基本类型变量的复制一样,而引用类型值的传递,如同引用类型变量的复制一样。有不少开发人员会在这一点上感到困惑,因为访问变量有按值和按引用两种方式,而参数只能按值传递。

在向参数传递基本类型的值时,被传递的值会被复制给一个局部变量(arguments对象中的一个元素),在向参数传递引用数据类型的值时,会把这个值在内存中的地址复制给一个局部变量,因此这个局部变量的变化会反映在函数的外部 --《JavaScript高级程序设计》以上都是书中原话

在读到《JavaScript高级程序设计》的4.1.3参数传递这一章的时候十分困惑,书中例举了几个案例来说明传递参数都是按值传递的

function addTen(num){
    num+=10;
    return num;
}
var count = 20;
var result = addTen(count);
console.log(count)//20 没有变化
console.log(result)//30

以上这个案例传递的是基本数据类型很好理解,num传递的是值不会影响函数外部变量count,他们仅仅具有相同的值。

但是我们接着使用对象,那就不那么好理解了:

function setName(obj){
    obj.name = "Nicholas";
}
var person = new Object();
setName(person);
console.log(person.name);//“Nicholas”

以上代码创建了一个对象保存在了变量person中,然后将对象传入setName()函数中之后就被复制给了obj,在这个函数内部,obj和person引用的是同一个对象,换句话说,即使这个变量是按值传递的,obj也会按照引用来访问同一个对象。于是当在函数内部修改了obj的name属性后,函数外部的person也将有所反映;到这里很多人会认为在局部作用域中修改的对象会在全局作用域中反应出来,说明参数是按引用传递的,至此书中又举了一个经过修改后的例子:

function setName(obj){
    obj.name = "Nicholas";
    obj = new Object();
    obj.name = "Greg";
}
var person = new Object();
setName(person);
console.log(person.name);//“Nicholas”

这个例子在吧person传递给setName()后其name属性被设置为Nicholas然后又将一个新对象赋值给了obj,同时将其name改为了“Greg”,如果person是按引用传递的,那么person就会自动被修改为指向其name属性值为“Greg”的新对象,但是接下来访问的时候person.name依旧是"Nicholas"。这说明即使在函数内部修改了参数的值,但原始的引用仍然保持不变。实际上,当函数内部重写obj时,这个变量引用的就是一个局部对象了,而这个局部对象会在函数执行完毕后立即被销毁。


以上就是《JavaScript高级程序设计》对函数传递参数的说明,但是还是很难理解向参数传递引用类型的值时是按值传递的的。这里我的理解是函数的参数都是按值传递的,传Object类型也是一样,只不过这个值是地址值,也就是说函数的参数传递的都是栈空间中的值(值类型的值就是数据,引用类型的值就是地址)上面的代码我是这么理解的:

我们把person的地址值传递给obj后,obj和person都指向了堆内存中的同一块地址(假设是a地址),所以这里对obj进行添加或者删除属性的操作,都是在a地址上操作的,所以相应的变化会反映在person对象上。

那么,当对obj重新赋值(新的地址b),这个时候就切断了obj和a地址之间的联系,所以对obj上的任何操作也不会反映到person对象上。如果函数的参数是按引用传递的话,person也会指向地址b,然而事实上person指向的是地址a

所以:引用类型传递,传递的是地址的值,修改成员对象会影响原对象,但对变量重新赋值,不会影响原对象

1.3-in关键字三个作用

<script>
        //1.for-in循环遍历对象属性
        var person = {
            name: '张三',
            age: 38
        };

        for (var key in person) {
            console.log(key);//获取对象属性名字符串
            console.log(person[key]);
        };

        //2.判断对象是否 包含 某个属性
        var student = {
            name: '班长',
            age: 38,
            sex: '男'
        };

        console.log("name" in student)//true
        console.log("age" in student)//true
        console.log("sex" in student)//true
        console.log("girlFriend" in student)//false

        //3.判断数组是否 包含 某个下标
        var arr = [10, 20, 30, 40, 50];
        console.log(5 in arr);//false
        console.log(4 in arr);//true
        console.log(0 in arr);//true

        //如何判断数组中是否包含某个元素
        console.log(arr.indexOf(10));//0    如果有则返回该元素下标
        console.log(arr.indexOf(100));//-1  如果没有则返回固定值  -1    
</script>

1.4-delete关键字两个作用

<script>
        //delete关键字两个作用

        //1.删除对象的属性 : delete 对象名.属性名

        /*对象的属性既可以动态添加,也可以动态删除*/
        var person = {
            name: '班长',
            sex: '男'
        }
        person.girlFriend = '苍老师';//动态添加属性
        delete person.sex;//动态删除属性
        console.log(person);

        //2.删除没有使用var声明的变量   ( 有var声明的delete删除无效 )

        num = 10;
        delete num;
    // console.log ( num );//程序报错num is not defined
</script>

1.5-比较运算符隐式转换

1.复习隐式转换 : 运算符在运算的时候,如果两边的数据类型不一致,则会自动转成一致后运算。

  • a. 其他类型转string :  + 连接符
  •             b. 其他类型转number :  
    •                 自增自减(++ --)
    •                 算术运算符( + - * / %)
    •                 关系运算符 :  > >= < <= == != === !==
  •             c. 其他类型转boolean :  ! 逻辑非

2. 特殊情况

  •             === : 全等运算符。 不存在类型转换, 先比较类型,然后比较值
  •             ==  :  比较运算符。 隐式转换规则是转成number,但是有前提条件

3. x == y: 比较运算符分为五种情况

  •             3.1 x和y 都为 null或undefined
    •                 * 不会类型转换,得到固定值true
  •             3.2 x或y 为NaN 
    •                 * 不会类型转换,得到固定值false  (NaN与任何数据都不等,包含自身)
  •             3.3 x和y 都为 string,boolean,number ,且类型不一致
    •                 * 会类型转换, 会把其他类型转成number后计算
  •             3.4 x或y 为引用类型 (一个是引用类型,一个是值类型)
    •                 * 前提 : 引用类型会先调用valueOf(),然后调用toString(),再来计算  (最终变成字符串来比较)
      •                     * valueOf() : 一般引用类型,返回自身(一般忽略)
      •                     * toString() : 数组是join()字符串, 对象是固定字符串 '[object Object]'
  •             3.5 x和y 都为引用类型。 则会比较两者地址,地址一样则为true,否则为false

1. === : 全等运算符(不存在类型转换)

        // 严格匹配 : 数据类型 与 值 必须要同时相等
        console.log('1' === 1 );//false
        console.log( 1 === 1 );//true
        console.log( undefined === null );//false

2. == : 比较运算符 : 隐式转换是有前提条件的  ( x == y )

2.1 x和y  都为 null或者undefined

        // 不会类型转换,固定返回true
        console.log( Number(null) );//0
        console.log( Number(undefined) );//NaN
        console.log( null == null );//true
        console.log( undefined == undefined );//true
        console.log( null == undefined );//true   

2.2 x或y  为NaN 

        // 不会类型转换,固定返回false (NaN与任何数据都不等)
        console.log( NaN == 0 );//false
        console.log( NaN == undefined );//false
        console.log( NaN == null );//false
        console.log( NaN == NaN );//false

2.3 当x或y 都为 :string,number,boolean。 且数据类型不一致,此时会转换成number后运算

console.log( 1 == '1' );//true   1 == Number('1')
console.log( false == '0' );//true   Number(false) == Number('0')  0 == 0        

2.4 x或y 存在引用类型,则会转成 `原始值` 后比较

        //  一个是引用类型,一个是基本类型
        // 引用类型转原始值 : 先调用对象的valueOf() 方法获取原始值,然后调用toString() 转成字符串比较
        // a :  valueOf() : 可以忽略, 对象类型默认valueOf会返回自身
        console.log( [10,20,30].valueOf() );// [10,20,30]
        console.log( new Number(10) );//10  valueOf() 默认只会对基本包装类型有效
        // b1.   toString() :  数组的toString() 本质是调用join()转成字符串
        console.log( [10,20,30] == '10,20,30' );//true
        console.log( [] == '' );//true
        console.log( [] == 0 );//true  (1) [].toString  (2) '' == 0 (3) 0 == 0
        // b2.   toString() :  对象的toString() 返回固定格式字符串  '[object Object]'
        console.log( {name:'张三'} == '[object Object]');//true
        console.log( {name:'李四'} == '[object Object]');//true

以下是针对2.4的面试题的坑

        console.log( [] == 0 );//true
        //这里我们要了解其他类型转Boolean为false的几种情况:0、-0、null、undefined、false、NaN、""
        //(1)  ![] 隐式规则转布尔类型  !Boolean([]) =  !true = false
        //(2)  flase == 0
        //(3)  Number(false) == 0   0 == 0
        console.log( ![] == 0 );//true  
        console.log( {} == 0 );//false    '[object Object]' == 0
        console.log( !{} == 0 );//true   原理同  ![] == 0   不存在调用toString() 本质是逻辑非表达式结果 与 0 比较       

2.5 x或y  都为引用类型。则直接比较两者地址,地址一致则为true,地址不一致则为false

        var arr1 = [10,20,30];
        var arr2 = arr1;//拷贝地址 赋值
        var arr3 = [10,20,30];
        //虽然arr1 arr2 arr3打印的时候,一模一样的。但是他们对应的堆地址不同(钱一样银行卡不一样 )
        console.log(arr1 == arr2);//true
        console.log(arr1 == arr3);//false
        console.log(arr2 == arr3);//false        

以下是针对2.5的面试题的坑

        console.log( [] == [] );//false   声明两个空数组,堆中地址不同
        //(1)左边   ![] = !true = false
        //(2)右边   [].toString = ''
        //(3)false (数字0) == ''(数字0)
        console.log( ![] == [] );//true   
        console.log( ![] == ![] );//true  两个逻辑非表达式比较  !true == !true   false == false

        //原理同上
        console.log(  {} ==  {} );//false
        //(1)左边 !{} = !true = false
        //(2)右边 {}.toString = '[object Object]'
        //(3) false (数字0) == '[object Object]' (数字NaN)
        console.log( !{} ==  {} );//false  
        console.log( !{} == !{} );//true

以下为特殊情况

        // null是原型链终点, 底层是堆地址起点 0x0000
        console.log( null == 0);//false   null不会转换 ,会直接用地址 和 0 比较
        //以上五种情况 只是对 == 运算符生效。 其他的比较运算符还是转number
        console.log( null >= 0);//true  Number(null) >= 0   0 >= 0
        console.log( null <= 0);//true  Number(null) <= 0   0 <= 0

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 前端day11-JS学习笔记(构造函数、对象的API、作用域、arguments关键字)

    当我们想要创建多个对象时很容易造成代码冗余,那么我们可以使用函数或者自定义构造函数去创建对象。

    帅的一麻皮
  • JavaScript网页性能优化(函数防抖与函数节流)

    b.输入框事件:验证手机号或者邮箱,用户输入时不断触发键盘事件,应该等用户结束输入之后,以最后一次输入为准

    帅的一麻皮
  • ES6语法学习(变量的解构赋值)

    另一种情况是不完全解构:就是等号左边的模式只匹配一部分等号右边的数组,这样解构依然可以成功

    帅的一麻皮
  • javascript 闭包详解

    一、什么是匿名函数 创建一个函数并将它赋值给变量functionName,这种情况下创建的函数,即匿名函数。(函数表达式就是匿名函数) 二、闭包 1.什么是闭包...

    柴小智
  • JavaScript(四):运算符&数据类型转换

    +:算符的加法;连接字符串 加法会将其它类型的值,自动转为字符串,然后再进行连接运算! 1 var a=1+2; 2 console.log('first:...

    用户1149564
  • 9 个让 JavaScript 调试更简单的 Console 命令

    一、显示信息的命令 <!DOCTYPE html> <html> <head> <title>常用console命令</title> ...

    用户1667431
  • 好用-除了Console.log()之外的JS日志打印输出方式

    几乎所有的javascript开发者最常使用的日志打印调试api都是console.log(),其实还有很多的选项供我们选择,笔者下面就为大家一一介绍.

    字母哥博客
  • 还是只使用console.log()进行调试?好吧,其实还有更多。

    在浏览器控制台中打印消息无疑可以拯救所有开发人员。 console.log()消息就像您的大多数疾病的药,同时调试了代码中的一些有线问题。

    Tz一号
  • 【译】超越console.log() —当debug时你需要使用的8个console方法

    你debug时或许没有使用过的超越console.log()的console方法!

    腾讯IVWEB团队
  • JavaScript Console的常见用法

    行文过程中出现错误或不妥之处在所难免,希望大家能够给予指正,以免误导更多人,最后,如果你觉得我的文章写的还不错,希望能够点一下喜欢和关注,为了我能早日成为简书优...

    Nian糕

扫码关注云+社区

领取腾讯云代金券