博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
《你不知道的Javascript--中卷 学习总结》(原生函数、强制类型转换)
阅读量:6963 次
发布时间:2019-06-27

本文共 9878 字,大约阅读时间需要 32 分钟。

原生函数

1、常见的原生函数有:

  • String()
  • Number()
  • Boolean()
  • Array()
  • Object()
  • Function()
  • RegExp()
  • Date()
  • Error()
  • Symbol() --- ES6中新加入的

2、所有typeof返回值为"object"的对象(如数组)都包含一个内部属性。我们可以通过Object.prototype.toString()来查看。(对象的内部[[Class]]属性和创建该对象的内建原生构造函数相对应)

Object.prototype.toString.call([1,2,3]) // "[object Array]"        Object.prototype.toString.call(null) // "[object Null]"        Object.prototype.toString.call(undefined) // "[object Undefined]"复制代码

3、如果想要自行封装基本类型值,可以使用Object()函数(不带new关键字)

var a = "abc";    var b = new String(a);    var c = Object(a);        typeof a; // "string"    typeof b; // "object"    typeof c; // "object"        b instanceof String // true    c instanceof String // true        Object.prototype.toString.call(b) // "[object String]"    Object.prototype.toString.call(c) // "[object String]"复制代码

4、如果想要得到封装对象中的基本类型值,可以使用valueOf()函数。

var a = new String('abc');    var b = new Number(42);    var c = new Boolean(true);    var d = a + ""; // 隐式拆封    a.valueOf() // "abc"    b.valueOf() // 42    c.valueOf(); // true        typeof d // "string"复制代码

5、Array构造函数只带一个数字参数的时候,该参数会被作为数组的预设长度,而非只充当数组中的一个元素

var a = new Array(1,2,3)        a // [1,2,3]复制代码

6、我们将包含至少一个"空单元"的数组称为稀疏数组

7、创建数组的不同的方式会有所区别

var a = new Array(3);    var b = [undefined,undefined,undefined]        a.join("-"); // "--"    b.join("-"); // "--"        a.map(function(v,i){
return i}); // [undefined * 3] b.map(function(v,i){
return i}); // [0,1,2] function fakeJoin(arr,connector){ var str = ""; for(var i = 0;i
0){ str += connector } if(arr[i]!==undefined){ str += arr[i] } } return str; }复制代码

8、new Object() 可以创建对象,但是无法像常量形式那样一次设定多个属性。new Function() 比如动态定义函数参数函数体的时候可以创建函数。 new RegExp() 可以动态定义正则表达式

var c = new Object();        var e = new Function("a","return a*2;") // 相当于var f = function(a){
return a * 2} var name = 'xxx' var namePattern = new RegExp("\\b(?:"+name+")+\\b","ig"); var matches = someText.match(namePattern) 复制代码

9、Symbol

  • 符号是具有唯一性的特殊值(并非绝对),用它来命名对象属性不容易导致重名。
  • ES6中有一些预定义符号,以Symbol的静态属性形式出现,如Symbol.createSymbol.iterator
// 可以自定义对象的迭代器,for..of可以遍历值    obj[Symbol.iterator] = function(){}复制代码
var mysym = Symbol('symbol')    mysym // Symbol(symbol)    mysym.toString() //"Symbol(symbol)"    typeof mysym // "symbol"        var a = {}    a[mysym] = 'foobar'        Object.getOwnPropertySymbols(a) // [Symbol(symbol)]复制代码

强制类型转换

值类型转换

1、将值从一种类型转换为另一种类型通常称为类型转换,这是显式的情况;隐式的情况称为强制类型转换

2、Javascript中的强制类型转换总是返回标量基本类型值,如字符串、数字和布尔值,不会返回对象和函数。

3、类型转换发生在静态类型语言的编译阶段,而强制类型转换发生在动态类型语言的运行时(runtime)

ToString

1、抽象操作ToString,它负责处理非字符串到字符串的强制类型转换。null转换为"null",undefined转换为"undefined",true转换为"true"。

2、对普通对象来说,除非自行定义,否则toString()返回内部属性[[class]]的值,如"[object Object]"

3、如果对象有自己的toString()方法,字符串化时就会调用该方法并使用其返回值。

4、数组的默认toString()方法经过了重新定义,将所有单元字符串化以后在用,连接起来

var a = [1,2,3]        a.toString(); // "1,2,3"复制代码

JSON字符串化

1、JSON字符串化(JSON.stringify)并非严格意义上的强制类型转换。安全的JSON值都可以使用JSON.stringify字符串化。安全的JSON值是指能够呈现为有效的JSON格式的值。

