初学者的JavaScript基础

我们今天发布的翻译材料专门针对JavaScript的基础知识,供初学者使用。 可以将其视为对JS基本结构的小参考。 特别是在这里,我们将讨论数据类型系统,变量,数组,函数,对象原型以及语言的其他一些特性。



原始数据类型


JavaScript中提供以下原始数据类型: numberbooleanstringundefinednull 。 应当立即指出,当使用原始数据类型(例如,使用字符串文字)时,即使不执行显式转换,我们也将能够访问其方法和属性。 这里的要点是,当尝试执行此类操作时,文字会自动配备适当的对象包装器。

▍数字


JavaScript只有一种类型的数字-它是双精度浮点数。 这导致某些表达式的计算结果在算术上不正确的事实。 您可能已经知道,在JS中,表达式0.1 + 0.2不是0.3 。 同时,在使用整数时,未观察到此类问题,即1 + 2 === 3

JavaScript有一个Number对象,它是数字值的对象包装。 可以使用格式为var a = new Number(10)的命令来创建Number类型的对象,也可以依赖上述系统的自动行为。 特别是,这允许您调用应用于数字文字的Number.prototype存储的方法:

 (123).toString();  //"123" (1.23).toFixed(1); //"1.2" 

全局函数旨在将其他类型的值转换为数字类型。 这是parseInt()parseFloat()Number()构造,在这种情况下,它们充当执行类型转换的普通函数:

 parseInt("1")       //1 parseInt("text")    //NaN parseFloat("1.234") //1.234 Number("1")         //1 Number("1.234")     //1.234 

如果在使用数字进行运算的过程中获得的内容不是数字(在进行一些计算或尝试将某物转换为数字时),则JavaScript不会抛出错误,但会以数值NaN (非整数,不是数字)。 为了检查某个值是否为NaN ,可以使用isNaN()函数。

JS算术运算以相当熟悉的方式工作,但是您需要注意一个事实,即+运算符可以执行数字加法和字符串连接。

 1 + 1      //2 "1" + "1"  //"11" 1 + "1"    //"11" 

▍弦


JavaScript字符串是Unicode字符串。 字符串文字是通过用双引号( "" )或单引号()引起来的文本来创建的。 如前所述,在处理字符串文字时,我们可以依赖于相应的对象包装器,该对象包装器的原型具有许多有用的方法,其中包括substring()indexOf()concat()

 "text".substring(1,3) //ex "text".indexOf('x')   //2 "text".concat(" end") //text end 

像其他原始值一样,字符串是不可变的。 例如, concat()方法不会修改现有的字符串,而是创建一个新的字符串。

▍逻辑值


JS中的逻辑数据类型由两个值truefalse 。 该语言可以自动将各种值转换为逻辑数据类型。 因此,除了逻辑值falsefalse还包括值nullundefined'' (空字符串), 0NaN 。 其他所有事物,包括任何物体,都代表着真正的意义。 在逻辑运算过程中,所有被认为是true东西都将转换为true ,而所有被认为是false的东西都将转换为false 。 看下面的例子。 根据上述原理,空字符串将被转换为false并且由于执行此代码,字符串This is false将进入控制台。

 let text = ''; if(text) { console.log("This is true"); } else { console.log("This is false"); } 

对象


对象是由键值对组成的动态结构。 值可以具有原始数据类型,可以是对象或函数。

使用对象文字语法最容易创建对象:

 let obj = { message : "A message", doSomething : function() {} } 

可以随时读取,添加,编辑和删除对象的属性。 方法如下:

  • 读取属性: object.name, object[expression]
  • 将数据写入属性(如果所访问的属性不存在,则添加具有指定键的新属性): object.name = valueobject[expression] = value
  • 删除属性: delete object.namedelete object[expression]

以下是一些示例:

 let obj = {}; //    obj.message = "A message"; //    obj.message = "A new message"; //   delete object.message; //   

语言中的对象被实现为哈希表。 可以使用Object.create(null)命令创建一个简单的哈希表:

 let french = Object.create(null); french["yes"] = "oui"; french["no"]  = "non"; french["yes"];//"oui" 

如果需要使对象不可变,则可以使用Object.freeze()命令。

