搜索
首页web前端js教程JavaScript 知识点梳理 | 从基础语法到高级用法
JavaScript 知识点梳理 | 从基础语法到高级用法Feb 04, 2017 pm 04:53 PM
javascript基础语法

JavaScript是按照ECMAScript标准设计和实现的,后文说的JavaScript语法其实是ES5的标准的实现。

先说说有哪些基础语法?


01- 

最基础语法有哪些?

基础语法几乎所有的语言差异不大,无非数据类型、操作符、控制语句、函数等,简单列举下。

5种基本数据类型 & 1种复杂的数据类型

JavaScript包含5种基本数据类型,分别是undefined / null /  boolean / number / string,基本数据类型就这五种,没有其他的!

JavaScript包含1种复杂的数据类型,就是Object类型,Object类型是所有其他对象的基类。(注意:JavaScript并不区分浮点数和整数,都是用number来表示。)

前面提到的5种基本数据类型,以及这儿的1种复杂数据类型,这就是数据类型的全部了!


基本操作符

这个是常识,知道怎么回事就好。

常用的操作符包括:算术操作符、关系操作符、布尔操作符、赋值操作符等。


控制语句

这就是我们常说的if-else之类的控制语句。

常用的并不多:if语句、switch语句、for语句、while语句、for-in语句。


函数

函数就是一小段逻辑的封装,理论上逻辑越独立越好。

JavaScript函数相对其他语言来说有很大不同。JavaScript函数既可以作为参数,也可以作为返回值。

此外JavaScript函数可以接受任意数量的参数,并且可以通过arguments对象来访问这些参数。

任何一门语言的基础语法都是相通的,除开一些细节差异,大致就是上面这些了:数据类型、操作符、控制语句、函数、模块等等。

接下来介绍稍微复杂的一些概念。


02- 

变量、作用域、内存问题

变量

JavaScript变量分为两种:基本类型和引用类型。其中基本类型就是前面提到的5种基本数据类型,引用类型就是前面提到的Object以及基于它的其他复杂数据类型。

基本类型:在内存中占据实际大小的空间,赋值的时候,会在内存中创建一份新的副本。保存在栈内存中。

引用类型:指向对象的指针而不是对象本身,赋值的时候,只是创建了一个新的指针指向对象。保存在堆内存中。

JavaScript 知识点梳理 | 从基础语法到高级用法

变量内存分配

一句话就是,基本类型在内存中是实际的值;而引用类型在内存中就是一个指针,指向一个对象,多个引用类型可能同时指向同一个对象。

那么,如何确定某个变量是哪种数据类型呢?

确定一个变量是哪种基本类型用typeof操作符。

确定一个变量是哪种引用类型用instanceof操作符。

这个别忘了!


作用域

变量是在某个特定的作用域中声明的,作用域决定了这些变量的生命周期,以及哪些代码可以访问其中的变量。

JavaScript作用域只包括全局作用域和函数作用域,并不包含块级作用域!


作用域是可以嵌套的,从而形成作用域链。由于作用域链的存在,可以让变量的查找向上追溯,即子函数可以访问父函数的作用域=>祖先函数的作用域=>直到全局作用域,这种函数我们也称为闭包,后文会介绍。

var color = "blue";

function changeColor() {
    var anotherColor = "red";

    function swapColors() {
        var tempColor = anotherColor;
        anotherColor = color;
        color = tempColor;
        // 这里可以访问color、anotherColor、tempColor 
    }
    // 这里可以访问color、anotherColor,但不能访问tempColor
    swapColors();
}
// 这里只能访问color、changeColor();

如下图所示,每个作用域能够访问到的变量以及嵌套的作用域可向上追溯。

JavaScript 知识点梳理 | 从基础语法到高级用法

作用域链

作用域的概念看着简单,实际使用会有不少问题,遇到问题要细心分析。

内存问题

JavaScript引擎具有自动垃圾回收机制,不需要太关注内存分配和垃圾回收问题。这儿就不展开了!


03- 

引用类型

前面提过,Object是唯一的复杂数据类型,引用类型都是从Object类型上继承而来。

Array:数组类型

