天天看点

JavaScript基础知识点整理(一)——数据类型、判定、转换、this指向1、JavaScript类型2、原始(primitive)类型3、对象(Object)类型4、类型判定5、类型转换6、四则运算符7、this

JavaScript是每一位前端开发者都必备的技能,接下来会分章节文章阐述介绍每一部分的内容。

JavaScript基础整理①

  • 1、JavaScript类型
  • 2、原始(primitive)类型
  • 3、对象(Object)类型
  • 4、类型判定
    • 4.1、typeof
    • 4.2、instanceof
    • 4.3、Object.prototype.toString.call
  • 5、类型转换
    • 5.1、对象转原始类型
  • 6、四则运算符
    • 6.1、比较运算符
  • 7、this

1、JavaScript类型

JavaScript数据类型分为两大类:

  • 原始类型

    :number、string、nul、undefined、boolean、symbol;
  • 对象类型

    :三大类,分别是内部对象(

    本地对象和内置对象

    )、

    宿主对象

    自定义对象

    • 本地对象:ES提供的需要实例化

      new

      才能够使用的对象:Object、Function、Array、String、Boolean、Number、Date、Error、EvalError、RangeError、ReferenceError、syntaxError、TypeError、URIError;
    • 内置对象,也就是

      Global

      Math

      ,其中JavaScript的全局属性有

      infinity-代表正的无穷大的数值、NaN-指示某一个数值不是数字值、undefined-指示未定义的数值。

    • 宿主对象:执行JavaScript脚本的环境所提供的对象,是浏览器提供的对象,所有的BOM和DOM都是宿主对象。
    • 自定义对象:包括对象字面量方式(通过JSON创建对象)、工厂模式、构造函数模式、原型模式、组合使用构造函数模式和原型模式、其他模式(

      动态原型模式、寄生构造函数模式、稳妥构造函数模式

      )。

2、原始(primitive)类型

在JavaScript中,存在着7种原始数值,分别是:

  • boolean

  • null

  • undefined

  • number

  • string

  • symbo

  • bigint

原始类型存储的都是数值,没有函数可以调用,不会存在如下:

undefined.toString()

JavaScript基础知识点整理(一)——数据类型、判定、转换、this指向1、JavaScript类型2、原始(primitive)类型3、对象(Object)类型4、类型判定5、类型转换6、四则运算符7、this
注意:如果采用

'1'.toString()

是可以正常使用,这是由于

'1'

已经被强制转换为了

String

类型也就是对象类型,可以调用toString方法。

JavaScript的

number

类型是浮点类型,使用会遇到bug,例如

0.1 + 0.2 !== 0.3

;

string

类型数值不可以改变,无论使用任何方法;

3、对象(Object)类型

对象类型和原始类型不一样,原始类型存储的是数值,一般保存在栈上,对象类型存储的是地址-指针,数据保存在堆上;

创建一个对象类型时候,计算机会在堆内存种开辟空间保存数值,开发者需要找到该内存空间,这个空间会拥有一个指针(地址)。

const a = []
           

对于常量a而言,设定内存地址

#001

,那么地址

#001

的位置保存了数值

[]

,常量a存放了地址

#001

,给出如下示例代码:

const a = []
const b = a
b.push(1)
           

当我们将变量赋值给另外一个变量时,复制的是原本变量的地址(指针),也就是说当前变量 b 存放的地址(指针)也是

#001

。因此当我们对任一变量进行数据修改的时候,等同于修改存放在地址(指针)

#001

上的值,所以就导致了两个变量的值都发生了改变。

若函数参数是对象的时候:

function test(person) {
  person.age = 26
  person = {
    name: 'yyy',
    age: 30
  }

  return person
}
const p1 = {
  name: 'yck',
  age: 25
}
const p2 = test(p1)
console.log(p1) // -> ?
console.log(p2) // -> ?
           
  • 首先,函数传参是传递对象指针的副本;
  • 达到函数内部修改参数的属性这一步,

    p1

    的数值修改,则

    age

    从25 -> 26;
  • 若重新给

    person

    分配一个对象就出现了问题,如下图:
    JavaScript基础知识点整理(一)——数据类型、判定、转换、this指向1、JavaScript类型2、原始(primitive)类型3、对象(Object)类型4、类型判定5、类型转换6、四则运算符7、this

所以最后 person 拥有了一个新的地址(指针),也就和 p1 没有任何关系了,导致了最终两个变量的值是不相同的。

4、类型判定

4.1、typeof

typeof

对于原始类型来说,除了

null

都可以显示正确的类型,若想判定

null

的话可以使用过

xxx === null

typeof 1 // 'number'
typeof '1' // 'string'
typeof undefined // 'undefined'
typeof true // 'boolean'
typeof Symbol() // 'symbol'
typeof 1n // bigint
           

typeof

对于对象来说,除了函数都会显示

object

,所以说

typeof

并不能准确判定变量到底是什么类型。

typeof [] // 'object'
typeof {} // 'object'
typeof console.log // 'function'
           

4.2、instanceof

instanceof

通过原型链的方式来判定是否构建函数的实例,一般用来判定具体的对象类型:

const Person = function() {}
const p1 = new Person()
p1 instanceof Person // true

var str = 'hello world'
str instanceof String // false

var str1 = new String('hello world')
str1 instanceof String // true
           

对于原始类型而言,

instanceof

直接判定类型不可以, 不过可以利用如下方法:

class PrimitiveString {
  static [Symbol.hasInstance](x) {
    return typeof x === 'string'
  }
}
console.log('hello world' instanceof PrimitiveString) // true
           

