Salesforce入门教程(中文)-022 学习JavaScript的核心概念

1.学习JavaScript的核心概念

在21世纪初,软件世界正在爆发出这样的想法:你可以建立完全通过互联网托管和交付的应用程序。
虽然我们现在认为网络应用是理所当然的,但在当时,它们就像看到机器人骑自行车一样令人心动。

浏览器是简单的HTML渲染器,而HTML和JavaScript标准是零散的。
为了创建一个具有轻微复杂功能的网页,你不得不强迫用户只使用一个浏览器,通常是IE浏览器。即使在今天,也有一些应用程序因为这个时代的设计决定而强制使用这种浏览器。

为了解决这些限制,服务器端UI框架的发展使软件开发者能够在服务器上动态地创建网页。
复杂的逻辑在有计算能力的地方执行:在服务器上。
然后将渲染好的HTML提供给孱弱的浏览器。
在这个世界上,JavaScript主要是使网页具有一定的互动性,并在没有服务器的情况下执行基本的逻辑。
服务器端框架非常流行,包括Salesforce框架Visualforce。
作为这种流行的证明,今天在Salesforce中有数百万的Visualforce页面。

快进到现在,世界是一个不同的地方。
浏览器是强大的应用程序,可以优化网页浏览。
JavaScript围绕ECMAScript标准进行了很好的标准化,而且顶级浏览器制造商一般都会很好地采用新功能。
今天的网络应用有丰富的用户界面,在浏览器中运行现代的JavaScript。
现代网络应用不是服务器端的框架,而是倾向于在客户端渲染。
在Salesforce中,这是由Lightning组件框架完成的。
但对于许多开发人员来说,编写JavaScript仍然是一件新鲜事。
如果你大部分时间都在使用Visualforce页面和Apex控制器,你可能需要一个台阶来真正了解JavaScript的工作原理,这样你才能更好地理解你的组件。

2.JavaScript的运行时间
JavaScript运行时是一个解释JavaScript代码的引擎。
它可以是浏览器的一部分,也可以是服务器等其他运行环境。
现代的JavaScript引擎是复杂而强大的,可以优化执行,而且设计上符合ECMAScript标准。

JavaScript引擎的决定性特征是一个单线程的运行时间,由下面的堆栈表示。
栈中正在进行的工作拥有线程,并且必须在交还线程控制权之前完成其同步逻辑。

运行时是一个繁忙的地方。
新的工作可以在任何时候从多个源头进来,包括用户(UI事件)和网络API(如地理位置或设备运动)。
由于只有一个线程,所以有一个队列,工作在那里等待轮到使用线程。

当堆栈为空时,事件循环从队列中取出等待完成的工作并将其移入堆栈。

 当然,这只是一种简化,但说明了JavaScript引擎如何完成工作的基本模式。因为这个架构,JavaScript语言在实践中才会有这样的工作方式。

3.JavaScript语言特点

JavaScript正在发生变化

因为JavaScript是根据ECMAScript标准建立的,所以它一直在变化。
每年都会发布描述新功能的标准更新,然后JavaScript引擎项目(浏览器和运行时制造商)将其投入使用。

随着JavaScript的成熟,更新可以包括更多的现代语言特性。
在其他情况下,功能被添加以实现现有功能的清洁语法(这些被称为语法糖syntactic sugar)。

API的采用并不普遍

这句话看起来很吓人,但绝大多数的JavaScript API都能在最常见的浏览器平台上运行。
不过,实施者并没有以同样的速度采用每一种语言特性或API。
有些人从不采用某些功能(虽然这种情况很少)。
一般来说,如果你想使用一个较新的语言特性,你应该通过caniuse.com这样的资源了解它在你的目标浏览器中的工作情况。

如果一个新的功能没有被原生地实现,通常会有一些代码被编写出来,以暂时满足该功能缺失的目的。
这种临时填补的代码被称为polyfill。
事实上,Lightning组件框架使用一个精心策划的polyfills列表,在其他代码运行前应用,以自动改善浏览器的兼容性。 

大小写敏感

JavaScript是区分大小写的。
这对许多习惯于Apex和SOQL不区分大小写的Salesforce开发人员来说很棘手。
请记住,在Salesforce中编写JavaScript代码时,一定要注意大小写的敏感性。

4.声明变量

变量的声明是通过三个运算符之一完成的:var、let和const。
一般来说,使用let和const。
下表总结了这三个关键字之间的功能差异。

关键字        范围        可变的分配
var             function        yes
let              block            yes
const         block             no

所有的变量都是指针。
赋值是指将该变量指向内存中的某个东西的行为。
可变性是指一旦一个变量最初被赋值,它是否可以被重新赋值。
使用var或let会产生可变的指针,而const是不可变的。
通常情况下,这一点最好通过演示来理解。

