很多人在使用Javascript之前都至少使用过C++、C#或Java,面向对象的编程思想已经根深蒂固,恰好Javascript在语法上借鉴了Java,虽然方便了Javascript的入门,但要深入理解Javascript的时候,长期使用这些编程语言造成的思维定势却给使用Javascript带来误导。作者在学习Javascript的时候曾陷入了这个误区,希望通过这篇文章让新学者避免走这个弯路,迅速正确地掌握Javascript。

1. 要点

在面对Javascript时,要牢记以下几点:

1.1 Javascript不是面向对象的编程语言

如果非要把Javascript归到面向什么的话,Javascript准确的说是面向原型的编程语言,它是从self语言发展而来,除了语法上借鉴了Java,其它方面和Java什么关系都没有,本质上更不同。简单说,Javascript里面没有类,全是对象。在使用Javascript的时候,应该时刻提醒自己:Javascript不是C++、C#或Java。

1.2 Javascript是解释执行的语言

虽然这很显而易见,但如果不时刻牢记这一点,而把Javascript和编译型语言的运行方式混淆的话,也非常不利于理解Javascript。比如,如果你用C++、C#或Java中的局部变量的思想去理解Javascript函数中通过var定义的变量的话,就会有麻烦。

2. Javascript中的对象和类型

Javascript没有传统面向对象编程语言中的类,全部是对象。

Javascript中的对象键值对的集合,键的类型是字符串,值可以是任意对象。创建新对象的方式有:new 函数()、{}语法、Object.create(原型对象)。

函数也是对象,是一种包含可运行的代码的特殊对象,并且代码能够以函数调用的形式被执行。函数对象能通过function关键字定义或通过new关键字使用Function构造函数来创建。

下面的示例创建了一个函数对象foo,并为它设置三个属性:一个数字,一个字符串,一个函数。从示例可以看到函数对象除了能被调用以外,其他行为和普通对象无异。

当通过“new 函数()”的语法创建对象时,函数被称为构造函数。

在Javascript中,通常将构造函数称为对象的类型。比如obj = new Fun(),那么称obj的类型为Fun。

Javascript有Undefined,  Null,  Boolean,  Number, String, Object和Function这几种基本类型。Javascript运行时会对Undefined,  Null,  Boolean,  Number, and  String这五种基础类型的对象以及Function类型的函数对象会以特定的方式解释和处理。

因为函数是对象,函数除了可以通过function语法定义以外,也可以用创建对象的方式创建:fun = new Function("参数", "函数体"),Function本身是Javascript内建的函数。

基本类型Boolean,  Number, String, Object, Array, Date等都是内建的函数。没有Undefined和Null内建函数,而是有Undefined和Null类型的内建的唯一的对象,分别是undefined和null。

3. 执行上下文

Javascript中每一行代码的执行都是在当前执行上下文中完成。

执行上下文的层级关系是由代码的定义结构(也就是源代码字面结构)决定的,与运行时函数的调用栈结构无关。

执行上下文由一个上下文变量容器和一个this绑定构成。上下文变量容器中包含当前执行上下文中定义的变量。this绑定表示当前执行上下文中this关键字指向的对象。

简单来说,每次函数调用都进入一个新的执行上下文,同一函数递的归调用也会进入新的执行上下文。

每一个执行上下文都包含对创建它的上一级执行上下文的引用,因此所有执行上下文组成一棵树。

在浏览器中,根执行上下文(即不在任何函数中运行的代码)中没有上下文变量容器,this绑定到全局对象window。因此在根执行上下文中定义变量时,使用var、不使用var和使用this.定义的变量都是全局对象window的属性,因为没有上下文变量容器。通过这一规定,Javascript运行过程中的所有执行上下文都能指向全局对象,形成一棵完整的树。

在除了根执行上下文之外的其它执行上下文中,变量定义的规则如下:

var i = 1 变量i位于当前执行上下文的上下文变量容器中 
j = 2 变量j是全局对象的属性
this.k = 3 变量k是当前执行上下文的this对象的属性

在表达式中使用一个变量时,Javascript将首先从当前执行上下文的上下文变量容器中查找该变量,如果不存在,则在上级执行上下文的上下文变量容器中查找,以此类推,直到根执行上下文,在根执行上下文中,将在全局对象中查找是否有同名的属性。示例如下:

当前执行上下文的this绑定默认继承自上级执行上下文,如果当前运行代码所在的函数是通过obj.currentfun()的方式调用,也就是obj对象的方法,那么this将被绑定到obj。在使用时,this关键字必须明确写出,因为this在逻辑上是与执行上下文有关的,与当前函数所属的对象没有直接因果关系。