要遍历对象的所有属性,可以使用Object.keys()命令:

 function logProperty(name){ console.log(name); //  console.log(obj[name]); //   } Object.keys(obj).forEach(logProperty); 

primitive比较原始类型和对象的值


如前所述,在使用原始值的实际工作中,您可以将它们视为具有属性和方法的对象,尽管它们不是对象。 原始值是不可变的,对象的内部结构可以改变。

变数


在JavaScript中,可以使用varletconst关键字声明变量。

使用var关键字,您可以声明一个变量,并在必要时使用某个值对其进行初始化。 如果未初始化变量,则其值为undefined 。 使用var关键字声明的变量具有功能范围。

let关键字与var非常相似,不同之处在于用let关键字声明的变量具有块范围。

使用const关键字声明的变量也具有块作用域,鉴于这样的变量的值不能更改,因此将其更正确地称为“常量”。 可以将“冻结”使用它声明的变量的值的const关键字与“冻结”对象的Object.freeze()方法进行比较。

如果在函数外部声明变量,则其范围是全局的。

数组


JavaScript中的数组是使用对象实现的。 结果,在谈论数组时,我们实际上讨论的是与数组相似的对象。 您可以使用数组元素的索引来使用它们。 数字索引将转换为字符串,并用作访问数组元素值的名称。 例如, arr[1]形式的构造类似于arr['1']形式的构造,并且两者都将访问相同的值: arr[1] === arr['1'] 。 根据上述内容,由命令let arr = ['A', 'B', 'C']声明的简单数组表示为以下形式的对象:

 { '0': 'A', '1': 'B', '2': 'C' } 

使用delete命令删除数组元素会在其中留下孔。 为了避免出现此问题,可以使用splice()命令,但是它运行缓慢,因为删除一个元素后,它会将数组的其余元素移动,实际上将它们移到数组的开头,即左侧。

 let arr = ['A', 'B', 'C']; delete arr[1]; console.log(arr); // ['A', empty, 'C'] console.log(arr.length); // 3 

数组方法使实现诸如堆栈和队列之类的数据结构变得容易:

 //  let stack = []; stack.push(1);           // [1] stack.push(2);           // [1, 2] let last = stack.pop();  // [1] console.log(last);       // 2 //  let queue = []; queue.push(1);           // [1] queue.push(2);           // [1, 2] let first = queue.shift();//[2] console.log(first);      // 1 

功能介绍


JavaScript中的函数是对象。 可以将函数分配给变量,存储在对象或数组中,作为参数传递给其他函数,并从其他函数返回。

有三种方法来声明函数:

  • 经典函数声明(函数声明或函数声明)。
  • 使用函数表达式(Function Expression),也称为函数文字(Function Literal)。
  • 使用箭头函数(箭头函数)的语法。

▍经典函数声明


使用这种声明函数的方法,适用以下规则:

  • 函数声明行中的第一个关键字是function
  • 必须为功能分配一个名称。
  • 由于可以将函数的声明提升到声明它的作用域的顶部,因此该函数可以在声明之前的代码中使用。

这是经典函数声明的样子:

 function doSomething(){} 

▍函数式


使用函数表达式时,应考虑以下几点:

  • function关键字不再是函数声明行中的第一个单词。
  • 函数名称是可选的。 可以同时使用匿名和命名函数表达式。
  • 用于调用此类功能的命令应遵循其声明的命令。
  • 在声明之后,可以使用IIFE(立即调用的函数表达式-立即称为函数表达式)的语法立即启动此类函数。

函数表达式如下所示:

 let doSomething = function() {} 

▍箭头功能


实际上,箭头函数可以被认为是创建匿名函数表达式的“语法糖”。 应该注意的是,这样的函数没有它们自己的实体thisarguments 。 箭头函数声明如下所示:

 let doSomething = () = > {}; 

to调用函数的方式


可以通过多种方式调用函数。

正常功能调用


 doSomething(arguments) 

对象方法形式的函数调用


 theObject.doSomething(arguments) theObject["doSomething"](arguments) 

构造函数调用


 new doSomething(arguments) 

使用apply()方法调用函数


 doSomething.apply(theObject, [arguments]) doSomething.call(theObject, arguments) 

使用bind()方法调用函数


 let doSomethingWithObject = doSomething.bind(theObject); doSomethingWithObject(); 

可以使用比声明函数时指定的参数数量更多或更少的参数来调用函数。 在函数的工作过程中,“额外”参数将被简单地忽略(尽管函数可以访问它们),缺少的参数将获得undefined的值。

函数具有两个伪参数: thisarguments

this关键字这里


this表示函数的上下文。 它指向的值取决于函数的调用方式。 根据函数的调用方式, this关键字的含义如下(它们在上面通过代码示例进行了描述,在此使用了其构造):

  • 通常的函数调用是window / undefined
  • 对象方法形式的函数调用是theObject
  • 构造函数形式的函数调用是一个新对象。
  • 使用apply()方法theObject调用函数。
  • 使用bind()方法theObject调用函数。

▍关键字参数


arguments关键字是一个伪参数,可以访问用于调用该函数的所有参数。 它看起来像一个数组,而不是一个数组。 特别是,它没有数组方法。

 function reduceToSum(total, value){ return total + value; } function sum(){ let args = Array.prototype.slice.call(arguments); return args.reduce(reduceToSum, 0); } sum(1,2,3); 

arguments关键字的替代方法是其余参数的新语法。 在以下示例中, args是一个数组,其中包含调用时传递给函数的所有内容。

 function sum(...args){ return args.reduce(reduceToSum, 0); } 

▍操作员返回


没有return函数将返回undefined 。 使用return关键字,请注意自动分号插入机制的工作方式。 例如,以下函数将不返回空对象,而是返回undefined值:

 function getObject(){ return { } } getObject() 

为了避免类似的问题,必须将大括号放在与return相同的行上:

 function getObject(){ return { } } 

动态打字


JavaScript是一种动态的打字语言。 这意味着特定值具有类型,而变量则没有。 在程序执行期间,可以将不同类型的值写入同一变量。 这是处理不同类型值的函数的示例:

 function log(value){ console.log(value); } log(1); log("text"); log({message : "text"}); 

要找出存储在变量中的数据类型,可以使用typeof()运算符:

 let n = 1; typeof(n);   //number let s = "text"; typeof(s);   //string let fn = function() {}; typeof(fn);  //function 

单线程执行模型


JavaScript运行时是单线程的。 尤其是这表现为无法同时执行两个功能(如果您不考虑异步代码执行的可能性,在此不再赘述)。 运行时有一个所谓的事件队列,它存储需要处理的任务列表。 结果,对于单线程JS执行方案,资源互锁的问题并不常见,因此,这里不需要锁定机制。 但是,落入事件队列的代码必须快速执行。 如果您的工作繁重,则在浏览器应用程序的主线程中,应用程序页面将不响应用户操作,浏览器将提供关闭此页面的功能。

异常处理


JavaScript具有处理异常的机制。 它根据此类机制的常见原理进行工作:使用try/catch构造执行可能导致错误的代码。 代码本身在try块中,错误在catch中处理。

有趣的是,有时在紧急情况下JavaScript不会产生错误消息。 这是由于在采用ECMAScript 3标准之前JS不会引发错误。

例如,在下面的代码片段中,尝试更改“冻结”对象将失败,但是不会引发异常。

 let obj = Object.freeze({}); obj.message = "text"; 

某些“无提示的” JS错误以严格模式显示;您可以使用"use strict";构造将其启用"use strict";

原型系统


此类JS机制(如构造函数, Object.create()命令, class关键字)的基础是原型系统。
考虑以下示例:

 let service = { doSomething : function() {} } let specializedService = Object.create(service); console.log(specializedService.__proto__ === service); //true 

在这里,为了创建一个specializedServiceservice对象,该对象的原型是制作一个service对象,使用了Object.create()命令。 结果,事实证明可以通过访问specializedService对象来调用doSomething()方法。 此外,这意味着__proto__对象的__proto__属性指向service对象。

现在,使用class关键字创建一个类似的对象:

 class Service { doSomething(){} } class SpecializedService extends Service { } let specializedService = new SpecializedService(); console.log(specializedService.__proto__ === SpecializedService.prototype); 

Service类中声明的方法将被添加到Service.prototype对象。 Service类的实例将具有相同的原型( Service.prototype )。 所有实例都将方法调用委托给Service.prototype对象。 结果,结果表明方法仅在Service.prototype中声明一次,之后,该类的所有实例都会“继承”这些方法。

▍原型链


对象可以是其他对象的“继承人”。 每个对象都有一个原型,可以使用其方法。 如果您尝试访问不在对象本身中的属性,JavaScript将开始在原型链中搜索它。 该过程将一直持续到找到属性或搜索到达链的末尾为止。

关于JavaScript中的函数式编程


在JavaScript中,函数是一类对象;该语言支持闭包机制。 这为在JS中实现函数式编程技术开辟了道路。 特别是,我们正在谈论使用高阶函数的可能性。

闭包是一个内部函数,即使在执行父函数之后,也可以访问在父函数内部声明的变量。

高阶函数是可以将其他函数用作参数,返回函数或同时执行两者的函数。

许多出版物都介绍了JS中的函数式编程。 如果您有兴趣,这里有一些有关该主题的资料,这些资料专门用于函数样式编写的一流函数组合修饰符闭包可读性

总结


JavaScript的强大之处在于其简单性。 了解语言的基本机制后,使用JS的程序员可以更有效地应用这些机制,并为他的专业发展奠定基础。

亲爱的读者们! 您认为大多数新手会导致JavaScript的哪些功能?

Source: https://habr.com/ru/post/zh-CN416375/


All Articles