Date:日期类型

RegExp:正则表达式类型,这个多学学有好处!

等等...

那问题来了,我们用的最多的函数是什么数据类型呢?答案是Function类型!

诶,好像发现了点什么东西?由于Function是引用类型,而JavaScript又可以往引用类型上加属性和方法。那么,函数也可以!这也是JavaScript函数强大和复杂的地方。也就是说:函数也可以拥有自定义方法和属性!

此外,JavaScript对前面提到的5种基本类型的其中3种也做了引用类型封装,分别是Boolean、Number、String,但其实使用不多,了解就行。

对了,在所有代码执行之前,作用域就内置了两个对象,分别是Global和Math,其中浏览器的Global就是window啦!

到此为止,JavaScript中基础的概念都差不多介绍了,其中函数和作用域相对来说复杂一些,其他的都比较浅显。

接下来,我会介绍介绍JavaScript中一些稍微复杂一些的概念:面向对象。


03- 

面向对象编程

JavaScript本身并没有类和接口的概念了,面向对象都是基于原型实现的。

为了简单,我们只分析面向对象的两个问题:

如何定义一个类?

如何实现类的继承

定义一个类

不扯其他的,直接告诉你。我们使用构造函数+原型的方式来定义一个类。

使用构造函数创建自定义类型,然后使用new操作符来创建类的实例,但是构造函数上的方法和属性在每个示例上都存在,不能共享,于是我们引入原型来实现方法和属性的共享。

JavaScript 知识点梳理 | 从基础语法到高级用法

最后,我们将需要共享的方法和属性定义在原型上,把专属于实例的方法和属性放到构造函数中。到这儿,我们就通过构造函数+原型的方式定义了一个类。

// 构造函数
function Person(name, age, job) {
    this.name = name;
    this.age = age;
    this.job = job;
    this.friends = ["Shelby", "Court"];

}
// 原型
Person.prototype = {
    constructor: Person,
    sayName: function() {
        return this.name;
    }
}
// 实例化
var person1 = new Person("Nicholas", 29, "Software Engineer");
var person2 = new Person("Greg", 27, "Doctor");

person1.friends.push("Van");
alert(person1.friends);                     //输出"Shelby,Count,Van"
alert(person2.friends);                     //输出"Shelby,Count"
alert(person1.friends === person2.friends);        //输出false
alert(person1.sayName === person2.sayName);        //输出true

实现继承

前文讲了如何定义一个类,那么我们定义一个父类,一个子类。

如何让子类继承父类呢?不扯别的,直接告诉你。JavaScript通过原型链来实现继承!

如何构建原型链呢?将父类实例赋值给子类构造函数的原型即可。好绕,但是千万得记住了!

JavaScript 知识点梳理 | 从基础语法到高级用法

原型链继承

构建原型链之后,子类就可以访问父类的所有属性和方法!

// 父类
function SuperType() {
    this.property = true;
}
SuperType.prototype.getSuperValue = function() {
    return this.property;
};

// 子类
function SubType() {
    this.subproperty = false;
}

//子类继承父类
SubType.prototype = new SuperType();

//给子类添加新方法
SubType.prototype.getSubValue = function() {
    return this.subproperty;
};
//重写父类的方法
SubType.prototype.getSuperValue = function() {
    return false;
};

// 实例化
var instance = new SubType();
console.log(instance.getSuperValue()); //输出false

面向对象的知识可以用一本书来写,这儿只是简单的介绍下最基础最常用的概念。


03- 

函数表达式

JavaScript中有两种定义函数的方式:函数声明和函数表达式。使用函数表达式无须对函数命名,从而实现动态编程,也即匿名函数。有了匿名函数,JavaScript函数有了更强大的用处。

递归

递归是一种很常见的算法,经典例子就是阶乘。也不扯其他的,直接说递归的最佳实践,上代码:

// 最佳实践,函数表达式
var factorial = (function f(num) {
    if (num <= 1) {
        return 1;
    } else {
        return num * f(num - 1);
    }
});

// 缺点:
// factorial存在被修改的可能
// 导致 return num * factorial(num - 1) 报错
function factorial(num) {
    if (num <= 1) {
        return 1;
    } else {
        return num * factorial(num - 1);
    }
}

