成为一个高效的JavaScript开发者的秘诀之一就是真正理解这门语言的语义。本文将会通过通俗易懂的图表来解释JavaScript中最基本的核心内容。

随处可见的引用

简单来说,JavaScript中的变量就是对内存中某个值的引用。这里的值可以是基本类型,如strings, numbers, booleans,也可以是引用类型如objects和functions。

局部变量

下面这个例子中,我们在最上层作用域内创建了四个局部变量,并将它们指向基础类型的值。

1 // Let's create some local variables in the top scope
2 var name = "Tim Caswell";
3 var age = 28;
4 var isProgrammer = true;
5 var likesJavaScript = true;
6 // Test to see if the two variables reference the same value
7 isProgrammer === likesJavaScript;
1 Output
2 => true

我们发现这两个布尔类型的变量在内存中指向同一个值。这是因为基础类型的值都是不可变的,所以虚拟机可以优化成让所有的引用都指向同一个值(译者注:为了节省内存开销)。

在上面的代码中我们用恒等号===检查这两个变量的引用是否为同一个值,测试结果为true。

图中黄色矩形代表最上层的作用域。里面的变量是最上层作用域中的局部变量,千万不要与全局对象的属性混淆。

对象与原型链

对象就是拥有对其他对象和原型引用的集合。除此之外,还有唯一特殊的就是原型链,通过原型链,可以访问在局部对象不存在而在其父级对象上的属性。

01 // Create a parent object
02 var tim = {
03   name: "Tim Caswell",
04   age: 28,
05   isProgrammer: true,
06   likesJavaScript: true
07 }
08 // Create a child object
09 var jack = Object.create(tim);
10 // Override some properties locally
11 jack.name = "Jack Caswell";
12 jack.age = 4;
13 // Look up stuff through the prototype chain
14 jack.likesJavaScript;
1 Output
2 => true

上述代码中,我们把一个有四个属性的对象赋给了变量tim,然后又创建了一个继承tim的新对象并赋给变量jack。接着我们在局部对象中重写了两个属性。

现在当我们要访问jack.likesJavaScript的时候,首先要在jack引用的对象中查找thelikesJavaScript属性,如果不存在再去父级对象中查找,最后我们在变量tim引用的对象中找到了这个属性值为true。

全局对象

是不是很想知道为什么像jslint这类工具总是提醒你要在声明变量前加上var,下面这个例子就很好的解释了原因。

1 var name = "Tim Caswell";
2 var age = 28;
3 var isProgrammer = true;
4 // Oops we forgot a var
5 likesJavaScript = true;

可以发现上述代码中的likesJavaScript并不是最上层闭包中的一个自由变量而是全局对象的一个属性。虽然这点只有当你尝试将很多脚本混合在一起的时候才可能遇到麻烦,但是我们还是应该避免在实际开发中出现省略var的情况。

为了保证变量在当前闭包和它的子闭包内,就要时刻记住在变量声明前加上var。这条简单的准则,对你有利无害。

如果一定要在全局对象上添加属性,浏览器中,可以像这样添加:window.woo,在nodejs中,可以像这样添加:global.goo

函数和闭包

JavaScript不仅仅是一组链式数据结构。它还有函数(一种可执行、可调用的代码片段)。这些函数形成链式作用域和闭包。

了解闭包

函数可以理解成一种包含可执行代码和属性的特殊对象。每一个函数都有一个 [scope]属性,这个属性存储着函数在定义时所在的上下文环境。当一个函数返回的时候,其所在的上下文环境就会被销毁,当前上下文也会切换到该函数调用者所在的上下文。

在下面这个例子中,我们创建了一个简单的工厂方法用来生成一个闭包并且返回一个函数。

1 function makeClosure(name) {
2   return function () {
3     return name;
4   };
5 }
6 var description1 = makeClosure("Cloe the Closure");
7 var description2 = makeClosure("Albert the Awesome");
8 console.log(description1());
9 console.log(description2());
1 Output
2 Cloe the Closure Albert the Awesome

当我们调用函数description1()的时候,虚拟机查找它引用的函数并执行该函数。该函数执行过程中需要访问名为name的局部变量,它在闭包作用域中找到了它。当想为每一个生成的函数分配单独的空间存储局部变量的时候,工厂方法是一个非常不错的选择。

可以看看这篇文章why use closure ,将对你深入了解闭包会有很大帮助。

共享函数和THIS

有时候出于性能的考虑,或者仅仅是因为你青睐某种风格,JavaScript提供了一个this关键字,this允许你重用一个函数对象,通过不同的调用方式,该对象所在的作用域也不同。

01 var Lane = {
02   name: "Lane the Lambda",
03   description: function () {
04     return this.name;
05   }
06 };
07 var description = Lane.description;
08 var Fred = {
09   description: Lane.description,
10   name: "Fred the Functor"
11 };
12 // Call the function from four different scopes
13 console.log(Lane.description());
14 console.log(Fred.description());
15 console.log(description());
16 console.log(description.call({
17   name: "Zed the Zetabyte"
18 }));
1 Lane the Lambda Fred the Functor undefined Zed the Zetabyte

上述图表中,我们可以看出虽然将Fred.description设置成Lane.description,但依然指向那个函数。因此,这三个引用都拥有那个匿名函数的平等所有权。这就是为什么我尽量不调用构造原型中的方法,因为如果我这么做的话就意味着我将函数绑定到了对象本身和构造函数上。(如果想更加深入的了解this,可以看这篇文章 what is this)

