• js 运算符 感叹号后置 是断言


    typescript变量名后面的感叹号是什么意思?

    ts的代码如下:

     let foo = () =>{
        let name = "alberto";
        return name!;
    }
    document.body.innerHTML = foo();
    

    编译成js后的代码如下:

     var foo = function () {
        var name = "alberto";
        return name;
    };
    document.body.innerHTML = foo();
    

    不理解name变量后面的感叹号是什么意思?

     
    感叹号(非空断言操作符) ,就你这个来说没有什么意义,因为name是常量,如果name可能为空,可以用这个,如果为空,会丢出断言失败。

    Typescript中的as、问号与感叹号

    1、as关键字表示断言

    在Typescript中,表示断言有两种方式。一种是扩号表示法:

    let someValue: any = "this is a string";
    let strLength: number = (someValue).length;
    
    • 1
    • 2

    另一种使用as关键字:

    let someValue: any = "this is a string";
    let strLength: number = (someValue as string).length;
    
    • 1
    • 2

    2、问号(?)用于属性定义

    问号表示可选的属性,一般用于属性定义,如,用于接口时:

    interface SquareConfig {
        color?: string;
        width?: number;
    }
    function createSquare(config: SquareConfig) {
        if (config.clor) {
            console.log(config);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    可选属性的含义是:使用这个属性时,要么这个属性名不存在,要么必须符合属性的类型定义

    比如上述createSquare函数编译时会报error错误:

    error TS2551: Property 'clor' does not exist on type 'SquareConfig'.
    
    • 1

    如果修改createSquare,将config.color的值改为undefined,会怎样?

    interface SquareConfig {
        color?: string;
        width?: number;
    }
    function createSquare(config: SquareConfig) {
        config.color = undefined;
        if (config.color) {
            console.log(config);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    这时并没有编译报错!明明config.color定义的是string类型呀?

    即便是添加–strictNullChecks进行编译,也不会报错。可见,可选属性所定义的类型,并没有被typescript严格地对待,默认并不检查undefined。需要注意的是,将上述undefined改成null时,普通编译也不报错,–strictNullChecks编译会报如下错误:

    error TS2322: Type 'null' is not assignable to type 'string | undefined'
    
    • 1

    从这句报错中,我们可以得出这样的结论:可选属性等价于一个union类型,union了undefined;不加–strictNullChecks编译时,null可以赋值给undfined类型。也就是说,SquareConfig的定义与下面的代码等价:

    interface SquareConfig {
        color: string|undefined;
        width: number|undefined;
    }
    
    • 1
    • 2
    • 3
    • 4

    下面比较一下可选属性与正常属性。再次修改createSquare,将color属性修改为正常属性。

    interface SquareConfig {
        color: string;
        width?: number;
    }
    function createSquare(config: SquareConfig) {
        config.color = undefined;
        if (config.color) {
            console.log(config);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    以–strictNullChecks编译,报错了:

    error TS2322: Type ‘undefined’ is not assignable to type ‘string’

    这个比较也验证了上述的结论。

    问号(?)用于属性读取

    问号用于属性读取,主要有两个场景:一是读取数组元素(如下面的node[i]),二是读取不确定的类型如any,union,可选类型(如node[i].data)等。如下例,保存为index.ts:

    interface VNodeData {
        class?: string;
    }
    interface VNode {
        sel?: string;
        data?: VNodeData;
    }
    function test(node: VNode[]) {
        let i = 0;
        var b = node[i].data.class;
        if(b !== undefined) {
            console.log(1);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    用tsc --strictNullChecks index.ts,报错:.

    error TS2532: Object is possibly 'undefined'
    
    • 1

    下面将一一展示这一行代码var b = node[i].data.class;修改改后的效果。

    1、修改为var b = node[i]?.data.class;,然后编译。报错:

    Object is possibly 'undefined'
    
    • 1

    2、修改为var b = node[i]?.data?.class;,然后编译。编译通过,查看编译后的对应代码为:

    function test(node) {
        var _a, _b;
        var i = 0;
        var b = (_b = (_a = node[i]) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b["class"];
        // var b = node[i].data.class;//报错
        if (b !== undefined) {
            console.log(1);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    var b = node[i]?表示,如果node[i]的值为null或者undefined,则b等于undefined,否则b=node[i]。

    3、修改为var b = (node[i] as VNode).data?.class;,然后编译。编译通过,查看编译后的对应代码为:

    function test(node) {
        var _a;
        var i = 0;
        var b = (_a = node[i].data) === null || _a === void 0 ? void 0 : _a["class"];
        // var b = node[i]?.data?.class;
        // var b = node[i].data.class;//报错
        if (b !== undefined) {
            console.log(1);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    此时,使用node[i]时,Typescript编译器将不再对其判断是否为null和undefined。即:var b = node[i] as VNode直接会被编成var b = node[i]。

    4、修改为var b = node[i]!.data?.class,然后编译。编译通过,查看编译后的对应代码为:

    function test(node) {
        var _a;
        var i = 0;
        var b = (_a = node[i].data) === null || _a === void 0 ? void 0 : _a["class"];
        // var b = (node[i] as VNode).data?.class
        // var b = node[i]?.data?.class;
        // var b = node[i].data.class;//报错
        if (b !== undefined) {
            console.log(1);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    可见,3和4的编译后代码完全一样,!的作用此时与as是等价的。然而,!只是用来判断null和undefined;as则可用于变更(缩小或者放大都可以)类型检测范围,仅当as后面跟的类型是一个非空类型时,两者才等价。如下例中,不能将as用法改为!。

    interface Cat {
        action: string;
    }
    interface Dog {
        action: string;
    }
    type Animal = Cat | Dog;
    let action:Animal = {} as Cat;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    结论

    1、as和!用于属性的读取,都可以缩小类型检查范围,都做判空用途时是等价的。只是!具体用于告知编译器此值不可能为空值(null和undefined),而as不限于此。

    2、?可用于属性的定义和读取,读取时告诉编译器此值可能为空值(null和undefined),需要做判断。

    一、感叹号

    1. 一个感叹号

    一个感叹号(!)最好理解,也是我们经常使用的。!可以将变量转为boolean值,所有的truthy和falsy都可以被转化,比如null、undefined、数字0和空字符串取反都为true,其余都为false。

    !null = true
    !undefined = true
    !"" = true
    !0 = true
    !100 = false
    !"asdss" = false
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    注意:truthy和falsy不是true和false

    2. 两个感叹号

    两个感叹号(!!),学习时比较少见到,通常用来判断变量是不是truthy或者falsy,这么说好像和前面一样?不,一个感叹号只是单个判断比如只对null或者只对undefined,使用两个!!可以对所有truthy和falsy判断,比如:

    	let a; // null、undefined、''、0
        if (a !== null && typeof(a) !== "undefined" && 
            a !== undefined && a !== '' && a !== 0){
              //a为truthy时才执行,或者说a为真值时才执行
           }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    	let a;
    	if(!!a){
    	//a为truthy时才执行,或者说a为真值时才执行
    	}
    
    • 1
    • 2
    • 3
    • 4

    这两种方法的功能一样,但是明显下面一种更加简洁。

    好像还有三个!!!的,但是并没有什么用处。似乎是将1和2都做了一遍,然后回到原点。

    二、3个点(…)

    三个点用于传参时可以看作是Rest参数的逆运算,将一个数组转为用逗号分隔的参数数组,就是说将参数数组展开了传入函数中。

    let a = [1,2,3]
    function f(x1,x2,x3){
    	...
    }
    f(...a) // 等价于 f(1,2,3)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    Rest参数和arguments对象的区别:

    • rest参数只包括那些没有给出名称的参数,arguments包含所有参数
    • arguments 对象不是真正的数组,而rest 参数是数组实例,可以直接应用sort, map, forEach, pop等方法
    • arguments 对象拥有一些自己额外的功能

    当用于函数形参时,后面就不能有其他参数,如下将会报错

    function func(a, ...b, c) {
        // ...
    }
    // Rest parameter must be last formal parameter
    
    • 1
    • 2
    • 3
    • 4

    使用三个点,在许多时候可以代替数组的apply方法

    // ES6以前
    Math.max.apply(null, [22, 2, 222])
    // ES6
    Math.max(...[22, 2, 222])
    //  等价于
    Math.max(22, 2, 222);
  • 相关阅读:
    CString::GetLength()获得字节数
    Altium Designer 总线式布线
    Altium 原理图出现元件 “Extra Pin…in Normal of part ”警告
    编辑结束后收回键盘
    storybody中页面跳转
    改变tabBarItem颜色
    改变Button文字和图片的位置
    添加视图模糊效果(高斯模糊)
    ios开发获取SIM卡信息
    IOS 清除UIWebview的缓存以及cookie
  • 原文地址:https://www.cnblogs.com/bigben0123/p/13883618.html
Copyright © 2020-2023  润新知