//primitive assignments
var myBike = "Mountain Bike";
let currentGear = 5;
const numberOfGears = 12;
//reassignment
myBike = "Penny Farthing"; // this works
currentGear = 1; // so does this
numberOfGears = 1; // error

上面,myBike和currentGear在被重新赋值时没有问题。但是当试图对numberOfGears这样做时,就出现了错误。

当使用对象(而不是原生primitives)时,const会阻止将你的变量重新分配给一个不同的对象。
对象本身(它的属性、函数等等)仍然可以被改变。

// call constructor, new object, assign it to bike
const bike = new Bike();
//Change internal state by calling a function
bike.changeGear("front", "Up");
// add a new member to bike that did not exist before
bike.type = "Penny Farthing";
// check for success
console.log(bike.calculateGearRatio()); // 4.0909...
console.log(bike.type); // "Penny Farthing"
// attempt to point bike to new instance of Bike
bike = new Bike(1,2); // error

在这里,我们从自行车构造函数中创建一个对象,并将其分配给自行车变量(记住,要区分大小写)。
然后,我们可以对其进行任何改变,比如调用改变其状态的函数,甚至添加新的成员。
但当我们试图将bike重新赋值给其他东西时,在这种情况下,再次调用构造函数,就会出现错误。

5.隐式类型强制法

当大多数JavaScript操作者遇到一个无效的类型时,他们会试图将该值转换为一个有效的类型。
这种隐式转换类型的过程被称为隐式类型强制。
考虑一下下面的情况。

let num1 = 9 * "3";
console.log(num1); // 27 (a number)
let num2 = 9 + "3";
console.log(num2); // "93" (a string)

在第一个例子中,*运算符只能用于数学运算,将字符串 "3 "胁迫成一个数字。
其结果是27。
在第二个例子中,+运算符看到了字符串 "3",使其成为一个单项运算符(连接)。
这就把9压缩成了字符串 "9",结果是字符串 "93"。

乍一看,这似乎很方便,但在实践中会导致混乱的结果。
所以不要使用隐式类型强制法!!!

许多隐式类型强制的例子是令人困惑的。
例如,布尔比较。
C族语言中常见的==和!=比较运算符将试图把任何东西转换为布尔型。
有一些确定的规则,但它们太复杂了,不实用。
这里有一些有趣的例子。

false == ""; // true
false == "0"; // true
"" == "0"; // false
[0] == 0; // true

"为什么会这样做?" 正是如此。对于布尔比较,最好的做法是使用===和!==。
使用这些运算符,原始类型只有在类型和值都匹配时才是等价的,而对象比较只有在它们各自的指针指向同一个内存地址时才是真的。
试着进行与上面相同的比较。

false === ""; // false
false === "0"; // false
"" === "0"; // false
[0] === 0; // false

6.Truthy和Falsy

你知道我们刚刚制定的那个警告反对隐式类型强迫的规则吗?
那么,这里有一个例外。

当一个表达式期望一个布尔值时,以下值总是被视为false。

false
0(数字0)
"" 或 '' (一个空字符串)
null
undefined
NaN(数学运算失败的结果)

false是假的(当然了!)。
其余的这些值都被胁迫为false。
作为一个群体,它们被称为falsy。
任何其他类型的值都被强制为真时,我们称这些值为truthy。

这有一个很方便的副作用。
假设你想通过简单地将一个变量传入if表达式来测试几种类型的无效数据。

const myRecord = response.getReturnValue();
if (myRecord) {
  //now process the record
}

如果由于某种原因,上面的赋值失败了,我们最终得到了一个未初始化的变量(undefined),一个空字符串,或者0,我们仅仅通过对myRecord变量进行条件检查,就已经涵盖了所有这些基础。
这是JavaScript中广泛接受的一种做法。

this是Tricky

本模块有一整节是关于如何使用this指针的。
它有明确的规则,但即使在同一个函数中,this指向的内容也会发生变化。
例如,在一个Apex类中,你可能会看到。

public class MyApexClass {
  private String subject;
  public MyApexClass(String subject) {
    this.subject  = subject;
  }
}

在这个例子的Apex类中,这只指MyApexClass的当前实例。
在JavaScript中,它所指向的不是一个函数的定义位置,而是该函数的调用位置。
稍后会有更多关于这个的内容。

函数Functions是值

在JavaScript中,所有东西都是一个对象。
这对函数来说也是如此。
像其他对象一样,函数可以被分配给变量,传递给其他函数的参数,并以与其他对象相同的方式使用。

如果你没有在函数是一等公民的语言中工作过,或者没有使用过lambdas,这可能会让你有点震惊。
以后我们会花一整个单元来讨论函数。

现在,你已经对JavaScript的概念有了很好的基本介绍。接下来,我们看看JavaScript是如何在浏览器中工作的。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一秒变桌子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值