垃圾回收机制:如果当前执行上下文及其中的代码已经执行完成,且其所有下级执行上下文已经释放,且没有来自当前执行上下文之外的对当前执行上下文的上下文变量容器中的变量的引用,那么当前执行上下文被释放,当前执行上下文的上下文变量容器中的变量指向的对象和this指向的对象的引用值减一(各引擎具体实现不同,这里描述的是原理)。

这也就是Javascript中常用到的闭包模式的原理。如果从传统面向对象语言的角度去看,闭包模式看上去很诡异;但是在理解了Javascript的执行上下文后,闭包模式就是一种很自然的代码编写模式。

4. 原型

由于Javascript中没有类的概念,因此也没有面向对象中的继承的概念。在完全没有任何继承机制的编程语言中,每个对象的方法都要明确设置一遍。假如Javascript没有继承机制,通过构造函数function A(name) {this.name= name;};创建了100个A的对象, 现在要为每个对象实现一个新的方法,就需要明确的为这100个对象都添加一个方法属性,当每个对象都有很多方法的时候,会带来巨大的性能开销和非常差的编码体验,使得代码编写方式最终会倒退到面向过程的方式。

Javascript由面向原型的编程语言self发展而来,通过原型实现了另一种方式的继承:属性共享。如果为了和面向对象中的继承区分,Javascript中通过原型实现的应该叫做共享。

Javascript中的原型在物理上是一个对象,可以是任意对象;原型这个词也表示一种机制。

每个对象都可以拥有一个原型,同时这个原型本身还可以有自己的原型,形成一个原型链,直到其原型为null的原型。

当获取对象的一个属性值的时候,先在当前对象的键值对集合中查找这属性,如果找到返回对应的值;如果没有,则在原型对象的键值对集合中查找,如果还没找到,则在原型的原型中查找,以此类推。

通过一个示例来演示原型的使用方法:

上面例子中,PersonPrototype就是原型对象,Person是构造函数,将Person的prototype属性设置为PersonPrototype对象,那么通过new Person创建的所有对象的原型都是PersonPrototype。

通过示例可以看到,修改原型中showMyName方法的定义,p.showMyName()的输出也会跟着发生变化,这个现象和上面原型的定义一致。

如果明确的为对象p设置一个showMyName方法,那么p对象的键值对集合中将也包含showMyName的定义,根据上面规则的描述的规则,p对象中定义的showMyName将被使用,忽略了原型中对showMyName的定义。这个时候,我们可以通过p.__proto__.showMyName来访问原型中的showMyName方法,但是调用p.__proto__.showMyName的时候,this关键字绑定到了原型对象PersonPrototype,由于原型对象中没有name属性的定义,因此输出“undefined!”。

接下来再定义几个Person对象:

在上述代码中,所有Person对象都共享了原型对象的方法,除非某个Person对象中重新定义了原型中同名的方法。

在对象中定义与原型中同名的属性时,会在该对象中创建一个新的键值对,而不会覆盖原型中同名属性的值。

一般来说原型对象中通常定义方法和常量,不应该定义对象的状态值,因为多数情况下所有的对象共享一个状态值没有实际意义。比如上面的代码中,name属性在逻辑上不应该被定义在原型中,因为每个人都有自己的名字。

方法是最适合定义在原型中的。共享方法给所有的对象,正是原型的主要作用。

5. 结论

本文介绍了Javascript的三个核心概念:对象、执行上下文和原型。这些是Javascript最重要的内容,理解这三点之后,很快就能掌握Javascript。

Javascript代码中各类表达式与Java基本相同。

Javascript包括很多预定义的类型、对象和对象属性,比如全局对象及其属性,JSON类型和RegExp类型等等,这些查阅手册即可。

当然,还有很多细节性的东西,例如:如果不明确设置Person的原型,该原型默认会是一个Person类型的对象;constructor属性的作用。有机会将在后续章节中展开讨论。