// 缺点:
// arguments.callee,规范已经不推荐使用
function factorial(num) {
    if (num <= 1) {
        return 1;
    } else {
        return num * arguments.callee(num - 1);
    }
}

递归就是这样,好多人还在使用arguments.callee的方式,改回函数表达式的方式吧,这才是最佳实践。

啰嗦一句,好多人觉得递归难写,其实你将其分为两个步骤就会清晰很多了。

边界条件,通常是if-else。

递归调用。

按这个模式,找几个经典的递归练练手,就熟悉了。

闭包

很多人经常觉得闭包很复杂,很容易掉到坑里,其实不然。

那么闭包是什么呢?如果一个函数可以访问另一个函数作用域中的变量,那么前者就是闭包。由于JavaScript函数可以返回函数,自然,创建闭包的常用方式就是在一个函数内部创建另一个函数!


这并没有什么神奇的,在父函数中定义子函数就可以创建闭包,而子函数可以访问父函数的作用域。


我们通常是因为被闭包坑了,才会被闭包吓到,尤其是面试题里一堆闭包。


闭包的定义前面提了,如何创建闭包也说了,那么我们说说闭包的缺陷以及如何解决?

/* 我们通过subFuncs返回函数数组,然后分别调用执行 */

// 返回函数的数组subFuncs,而这些函数对superFunc的变量有引用
// 这就是一个典型的闭包
// 那么有什么问题呢?
// 当我们回头执行subFuncs中的函数的时候,我们得到的i其实一直都是10,为什么?
// 因为当我们返回subFuncs之后,superFunc中的i=10
// 所以当执行subFuncs中的函数的时候,输出i都为10。
// 
// 以上,就是闭包最大的坑,一句话理解就是:
// 子函数对父函数变量的引用,是父函数运行结束之后的变量的状态
function superFunc() {
    var subFuncs = new Array();
    for (var i = 0; i < 10; i++) {
        subFuncs[i] = function() {
            return i;
        };
    }

    return subFuncs;
}

// 那么,如何解决上诉的闭包坑呢?
// 其实原理很简单,既然闭包坑的本质是:子函数对父函数变量的引用,是父函数运行结束之后的变量的状态
// 那么我们解决这个问题的方式就是:子函数对父函数变量的引用,使用运行时的状态
// 如何做呢?
// 在函数表达式的基础上,加上自执行即可。
function superFunc() {
    var subFuncs = new Array();
    for (var i = 0; i < 10; i++) {
        subFuncs[i] = function(num) {
            return function() {
                return num;
            };
        }(i);
    }
    return subFuncs;
}

综上,闭包本身不是什么复杂的机制,就是子函数可以访问父函数的作用域。


而由于JavaScript函数的特殊性,我们可以返回函数,如果我们将作为闭包的函数返回,那么该函数引用的父函数变量是父函数运行结束之后的状态,而不是运行时的状态,这便是闭包最大的坑。而为了解决这个坑,我们常用的方式就是让函数表达式自执行。


此外,由于闭包引用了祖先函数的作用域,所以滥用闭包会有内存问题。


好像把闭包说得一无是处,那么闭包有什么用处呢?

主要是封装吧...


封装

闭包可以封装私有变量或者封装块级作用域。


➙ 封装块级作用域

JavaScript并没有块级作用域的概念,只有全局作用域和函数作用域,那么如果想要创建块级作用域的话,我们可以通过闭包来模拟。


创建并立即调用一个函数,就可以封装一个块级作用域。该函数可以立即执行其中的代码,内部变量执行结束就会被立即销毁。

function outputNumbers(count) {
    // 在函数作用域下,利用闭包封装块级作用域
    // 这样的话,i在外部不可用,便有了类似块级作用域
    (function() {
        for (var i = 0; i < count; i++) {
            alert(i);
        }
    })();

    alert(i); //导致一个错误! 
}

// 在全局作用域下,利用闭包封装块级作用域
// 这样的话,代码块不会对全局作用域造成污染
(function() {
    var now = new Date();

    if (now.getMonth() == 0 && now.getDate() == 1) {
        alert("Happy new year!");
    }
})();

