快速入门JavaScript

JavaScript简介

JavaScript从名字上看和Java很像,实际上两者也有不少相似的地方。但是它们之间没有任何关系,就像众多周知的老婆饼里没有老婆一样。
JavaScript(简称“JS”) 是一种具有函数优先的轻量级,解释型或即时编译型的编程语言。虽然它是作为开发Web页面的脚本语言而出名,但是它也被用到了很多非浏览器环境中,JavaScript是基于原型编程、多范式的动态脚本语言,并且支持面向对象、命令式、声明式、函数式编程范式。
JavaScript的标准是ECMAScript。2015年6月17日,ECMA国际组织发布了ECMAScript的第六版,该版本正式名称为 ECMAScript 2015,但通常被称为ECMAScript 6 或者ES2015。

变量

JavaScript是一种动态类型的语言。因此声明变量时,不需要指明变量的数据类型。同时,JavaScript还支持隐式转换,会自动将变量由一种类型转换一种类型进行运算。在JavaScript中,万物皆对象,因此所有的变量都是对象。

数据类型分类

在这里插入图片描述

数据类型分为基础类型和引用类型。

变量声明

var gloableVar = 100 //全局变量,作用域在全局
const constPI = 3.1415926 //常量,不允许修改
let name = 'Jaesoon' //局部变量,作用域在该文件
let animals = ['elephant', 'dog', 'monkey', 'panda'] //定义数组

//定义引用类型变量
let person = {
    firstName: "John",
    lastName: "Doe",
    age: 50,
    eyeColor: "blue"
}

//代码块
{
    let name = 'Jame' //局部变量,作用域在花括号中
    console.log(name)
}

let info = 'This person\'s name is ' + person.firstName + ', and age is ' + person['age']
console.log(info)
console.log(constPI)