Javascript本质第一篇:核心概念的更多相关文章

  1. Javascript本质第二篇:执行上下文

    在上一篇文章<Javascript本质第一篇:核心概念>中,对Javascript执行上下文做了解释,但是这些都是基于Javascript标准中对执行上下文的定义,也就是说理论上的东西,本 ...

  2. 学习 JavaScript (四)核心概念:操作符

    JavaScript 的核心概念主要由语法.变量.数据类型.操作符.语句.函数组成,前面三个上一篇文章已经讲解完了.后面三个内容超级多,这篇文章主要讲解的是操作符. 操作符 什么叫做操作符? 这是一种 ...

  3. 学习 JavaScript (三)核心概念:语法、变量、数据类型

    JavaScript 的核心概念主要由语法.变量.数据类型.操作符.语句.函数组成,这篇文章主要讲解的是前面三个,后面三个下一篇文章再讲解. 01 语法 熟悉 JavaScript 历史的人应该都知道 ...

  4. vue-learning:40 - Vuex - 第一篇:概念和基本使用

    vuex 第一篇 目录 vuex概念 state / mapState getter / mapGetter mutation / mapMutation action / mapAction mod ...

  5. Vue入门教程 第一篇 (概念及初始化)

    注:为了本教程的准确性,部分描述引用了官网及网络内容. 安装Vue 1.使用npm安装vue: npm install vue 2.下载使用js文件: https://vuejs.org/js/vue ...

  6. 学习 JavaScript (六)核心概念:函数

    基本知识 函数对于我们来说,不算陌生的东西.中学就已经有了函数的概念,比如: y = f(x) 输入一个数 x,能够得到与之对应的一个数 y.也就是说,f(x) 的有一个返回值,这是函数在数学上的定义 ...

  7. 学习 JavaScript (五)核心概念:语句

    语句 语句被称作是流控制语句,通常有标志性的一个或者多个关键字,if . do-while. while.for. for-in. label. break.continue.with.switch. ...

  8. JavaScript学习第一篇

    在学习之前让我们了解了解JavaScript的由来 Javascript是一种web技术,最初起名叫LiveScript,它是Netscape开发出来一种脚本语言,其目的是为了扩展基本的Html的功能 ...

  9. android学习第一篇 基本概念

    一.   1.  Android 四大組件 Activity , Service  , BroadcastReceiver ,ContentProvider 2.  多個Activity組成棧,當前A ...

随机推荐

  1. WebService技术(二)— CXF

    前言:学习笔记,以供参考 Apache CXF 是一个开源的 Services 框架,CXF 帮助您利用 Frontend 编程 API 来构建和开发 Services .可以与Spring进行快速无 ...

  2. 前端优化 - 打开速度1s

    先看一下网页的加载流程: 1.解析html结构2.加载外部脚本和样式表文件3.解析并执行脚本(脚本会阻塞页面的加载)4.DOM树构建完成 (DOMContentLoaded)5.加载图片等外部文件6. ...

  3. MVC5项目中添加Wep API

    一.查看MVC版本,决定你有没有必要看这篇文章 打开web.config,看到以下内容 <dependentAssembly> <assemblyIdentity name=&quo ...

  4. 使用mongodump将mongodb数据备份带JOSN文件

    备份: 首先,mongodb要连接到指定数据库 在指定数据库目录下,shift+右键--在此次打开命令行--输入以下命令: mongodump -d databaseName -o backup 备份 ...

  5. 单链表、循环链表的JS实现

    数据结构系列前言: 数据结构作为程序员的基本知识,需要我们每个人牢牢掌握.近期我也展开了对数据结构的二次学习,来弥补当年挖的坑......   当时上课的时候也就是跟着听课,没有亲自实现任何一种数据结 ...

  6. C#调用win32 api程序实例

    1.声明static extern 方法,使用DllImport特性 class MyClass { [DllImport("kernel32", SetLastError = t ...

  7. JavaScript 中string方法

    注意:JavaScript的字符串是不可变的(immutable),String类定义的方法不能改变原来字符串内容,例如String.toUpperCase()这样的方法,返回的是全新的字符串,而不是 ...

  8. 从源代码构建 Go 开发环境

    从源代码构建 Go 开发环境 Go 1.5 之前的版本 安装C 语言开发环境 在Go 1.5 之前的版本(比如 1.3.1.4),都会部分的依赖 C 语言的工具链,所以如果你有C 语言的开发环境,就可 ...

  9. js返回顶部效果

    当用户浏览的网页过于长的时候,用户在浏览到网页底部想要在返回顶部需要滚动好几次滚轮才能返回顶部,不仅麻烦,而且用户体验也会很差.现在的大多是页面都会在页面顶部或者是页面的可见区域的某一位置固定一个按钮 ...

  10. webservice 小小例子

    Web Service的主要目标是跨平台的可互操作性.为了实现这一目标,Web Service 完全基于XML(可扩展标记语言).XSD(XML Schema)等独立于平台.独立于软件供应商的标准,是 ...