JS概观
学习JS的最好方法,就是书写JS代码
每个文件都是程序
在JS中,每一个独立的文件都是它自己的独立的程序。我们可以通过 【全局作用域】 的方式将多个.js
文件共享它们的状态。它们在这个全局作用域的命名空间内混合在一起,所以它们可以作为一个整体运行。
从ES6开始,JS除了典型的独立JS外,支持了模块导入。模块也是基于文件的,JS仍然是单独的对待每个模块,当将一个模块导入到另一个模块中,这个情况就类似于【全局作用域】文件混合一样,支持它们在运行时互相操作。
所以无论使用哪种代码组织方式和加载机制(独立的或者模块的),我们都应该将每个文件看做自己的独立的程序, 然后和其他的小的程序合作来执行完整的程序应用的功能。
值
程序中基本的信息单位是值
。在JS中,值有两种形式:原始值 和 对象的;
通常我们使用单引号('')或者双引号("")
来定义字符串值,使用哪一种完全按照自己的风格。
js
console.log('you dont know JS')
我们还有另外一种方式定义:使用`````定义字符串,然后可以使用(${..})
,将变量值解析出来。
js
var firstName = 'Jerry'
consolo.log(`my name is ${firstName}`)
// my name is Jerry
除了字符串之外,JS程序经常使用的还有数字和布尔值
js
// 布尔值(boolean):true | false
// 数字(number):1 3.1415
while(true) {
console.log(2333)
}
数字还有一个变体,是bigint(大整数)原始类型,通常用于存储任意大的数字
除了字符串、数字、布尔之外,JS还有两个原始值 null
和undefined
,它们两个值都是表示一个空或者不存在的值
最后一个需要注意的原始值是Symbol
,这是一个特殊用途的值,表示一个隐藏的不可猜测的值,几乎只是作为对象的特殊键使用
所以,综上所述,JS中的原始类型的值有 7 种:string、number、boolean、null、undefined、bigint、symbol
数组和对象
除了原始,JS的另一种值类型是对象。
我们经常会用到的数据就是一种特殊类型的对象。
js
var fruits = ['apple','pear','orange','banana']
fruits.length // 4
fruits[0] // 'apple'
而对象更像是:一个无序的、有键的任何各种值的集合
js
var person = {
name: 'jerry',
age: 18,
hobbies: ['sing','play game']
}
person.name // 'jerry'
通常我们想要获取对象的信息,可以使用.
语法,或者使用[]
,比如person['name']
判断值的类型
我们可以使用typeof
操作符进行判断,这个操作符对于原始数据类型可以正确的识别(除了null)
js
typeof 42 // 'number'
typeof 'abc' // 'string'
typeof true // 'boolean'
typeof undefined // 'undefined'
typeof null // 'object'
typeof {a: 1} // 'object'
typeof [3,2,1] // 'object'
typeof function hell() {} // 'function'
声明和使用变量
在Js中,我们可以把值放到变量中,变量可以看做是值的容器。需要注意的是,变量必须要要先声明才能被使用。
通常有3个关键词可以来声明变量var
,let
,const
,区别在于
let | var | const |
---|---|---|
块级作用域 ,暂时性死区,不允许重复声明 | 块级作用域,暂时性死区,声明时需要赋值,不允许重新赋值 |
函数
在JS中,函数的含义更像是【过程】:一个过程是一个语句的集合,可以被调用多次。 通常我们可以使用函数声明的方式来定义函数,比如:
js
function hello() {
console.log('hello')
}
或者使用函数表达式的方式定义:
js
const hello = function() {
// dosometging
}
两者的区别需要注意的是:前者标识符hello和函数值产生关联是在代码编译阶段,在代码被执行之前;后者是在代码执行时才会产生联系
另外,需要注意的是,在JS中,函数是可以被分配和传递的值,但是在其他函数中,不一定是这个情况。
我们 在使用函数的时候,可以接受参数
输入,参数在函数值充当一个局部变量。
js
function greeting(pname) {
console.log(`hello, ${pname}`)
}
greeting('JACK')
// hello, JACK
比较
== | === |
---|---|
比较时,如果类型不同,会进行强制转换 | 同时比较值跟类型,但是对于NaN和 -0,判断不准确 |
JS中对于对象值的比较,提供的是引用(身份)相等的机制,即只会比较对象的值的引用地址是否相等来判断。如果需要结构相等则需要自己实现。但是这个是比较复杂的。
如何在JS中组织代码
在JS生态中,一般使用两种组织代码的形式:类和模块
类 Classes
程序中的类是对自定义数据结构[类型]的定义,包括了数据和对数据的操作的行为。类并不是一个具体的值,在使用时,需要通过new
关键字进行实例化
js
class Person {
constructor(name) {
this.name = name
}
eat() {
console.log('person need eat')
}
}
const p1 = new Person('JACK')
p1.eat()
// person need eat
在传统的【面向类】设计中,继承和多态也是固有的一种能力
js
class Person {
constructor(name) {
this.name = name
}
eat() {
console.log('person need eat food')
}
}
class blackMan extends Person {
constructor() {
super()
}
eat() {
super.eat()
console.log('like eat chiken')
}
}
const bm1 = new blackMan()
bm1.eat()
// person need eat food
// leike eat chiken
子类中的eat
方法,覆盖了父类的eat方法;通过super.eat() 调用父类的方法,继承和覆盖的方法可以有相同的名字,并且共存。这就是多态。
模块 Modules
模块的目标与类一样,是为了将数据和行为组合成逻辑单元,并且和类一样,模块可以包含和访问其他模块的数据和行为
classic Modules
它的主要标志是一个外部函数(至少运行一次),返回一个模块的【实例】,并暴露出一个或者多个函数,可以对实例内部的数据进行操作,它也被成为【模块工厂】
使用模块工厂函数的时候,我们可以明确的创建并返回一个具有任何公开暴露方法的对象,任何数据和其他未被引用的方法在工厂函数中保持私有。
js
function Publication(title,author,pubDate) {
var publicAPI = {
print() {
console.log(`
Title: ${title}
By: ${author}
${pubDate}
`)
}
}
return publicAPI
}
function Book(booKDetails) {
var pub = Publication(bookDetails.title,bookDetails.author,bookDetails.publishedOn)
var publicAPI = {
print() {
pub.print()
console.log(`
Published: ${bookDetails.publisher}
ISBN: ${bookDetails.ISBN}
`
)
}
}
return publicAPI
}
var YDKJS = Booke({
title: 'You Dont know JS',
author:'Kyle Simpson',
publishedOn: 'June 2014',
publisher: 'O Reilly',
ISBN: '123456-789'
})
YDKJS.print()
// Title: 'You Dont know JS',
// author:'Kyle Simpson',
// 'June 2014',
// publisher: 'O Reilly',
// ISBN: '123456-789'
模块工厂函数在使用时,像普通函数一样调用即可,这种工厂函数的形式还有其他的变化,比如AMD(异步木块定义、UMD(通用模块定义)、和CommonJS(典型的Node.js风格模块)
ES Modules
ESM是ES6被引入JS的。它的实现方法与classic Modules有所区别
- 首先ESM是基于文件的,一个文件,一个模块
- 其次,它主要通过export关键字将一个变量或者方法导出到公共API定义,如果没有export的话,该方法和变量相当于被隐藏掉了
- ESM是单例的,在程序中第一次import【导入】时创建了一个实例,所有的其他导入都是这个单一实例的引用