//变量类型判断 typeof
console.log(typeof "John")               // 返回string
console.log(typeof 3.14// 返回 number
console.log(typeof false)                 // 返回 boolean
console.log(typeof [1,2,3,4]// 返回 object
console.log(typeof {name:'John', age:34}) // 返回 object

以上代码将会输出
在这里插入图片描述

这说明,let声明的变量作用域是它所在的花括号内。同时,变量在运算时会进行自动类型转换。而var和let的区别是,var定义的变量是全局的。

undifined 与 null

1、定义

  • (1)undefined:是所有没有赋值变量的默认值,自动赋值。
  • (2)null:主动释放一个变量引用的对象,表示一个变量不再指向任何对象地址。
    2、何时使用null?
    当使用完一个比较大的对象时,需要对其进行释放内存时,设置为 null。
    3、null 与 undefined 的异同点是什么呢?
    共同点:都是原始类型,保存在栈中变量本地。
    不同点:
    (1)undefined——表示变量声明过但并未赋过值。
    它是所有未赋值变量默认值,例如:
    var a; // a 自动被赋值为 undefined

(2)null——表示一个变量将来可能指向一个对象。
一般用于主动释放指向对象的引用,例如:
var emps = [‘ss’,‘nn’];
emps = null; // 释放指向数组的引用

4、延伸——垃圾回收站
它是专门释放对象内存的一个程序。

  • (1)在底层,后台伴随当前程序同时运行;引擎会定时自动调用垃圾回收期;
  • (2)总有一个对象不再被任何变量引用时,才释放。

运算符

以下变量中,y的初始值5
在这里插入图片描述

常见语句

let x = 3
//条件语句
if (x > 0) {
    console.log('x bigger than 0')
} else if (x >= 3) {
    console.log('x bigger or equal to 3')
}

//开关语句
var d = new Date().getDay()
switch (d) {
    case 0:
        x = "星期日"
        break
    case 1:
        x = "星期一"
        break
    case 2:
        x = "星期二"
        break
    case 3:
        x = "星期三"
        break
    case 4:
        x = "星期四"
        break
    case 5:
        x = "星期五"
        break
    case 6:
        x = "星期六"
        break
}
console.log('今天是:' + x)

//循环语句
//for循环
for (let i = 0; i < 5; i++) {
    console.log("这是第" + (i + 1) + '次循环')
}
let students = [
    { name: 'Jame', age: 12 }, { name: 'Jaesoon', age: 12 },
    { name: 'Steven', age: 12 }, { name: 'Jobs', age: 12 }
]
console.log('students info as follows')
console.log('\tNAME\tAGE')
for (let index in students) {
    let student = students[index]
    let info = '\t'
    for (let property in student) {
        info += student[property] + '\t'
    }
    console.log(info)
}

//while循环
let i = 0
while (i < 5) {
    console.log("这是第" + (i + 1) + '次循环')
    i++
}

i = 0
do {
    console.log("这是第" + (i + 1) + '次循环')
    i++
}
while (i < 5)

函数与方法

// 函数
function add(a, b) {
    return a + b
}

//方法
let addMethod = function (a, b) {
    return a + b
}

let sum1 = add(1, 2)
console.log('sum1 is ' + sum1)

let sum2 = addMethod(1, 2)
console.log('sum2 is ' + sum2)

在这里插入图片描述

面向对象

对象继承

class Person {
    constructor(name, sex, age) {
        this.name = name
        this.sex = sex
        this.age = age
    }

    selfIntroduction() {
        return 'I\'m ' + this.name + ',' + this.age + ' yeas old. I\'m ' + this.sex + '. '
    }
}

class Teacher extends Person {

    constructor(name, sex, age, cls) {
        super(name, sex, age)
        this.cls = cls
    }

    selfIntroduction() {
        let baseInfo = super.selfIntroduction()
        baseInfo += 'I\'m a teacher, teaching in class ' + this.cls + '. '
        return baseInfo
    }

    teach() {
        console.log('I\'m teaching!')
    }
}

class Student extends Person {
    constructor(name, sex, age, cls) {
        super(name, sex, age)
        this.cls = cls
    }

    selfIntroduction() {
        let baseInfo = super.selfIntroduction()
        baseInfo += 'I\'m a student, study in class ' + this.cls + '. '
        return baseInfo
    }

    learn() {
        console.log('I seem to be learning')
    }
}

let gang = new Teacher('Gang', 'female', 25, 1)
console.log(gang.selfIntroduction())
gang.teach()

let xiaoming = new Student('XiaoMing', 'male', 12, 1)
console.log(xiaoming.selfIntroduction())
xiaoming.learn()

在这里插入图片描述

this

面向对象语言中 this 表示当前对象的一个引用。JavaScript中的this具体代表的对象跟它被调用的位置有关系。

  • 在方法或构造函数中,this 表示该方法所属的对象。
  • 单独使用,this 表示全局对象。
  • 在函数中,this 表示全局对象。
  • 还有一种特殊的情况是被apply改变了作用范围
    需要理解下这个全局对象,在浏览器中和在nodejs中,所指的并不一致。nodejs在执行某一个js脚本文件时,会将整个文件定义为一个module。this指向的是module.exports对象。可以通过这个语句进行验证 console.log(module.exports === this)
this.a = 0
function testFunc() {
    return this.a
}

class Test {
    constructor(x) {
        this.a = x
    }

    test() {
        return this.a
    }
}

console.log('global call this.a is ' + this.a)

console.log('testFunc call this.a is ' + testFunc())

let test1 = new Test(1)
console.log('method call test1 this.a is ' + test1.test())

let test2 = new Test(2)
console.log('method call test2 this.a is ' + test2.test())

console.log('apply modify test2 this referance and call test2 this.a is ' + test2.test.apply(test1))

console.log(module.exports === this)

在这里插入图片描述

闭包

JavaScript变量的作用域可以分成全局变量和局部变量。全局变量能被全局访问,变量的生命周期和程序运行的周期是一致的。局部变量跟它所在的函数的生命周期有关系。函数执行完成之后,局部变量就会被回收。如果有一种需求是:该变量需要被全局访问,但是又不能被全局直接访问,因为这个变量的改动需要伴随这一系列的其它操作。因为有一系列的其它操作,所以,需要封装成一个函数来完成这一系列的操作。但是该变量又不能放在这个函数中,因为会因为函数调用完毕被释放掉。如果是c语言,我们直接给函数内定义一个静态变量,就可以突破它的生命周期。但是JavaScript没有这个数据类型。不过,JavaScript作为一种成熟的语言,可以通过其它方式来实现。这就是闭包。
闭包是一种保护私有变量的机制,在函数执行时形成私有的作用域,保护里面的私有变量不受外界干扰。直观的说就是形成一个不销毁的栈环境。

function getCountFunction() {
    let x = 0
    return function () {
        console.log('here we simulate complete some operations.')
        return ++x
    }
}

let countFunc = getCountFunction()
//countFunc就是函数闭包
let nowCount = countFunc()
console.log('count = ',nowCount)
nowCount = countFunc()
console.log('count = ',nowCount)

在这里插入图片描述

异步

JavaScript是单线程模型。代码都在一个线程内执行。但是JavaScript却提供了异步编程的能力。这怎么理解?
先看看一个异步编程的例子

console.log(new Date())
setTimeout(function () {
    console.log(new Date())
}, 1000)
console.log('--------divider--------')

在这里插入图片描述

可以看到,启动之后首先打印了开始时间,然后打印了分割线,最后1000ms后,程序打印了第二个时间,两者之间差了1s。说明setTimeout语句并未阻塞程序,调用完成之后,程序紧接着就打印了分割线。然后满足超时1s之后,再打印了第二个时间。这是不是和JavaScript的单线程模型想冲突?并不冲突,因为程序的第三行代码,依然是和其他行代码一样是在同一个线程中执行的。如何实现呢?JavaScript通过事件来完成异步操作。程序遇到setTimeout之后,我们创建了一个1000ms之后触发的事件,然后将

function () {
    console.log(new Date())
}

放入事件池。当满足事件时,从事件池中取出这段代码,然后在当前线程中继续执行这段代码。这些机制都是由JavaScript引擎来实现的,我们不需要深入研究。如果感兴趣,可以看看我的关于QuickJS引擎的解析。

模块

随着JavaScript被大规模的应用在各种场景上,用它来实现的系统也变的越来越复杂。为了降低程序的复杂度,减少程序的维护成本,同时也为了能够更好的复用代码,我们需要将一些功能趋近的代码,抽象到一个模块中。然后将模块放在另外一个文件中,被另外一个文件所引用。于是,ES6中,提出了模块的概念,并提供了export和import接口,以便实现模块功能。
module.mjs

function removeSensitiveInformation(name) {
    if (name == undefined || name == null) {
        return name
    }
    let ret = ''
    for (let i = 0; i < name.length - 1; i++) {
        ret += '*'
    }
    return ret + name[name.length - 1]
}

function formatBankNo(bankNo) {
    let patt = /\d{4}/g
    let arr = bankNo.match(patt)
    let left = bankNo.substring(arr.length * 4, bankNo.length)
    return arr.toString().replace(/,/g, ' ') + ' ' + left
}

export {
    removeSensitiveInformation as removeSensiInfo,
    formatBankNo
}

test.mjs

import { removeSensiInfo, formatBankNo } from './module.mjs'

console.log(removeSensiInfo('欧阳小峰'))
console.log(formatBankNo('6214837821912552'))

需要注意的是,为了在node中使用module功能,需要将我们的js文件后缀名改为mjs。
在这里插入图片描述

最后的话

事实上,如果你有编程基础,读完本文就基本入门的了JavaScript这门语言了。如果想要熟练的使用这门语言,你需要去了解下常用的几个内置对象。如:String,Date,Array,RegExp等。毕竟,想要完成一个完成的程序,至少还需要使用它内置的各种运行时库。最后,推荐一个比较好的入门JavaScript的书,《SpeakingJS》。写的很详细很棒。不得不说,这个老外写的书真的是太赞了,就像是课后习题解。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值