// 是的,封装块级作用域的核心就是这个:函数表达式 + 自执行!
(function() {
    //这里是块级作用域
})();

➙ 封装私有变量

JavaScript也没有私有变量的概念,我们也可以使用闭包来实现公有方法,通过隐藏变量暴露方法的方式来实现封装私有变量。

(function() {
    //私有变量和私有函数
    var privateVariable = 10;

    function privateFunction() {
        return false;
    }

    //构造函数
    MyObject = function() {};
    //公有/特权方法
    MyObject.prototype.publicMethod = function() {
        privateVariable++;

        return privateFunction();
    };
})();

03- 

总结说点啥?

这差不多就是JavaScript的一些基础语法和稍微高级一些的用法,其实所谓的高级,都是JavaScript“不太成熟”的表现,尤其是面向对象,出于工程化的需要但是JavaScript本身并不完美支持。好在ES6最新标准解决了很多问题,结合Babel用起来也不用太考虑兼容性问题,如果你是新手的话,建议你直接去撸ES6+Babel吧。

JavaScript的基础主要包括:5中基本数据类型、1种复杂的数据类型、操作符、控制语句、函数等。

了解基本的语法后,你还需要学习学习JavaScript的变量、作用域、作用域链。

常见的引用类型可以边查边用。作为过来人,建议多学学正则,对你的代码功底会有较大的提升。

面向对象编程的部分外面有很多种方式,你只需要记住使用构造函数+原型去定义一个类,使用原型链去实现继承即可。更多的扩展,去翻翻书吧。

函数表达式引出了几个比较好玩的东西:递归、闭包、封装。记住递归的最佳实践、闭包的定义及缺陷、闭包的适用场景。

JavaScript作为一门动态语言,和其他语言有较大的差异,这也造成很多人学习JavaScript时会觉得难学。但你现在看看前文,虽然是一个简略的总结,但JavaScript主要的内容就这些了,所以不要被自己吓到了。

再补一句,如果你是新手的话,建议你直接去撸ES6+Babel吧。

更多JavaScript 知识点梳理 | 从基础语法到高级用法相关文章请关注PHP中文网!

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
如何快速把你的 Python 代码变为 API如何快速把你的 Python 代码变为 APIApr 14, 2023 pm 06:28 PM

提到API开发,你可能会想到DjangoRESTFramework,Flask,FastAPI,没错,它们完全可以用来编写API,不过,今天分享的这个框架可以让你更快把现有的函数转化为API,它就是Sanic。Sanic简介Sanic[1],是Python3.7+Web服务器和Web框架,旨在提高性能。它允许使用Python3.5中添加的async/await语法,这可以有效避免阻塞从而达到提升响应速度的目的。Sanic致力于提供一种简单且快速,集创建和启动于一体的方法

PHP8.0中新的类型别名语法PHP8.0中新的类型别名语法May 14, 2023 pm 02:21 PM

随着PHP8.0的发布,新增了一种类型别名语法,使得使用自定义的类型变得更加容易。在本文中,我们将深入了解这种新的语法,以及它对开发人员的影响。什么是类型别名?在PHP中,类型别名本质上是一个变量,它引用另一个类型的名称。这个变量可以像其他类型一样使用,并在代码中的任何地方声明。这种语法的主要作用是为常用的类型定义自定义别名,使得代码更加易于阅读和理解。

lambda 表达式的语法和结构有什么特点?lambda 表达式的语法和结构有什么特点?Apr 25, 2024 pm 01:12 PM

Lambda表达式是无名称的匿名函数,其语法为:(parameter_list)->expression。它们具有匿名性、多样性、柯里化和闭包等特点。实际应用中,Lambda表达式可用于简洁地定义函数,如求和函数sum_lambda=lambdax,y:x+y,并通过map()函数应用于列表来进行求和操作。

Go语言与JS的联系与区别Go语言与JS的联系与区别Mar 29, 2024 am 11:15 AM