我们可能不知道

Symbol.hasInstance

是什么东西,其实就是一个能让我们自定义

instanceof

行为的东西,以上代码等同于

typeof 'hello world' === 'string'

,所以结果自然是 true 了。

这其实也侧面反映了一个问题:instanceof 并不是百分之百可信的。

// true
[].constructor === Array
           

4.3、Object.prototype.toString.call

Object.prototype.toString.call

综合来看是最佳选择,能判断的类型最完整,基本上是开源库选择最多的方式。

JavaScript基础知识点整理(一)——数据类型、判定、转换、this指向1、JavaScript类型2、原始(primitive)类型3、对象(Object)类型4、类型判定5、类型转换6、四则运算符7、this

5、类型转换

JavaScript中存在三种情况:

  • 转换为bool
  • 转换为数字
  • 转换为字符串
JavaScript基础知识点整理(一)——数据类型、判定、转换、this指向1、JavaScript类型2、原始(primitive)类型3、对象(Object)类型4、类型判定5、类型转换6、四则运算符7、this
注意:图中有一个错误,

Boolean 转字符串

这行结果我指的是 true 转字符串的例子,不是说 Boolean、函数、Symblo 转字符串都是 true
转Boolean:在条件判断时,除了

undefined, null, false, NaN, '', 0, -0,

其他所有值都转为 true,包括所有对象。

5.1、对象转原始类型

对象在转换类型的时候,会调用内置的

[[ToPrimitive]]

函数,算法逻辑如下:

  • 若已经是原始类型,则不需要转换了;
  • 若需要转换的字符串就调用

    x.toString()

    ,转换为基础类型的话就返回转换的数值,不是字符串类型的话就先调用

    valueOf

    ,结果不是基础类型的话就调用

    toString

  • 调用

    x.valuof

    ,若转换为了基础类型,就返回转换的数值;
  • 若都没有返回原始类型,则报错。
当然,可以选择重写

Symbol.toPrimitive

,这个方法可以在转原始类型的时候优先级最高。
let a = {
  valueOf() {
    return 0
  },
  toString() {
    return '1'
  },
  [Symbol.toPrimitive]() {
    return 2
  }
}
1 + a // => 3
           

6、四则运算符

加法运算符不同于其他几个运算符,它有以下几个特点:

  • 运算中其中一方为字符串,那么就会把另一方也转换为字符串
  • 如果一方不是字符串或者数字,那么会将它转换为数字或者字符串
1 + '1' // '11'
true + true // 2
4 + [1,2,3] // "41,2,3"
           
  • 对于第一行代码来说,触发特点一,所以将数字 1 转换为字符串,得到结果

    '11'

  • 对于第二行代码来说,触发特点二,所以将

    true

    转为数字

    1

  • 对于第三行代码来说,触发特点二,所以将数组通过

    toString 转为字符串 1,2,3

    ,得到结果

    41,2,3

6.1、比较运算符

  • 若是对象,则通过

    toPrimitive

    转换对象
  • 若是字符串,则通过

    unicode

    字符索引来比较
let a = {
  valueOf() {
    return 0
  },
  toString() {
    return '1'
  }
}
a > -1 // true
           

在上述的代码中,

a

是对象,所以通过

valueOf

转换为原始类型在比较数值。

7、this

首先给出常见的

this

调用场景:

function foo() {
  console.log(this.a)
}
var a = 1
foo()

const obj = {
  a: 2,
  foo
}
obj.foo()

const c = new foo()
           
  • 对于直接调用

    foo

    而言,不管

    foo

    函数放在何处,

    this

    一定是

    window

  • 对于

    obj.foo

    而言,只要记住,谁调用了函数,谁就是

    this

    ,所以这时候

    foo

    函数中的

    this

    指的就是

    obj

    对象;
  • 对于

    new

    的方式而言,

    this

    被永远绑定在了

    c

    上面,不会被任何方式改变

    this

给出JavaScript的箭头函数中的

this

function a() {
  return () => {
    return () => {
      console.log(this)
    }
  }
}
console.log(a()()())
           
  • 首先箭头函数没有

    this

    ,箭头函数的

    this

    只是取决于包裹箭头函数的第一个普通函数的

    this

    ,在这个例子中,因为包裹箭头函数的第一个普通函数就是

    a

    ,所以这时的

    this

    就是

    window

    。另外箭头函数使用

    bind

    方法是无效的。
  • 另外一种情况就是

    bind

    这些改变上下文的API,

    this

    取决于第一个参数,若第一个参数空,则就是

    window

注意:若对一个函数进行多次

bind

,上下文表现如何?
let a = {}
let fn = function () { console.log(this) }
fn.bind().bind(a)() // => ?
           

也可以写作另一种形式:

let a = { name: 'yck' }
function foo() {
  console.log(this.name)
}
foo.bind(a)() // => 'yck'
           

以上就是

bind

的所有规则了,不同的规则之间根据优先级的高低来决定

this

的最终指向。

首先,

new

的方式优先级最高,接下来是

bind

这些函数,然后是

obj.foo()

这种调用方式,最后是

foo

这种调用方式,同时,箭头函数的

this

一旦被绑定,就不会再被任何方式所改变。

总结如下图所示:

JavaScript基础知识点整理(一)——数据类型、判定、转换、this指向1、JavaScript类型2、原始(primitive)类型3、对象(Object)类型4、类型判定5、类型转换6、四则运算符7、this

继续阅读