总结

我已经乐此不疲地用图表阐述了这些数据结构。我希望这篇文章能够帮助大家更好的理解JavaScript的精髓。我有过前端开发、后端开发和服务端架构经验。我希望我这种独特的方式能够帮助来自全球各地的开发者更好的了解JavaScript的内部机制。

原文链接/译文链接

图解Javascript核心内容相关推荐

  1. javascript核心_只需几分钟即可学习这些核心JavaScript概念

    javascript核心 Sometimes, you just want to learn something quickly. And reading through comprehensive ...

  2. ES6/ES2015核心内容-转载

    传送门:http://www.cnblogs.com/doit8791/p/5184238.html ECMAScript定义了: JS语言语法 – 语法解析规则.关键字.语句.声明.运算符等. 类型 ...

  3. 30分钟掌握ES6/ES2015核心内容(上) 1

    ECMAScript 6(以下简称ES6)是JavaScript语言的下一代标准.因为当前版本的ES6是在2015年发布的,所以又称ECMAScript 2015. 也就是说,ES6就是ES2015. ...

  4. 黑马JavaScript核心操作BOM与DOM课程笔记1-DOM

    一.Web APIs 简介 此部分的目标:能够说出 Web APIs 阶段与 JavaScript 语法阶段的关联性: 能够说出什么是 API: 能够说出什么是 Web API. 1. Web API ...

  5. JavaScript核心 DOM 和 BOM操作

    JavaScript核心 DOM 和 BOM操作 Web APIs 简介 1. Web APIs 和 JS 基础关联性 1.1 JS 的组成 1.2 JS 基础阶段以及 Web APIs 阶段 JS ...

  6. JavaScript核心知识第二章---事件高级(含大量代码分析)

    前言 ❤️ 一个人有多重的才华,骨子里就会刻上多大重量的谦卑 ❤️ JavaScript核心知识第二章---事件高级 一.JavaScript 事件高级 (1)注册事件(绑定事件) 1.1 注册事件概 ...

  7. JavaScript核心笔记未完

    JavaScript核心 Web API阶段 DOM BOM 操作 js基础是语法阶段 web API阶段是应用 主要是BOM DOM 页面交互功能 1.API 和Web API 1.1API (应用 ...

  8. JavaScript核心1

    JavaScript核心1 Web API阶段 DOM BOM 操作 js基础是语法阶段 web API阶段是应用 主要是BOM DOM 页面交互功能 1.API 和Web API 1.1API (应 ...

  9. 视频教程-2020年前端面试/晋级必修,60分钟掌握JavaScript核心算法-JavaScript

    2020年前端面试/晋级必修,60分钟掌握JavaScript核心算法 十年前端开发经验,熟练掌握vue及react技术栈. 李雄 ¥39.00 立即订阅 扫码下载「CSDN程序员学院APP」,100 ...

最新文章

  1. 微信红包要哭了...给抢红包设计一个新交互
  2. 无极菜单 php,ThinkPHP菜单无极分类 ThinkPHP菜单无极分类实例讲解
  3. TestNg依赖详解(三)------灵活的文件配置依赖
  4. SAP Spartacus初始化时和user token相关的APP INITIALIZER
  5. linux脚本写的计算器,一步步打造自己的linux命令行计算器
  6. Linux环境Elasticsearch6.xxx 之kibana可视化工具操作索引
  7. 强化学习《基于策略价值 - Asynchronous Adventage Actor-Critic》
  8. php自动载入类文件函数,我可以在没有PHP的类中自动加载函数文件吗?
  9. AWT_Swing_图片Icon
  10. 运行成功:char转换为wchar_t的代码
  11. 善于总结、不断反思做更好的自己
  12. IText生成PDF 加粗字体的代码例子
  13. iOS快速清除全部的消息推送
  14. 各大编程语言优势对比,哪些值得学习更高薪?
  15. RootBeanDefinition、ChildBeanDefinition、GenericBeanDefinition的区别
  16. 【java神操作】java竟然还可以能执行Javascript代码!!
  17. FPGA课程设计——数字电子时钟VERILOG(基于正点原子新起点开发板,支持8位或6位共阳极数码管显示时分秒毫秒,可校时,可设闹钟,闹钟开关,led指示)
  18. linux 查看 x64 x86 arm64 以及它们的区别
  19. css禁止背景图拉伸_css3 background 新添属性让你的背景图不再拉伸而是随窗口变化而变化...
  20. 程序人生 - 提前冲线!10名浙江高中生不用高考,直接被清华大学录取,杭州4位学霸来自这些学校

热门文章

  1. 分布式中间件之消息中间件
  2. 无线AP的注册上线方式
  3. Vue中 引入使用 js-pinyin 实现汉字转拼音
  4. C++中各个构造函数原理
  5. TypeError: Cannot create property ‘csrq‘ on string ‘‘“
  6. ASP.NET MVC 5 - 给电影表和模型添加新字段
  7. 华为笔记本linux驱动支持,华为笔记本电脑对Linux 5.5内核的支持得到改善
  8. 多球或嵌套(氦-3、金箔)中子能谱议在线图形化解谱软件(NSUP)
  9. DVWA指点迷津-CSP Bypass
  10. 关于安时积分法的二阶RC模型