2、不安全的JSON值:

  • undefined
  • symbol
  • function
  • 包含循环引用(对象之间相互引用,形成一个无限循环)的对象。

3、JSON.stringify()在对象中遇到undefined、function和symbol时会自动将其忽略。在数组中则会返回null(以保证单元位置不变)。对包含循环引用的对象执行JSON.stringify()会出错。

JSON.stringify(undefined);// undefined    JSON.stringify(function(){}); // undefined    JSON.stringify([1,undefined,function(){},4]) // "[1,null,null,4]"    JSON.stringify({a:2,b:function(){}}) // "{"a":2}"复制代码

4、如果对象中定义了toJSON()方法,JSON字符串化时会首先调用该方法,然后用它的返回值来进行序列化。(如果含有非法JSON值的对象做字符串化,或者对象中的某些值无法序列化时,就需要定义toJSON()方法来返回一个安全的JSON值

var o = {}    var a = {        b:41,        c:o,        d:function(){}    }        // 循环引用    o.e = a;        JSON.stringify(a) // 产生错误        a.toJSON = function(){        // 序列化仅包含b        return {b:this.b}    }        JSON.stringify(a) // "{"b":42}"复制代码

5、toJSON() 返回的应该是一个适当的值,可以是任何类型,然后在由JSON.stringify()对其进行字符串化。(也就是说返回一个能够被字符串化的安全的JSON值,而不是返回一个JSON字符串

var a = {        val:[1,2,3],        toJSON:function(){            return this.val.slice(1);            }    }        JSON.stringify(a); // "[2,3]"复制代码

6、可以向JSON.stringify()传递一个可选参数replacer,它可以是数组或者函数。用来指定对象序列化过程中哪些属性应该会处理,哪些应该被排除,和toJSON很像。

  • 如果replacer是一个数组,它必须是一个字符串数组,其中包含序列化要处理的对象的属性名称
  • 如果replacer是一个函数,它会对对象本身调用一次,然后对对象中的每个属各调用一次,每次传递两个参数,。如果要忽略某个键就返回undefined,否则返回指定的值。
var a = {        b:42,        c:"42",        d:[1,2,3]    }    JSON.stringify(a,["b","c"]) // "["b":42,"c":"42"]"        JSON.stringify(a,function(k,v){        if(k!=="c") return v    })    // "{"b":42,"d":[1,2,3]}"复制代码
  • JSON.stringify还有一个可选参数space(第三个参数),用来指定输出的缩进格式。space为正整数时是指定每一级缩进的字符数,还可以是字符串,此时最前面的十个字符被用于每一级的缩进。(感觉没啥大用)

ToNumber

1、true转换为1,false转换为0。undefined转换为NaN,Null转换为0。

2、对象(包含数组)转换为基本的类型值,会按照如下规则:

  • 检查该值是否有valueOf的方法。如果有并且返回基本类型值,就使用该值进行强制类型转换。
  • 如果没有的话就使用toString的返回值(如果存在)来进行强制类型转换。
  • 如果上面两个均不返回基本类型值,会产生TypeError错误。

3、使用Object.create(null)创建的对象[[Prototype]]属性为null,并且没有valueOf和toString方法,因此无法进行强制类型转换

ToBoolean

1、以下这些是假值:

  • undefined
  • null
  • false
  • +0、-0和NaN
  • ""

2、假值对象(了解以下吧)

document.all

显示强制类型转换

字符串和数字之间的转换

1、字符串=>数字

  • Number()
  • +(一元运算符)

2、数字=>字符串

  • String()
  • toString()
var a = 42;    var b = a.toString()        var c = "3.14"    var d = +c;        b // "42"    d // 3.14复制代码

3、一元运算符+的另一个常见用途是将日期(Date)对象强制类型转换为数字,返回结果为Unix时间戳,以毫秒为单位。

var d = +new Date()    d // 1560354322864        // 别的方式获取时间戳        var timestamp = new Date().getTime()        // Date.now    if(!Date.now){        Date.now = function(){            return +new Date();        }    }复制代码

~运算符(非)

  • ~x == -(x+1) (记住这一个就行了)
  • 使用场景,if(~a.indexOf(..)),如果if判断的结果为false,证明不存在,否则就是存在。

显示解析数字字符串

1、parseInt解析允许字符串中含有非数字字符,解析从左到右的顺序,如果遇到非数字字符就停止。而转换不允许出现非数字字符,否则会失败并返回NaN。(解析浮点数可以使用parseFloat())

var a = "42"    var b = "42px"    Number(a) // 42    parseInt(b) // 42复制代码

2、早期版本的parseInt()有一个问题,如果没有第二个参数来指定的基数,parseInt会根据字符串的第一个字符来自行决定基数。如果第一个字符是x或X,则转换为十六进制数字。如果是0,则转换为八进制数字。(注意ES5之后默认转换为十进制数。如果第二个参数不传或者false值,按照十进制处理。)

显示转换为布尔值

1、一元运算符 ! 显式地将值强制类型转换为布尔值。但是它同时还将 真值反转为假值(或者将假值反转为真值)。所以显式强制类型转换为布尔值最常用的方法是 !!,因为第二个 ! 会将结果反转回原值。

隐式强制类型转换

字符串和数字之间的隐式强制类型转换

1、根据 ES5 规范 11.6.1节,如果某个操作数是字符串或者能够通过以下步骤转换为字符串 的话,+ 将进行拼接操作。如果其中一个操作数是对象(包括数组),则首先对其调用 ToPrimitive 抽象操作(规范 9.1 节),该抽象操作再调用 [[DefaultValue]](规范 8.12.8 节),以数字作为上下文。 2、如果 + 的其中一个操作数是字符串(或者通过以上步骤可以得到字符串), 则执行字符串拼接;否则执行数字加法。

var a = [1,2];     var b = [3,4];    a + b; // "1,23,4"复制代码

3、我们可以将数字空字符串 ""相 + 来将其转换为字符串

var a = 42;    var b = a + "";    b; // "42"复制代码

4、a + ""(隐式)和前面的String(a)(显式)之间有一个细微的差别需要注意。根据 ToPrimitive抽象操作规则,a + ""会对a调用valueOf()方法,然后通过ToString抽象 操作将返回值转换为字符串。而 String(a) 则是直接调用 ToString()

var a = {         valueOf: function() { return 42; },         toString: function() { return 4; }     };     a + "";         // "42"     String( a );    // "4"复制代码

5、-是数字减法运算符,因此a - 0会将a强制类型转换为数字。也可以使用a * 1和a / 1。

var a = "3.14";    var b = a - 0;    b; // 3.14        var a = [3];    var b = [1];    a - b; // 2复制代码

布尔值到数字的隐式强制类型转换

1、可以使用!!来将值转换为布尔值,再通过 Number(..) 显式强制类型转换为 0 或 1。

隐式强制类型转换为布尔值

1、下面的情况会发生 布尔值隐式强制类型转换:

  • if (..)语句中的条件判断表达式。
  • for ( .. ; .. ; .. )语句中的条件判断表达式(第二个)。
  • while (..) 和 do..while(..) 循环中的条件判断表达式。
  • ? :中的条件判断表达式。
  • 逻辑运算符 ||(逻辑或)和 &&(逻辑与)左边的操作数(作为条件判断表达式)。

|| 和 &&

1、&& 和 || 运算符的返回值并不一定是布尔类型,而是两个操作数其中一个的值。 2、使用|| 和 &&注意以下几点:

  • || 和 && 首先会对第一个操作数(a 和 c)执行条件判断,如果其不是布尔值(如上例)就 先进行 ToBoolean 强制类型转换,然后再执行条件判断。
  • 对于 || 来说,如果条件判断结果为 true 就返回第一个操作数(a 和 c)的值,如果为 false 就返回第二个操作数(b)的值。
  • && 则相反,如果条件判断结果为 true 就返回第二个操作数(b)的值,如果为 false 就返 回第一个操作数(a 和 c)的值。
var a = 42;     var b = "abc";     var c = null;    a || b; a && b;    c || b; c && b;    // 42    // "abc"    // "abc"    // null复制代码

符号的强制类型转换

1、ES6 允许 从符号到字符串的显式强制类型转换,然而隐式强制类型转换会产生错误。 2、符号不能够被强制类型转换为数字(显式和隐式都会产生错误),但可以被强制类型转换 为布尔值(显式和隐式结果都是 true)

var s1 = Symbol( "cool" );    String( s1 );     // "Symbol(cool)"    var s2 = Symbol( "not cool" );    s2 + "";      // TypeError复制代码

宽松相等和严格相等

1、常见的误区是“== 检查值是否相等,=== 检查值和类型是否相等”。正确的解释是:“== 允许在相等比较中进行强制类型转换,而 === 不允许。”

抽象相等(挺重要的!!)

1、字符串数字之间的相等比较

ES5 规范 11.9.3.4-5 这样定义:

  • 如果 Type(x) 是数字,Type(y) 是字符串,则返回 x == ToNumber(y) 的结果。
  • 如果 Type(x) 是字符串,Type(y) 是数字,则返回 ToNumber(x) == y 的结果。
var a = 42;    var b = "42";    a === b;    // false  不进行强制类型转换比较    a == b;     // true   进行强制转换后进行比较复制代码

2、其他类型和布尔类型之间的相等比较

ES5 规范 11.9.3.6-7 这样定义:

  • 如果 Type(x) 是布尔类型,则返回 ToNumber(x) == y 的结果。
  • 如果 Type(y) 是布尔类型,则返回 x == ToNumber(y) 的结果。
var a = "42";    var b = true;    a == b; // false复制代码

3、null 和 undefined 之间的相等比较

ES5 规范 11.9.3.2-3 这样定义:

  • 如果 x 为 null,y 为 undefined,则结果为 true。
  • 如果 x 为 undefined,y 为 null,则结果为 true。

在 == 中 null 和 undefined 相等(它们也与其自身相等),除此之外其他值都不存在这种 情况

var a = null;     var b;     a == b;     // true     a == null;  // true     b == null;  // true          a == false; // false     b == false; // false     a == ""; // false    b == "";// false    a == 0;// false    b == 0;// false    复制代码

4、对象和非对象之间的相等比较

ES5 规范 11.9.3.8-9 这样定义:

  • 如果 Type(x) 是字符串或数字,Type(y) 是对象,则返回 x == ToPrimitive(y) 的结果;
  • 如果 Type(x) 是对象,Type(y) 是字符串或数字,则返回 ToPromitive(x) == y 的结果。
var a = 42;    var b = [ 42 ];    a == b; // true            var a = 'abc'    var b = Object(a)        a===b // false    a==b // true复制代码

5、极端情况

[] == ![] // true复制代码

让我们看看 ! 运算符都做了些什么?根据 ToBoolean 规则,它会进行布尔 值的显式强制类型转换(同时反转奇偶校验位)。所以[] == ![]变成了[] == false。 []=>''=>0,而false=>0 ,所以两边自然就相等了。

抽象关系比较

ES5 规范 11.8.5 节定义:

  • “抽象关系比较”(abstract relational comparison),分为两个部 分:比较双方都是字符串(后半部分)和其他情况(前半部分)。

1、比较双方首先调用 ToPrimitive,如果结果出现非字符串,就根据 ToNumber 规则将双方强 制类型转换为数字来进行比较。(感觉这个有点问题)

var a = [ 42 ];    var b = [ "43" ];        a < b;  // true    b < a;  // false复制代码

2、如果比较双方都是字符串,则按字母顺序来进行比较

var a = [ "42" ];     var b = [ "043" ];    a < b; // false复制代码

3、下面的例子有点奇怪

var a = { b: 42 };     var b = { b: 43 };     a < b;  // false     a == b; // false   对象比较 值不同直接是false     a > b;  // false     a <= b; // true     a >= b; // true复制代码

规范规定,<= 应该是“小于或者等于”。实际上 JavaScript 中 <= 是 “不大于”的意思(即 !(a > b),处理为 !(b < a))。同理 a >= b 处理为 b <= a

转载于:https://juejin.im/post/5cf92755f265da1b614fe8f0

你可能感兴趣的文章
c++——const
查看>>
古老的加密技术
查看>>
自学两周,轻松利用C语言实现黑客数码雨(内附源码)
查看>>
iOS 13 上手体验
查看>>
个人笔记
查看>>
【题解】 CF949C Data Center Maintenance
查看>>
【第四期】基于 @vue/cli3 插件,集成日志系统【SSR第三篇】
查看>>
命令类型即使用帮助
查看>>
struts2中不能使用static关键字作为URL路径
查看>>
SQL Sever 学习系列之三
查看>>
Cannot determine embedded database driver class for database type NONE
查看>>
解决Unknown error: Unable to build: the file dx.jar was not loaded from the SDK folder!
查看>>
前端页面性能优化
查看>>
JavaScript 计算两个颜色叠加值
查看>>
asyncio 学习
查看>>
多线程--多线程断点下载
查看>>
Intersect
查看>>
编程语言中,到底什么是变量,变量的作用是什么?
查看>>
Java多线程系列--“JUC集合”02之 CopyOnWriteArrayList
查看>>
Python模块
查看>>