Go语言与JS的联系与区别Go语言(也称为Golang)和JavaScript(JS)都是当前流行的编程语言,它们在某些方面有联系,在其他方面又有明显的区别。本篇文章将探讨Go语言与JavaScript之间的联系与区别,同时提供具体的代码示例来帮助读者更好地理解这两种编程语言。联系:都是跨平台的Go语言和JavaScript都是跨平台的,可以在不同的操作系统

PHP8.0中的父类调用语法PHP8.0中的父类调用语法May 14, 2023 pm 01:00 PM

PHP是一种广泛应用于Web开发的服务器端脚本语言,而PHP8.0版本中引入了一种新的父类调用语法,让面向对象编程更加方便和简洁。在PHP中,我们可以通过继承的方式创建一个父类和一个或多个子类。子类可以继承父类的属性和方法,并可以通过重写父类的方法来修改或扩展其功能。在普通的PHP继承中,如果我们想在子类中调用父类的方法,需要使用parent关键字来引用父

学会使用CSS选择器的基本语法学会使用CSS选择器的基本语法Jan 13, 2024 am 11:44 AM

掌握基本的CSS选择器语法,需要具体代码示例CSS选择器是前端开发中非常重要的一部分,它可以用来选择和修改HTML文档的各个元素。掌握基本的CSS选择器语法对于编写高效的样式表是至关重要的。本文将介绍一些常见的CSS选择器以及对应的代码示例。元素选择器元素选择器是最基本的选择器,可以通过元素的标签名来选择对应的元素。例如,要选择所有的段落(p元素),可以使用

乘方运算在C语言中的用法及语法乘方运算在C语言中的用法及语法Feb 18, 2024 pm 04:05 PM

C语言中乘方运算的语法和用法简介:在C语言中,乘方运算(poweroperation)是一种常见的数学运算,它用于计算一个数的幂。在C语言中,我们可以使用标准库函数或者自定义函数来实现乘方运算。本文将详细介绍C语言中乘方运算的语法和用法,并提供具体的代码示例。一、使用math.h中的pow()函数在C语言中,math.h标准库中提供了pow()函数,用于执

C++语法中易混淆的概念解析C++语法中易混淆的概念解析Jun 01, 2024 pm 09:13 PM

混淆概念解析:指针和引用:指针存储变量地址,引用直接指向变量。值传递和引用传递:值传递副本,引用传递引用。const和constexpr:const为运行时常量,constexpr为编译时常量。&&和&:&&和&&&为逻辑与运算符,&为引用运算符。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
3 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
3 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
3 周前By尊渡假赌尊渡假赌尊渡假赌

热工具

MinGW - 适用于 Windows 的极简 GNU

MinGW - 适用于 Windows 的极简 GNU

这个项目正在迁移到osdn.net/projects/mingw的过程中,你可以继续在那里关注我们。MinGW:GNU编译器集合(GCC)的本地Windows移植版本,可自由分发的导入库和用于构建本地Windows应用程序的头文件;包括对MSVC运行时的扩展,以支持C99功能。MinGW的所有软件都可以在64位Windows平台上运行。

安全考试浏览器

安全考试浏览器

Safe Exam Browser是一个安全的浏览器环境,用于安全地进行在线考试。该软件将任何计算机变成一个安全的工作站。它控制对任何实用工具的访问,并防止学生使用未经授权的资源。

适用于 Eclipse 的 SAP NetWeaver 服务器适配器

适用于 Eclipse 的 SAP NetWeaver 服务器适配器

将Eclipse与SAP NetWeaver应用服务器集成。

SublimeText3 英文版

SublimeText3 英文版

推荐:为Win版本,支持代码提示!

mPDF

mPDF

mPDF是一个PHP库,可以从UTF-8编码的HTML生成PDF文件。原作者Ian Back编写mPDF以从他的网站上“即时”输出PDF文件,并处理不同的语言。与原始脚本如HTML2FPDF相比,它的速度较慢,并且在使用Unicode字体时生成的文件较大,但支持CSS样式等,并进行了大量增强。支持几乎所有语言,包括RTL(阿拉伯语和希伯来语)和CJK(中日韩)。支持嵌套的块级元素(如P、DIV),