快速掌握JavaScript面试基础知识(一)

译者按: 总结了大量JavaScript基本知识点,颇有用!javascript

为了保证可读性,本文采用意译而非直译。另外,本文版权归原做者全部,翻译仅用于学习。java


根据StackOverflow调查, 自2014年一来,JavaScript是最流行的编程语言。固然,这也在情理之中,毕竟1/3的开发工做都须要一些JavaScript知识。所以,若是你但愿在成为一个开发者,你应该学会这门语言。git

这篇博客的主要目的是将全部面试中常见的概念总结,方便你快速去了解。
(译者按:鉴于本文内容过长,方便阅读,将分为三篇博客来翻译。)github

类型和类型转换

在JavaScript中有7个内置类型:nullundefinedbooleannumberstringobject,和symbol(ES6)。面试

除了object之外,其它都叫作基本类型。编程

typeof 0 // number
typeof true // boolean
typeof 'Hello' // string
typeof Math // object
typeof null // object !!
typeof Symbol('Hi') // symbol (New ES6)
  • Null vs. Undefined

Undefined表示未定义。对于没有初始化的变量、函数调用时候未提供的函数参数、缺失的对象属性,它们的默认值就是undefined。若是一个函数没有返回语句,那么默认的返回值也是undefined数组

NUll表示值为空。一个变量咱们能够将其赋值为null,表示当前的没有值。浏览器

  • 隐式转换

请看下面的例子:编程语言

var name = 'Joey';
if (name) {
console.log(name + " doesn't share food!") // Joey doesn’t share food!
}

if语句的条件判断中,name从字符串转换为布尔型。在if的代码块中,在控制台将name原本来本打印出来。你知道在什么状况下字符串会转换为真,何时为假么?函数

""0, nullundefinedNaNfalse 会自动转换为false。其它的都会转换为真:

Boolean(null) // false
Boolean('hello') // true
Boolean('0') // true
Boolean(' ') // true
Boolean([]) // true
Boolean(function(){}) // true

空数组、对象、函数定义都会自动转换为真。

  • String & Number之间的转换

第一个你要很是当心的是+操做符。由于它同时用于数字相加和字符串拼接。

*,/,-只用于数字运算,当这些操做符和字符串一块儿使用,那么字符串会被强制转换为数字。

1 + "2" = "12"
"" + 1 + 0 = "10"
"" - 1 + 0 = -1
"-9\n" + 5 = "-9\n5"
"-9\n" - 5 = -14
"2" * "3" = 6
4 + 5 + "px" = "9px"
"$" + 4 + 5 = "$45"
"4" - 2 = 2
"4px" - 2 = NaN
null + 1 = 1
  • == vs. ===

一个普遍被接受的认知就是:==判断值是否相等,===同时判断值是否相等和类型是否相同。可是,这里有些误解。

实际上,==在验证相等性的时候,会对类型不一样的值作一个类型转换。===对要判断的值不作类型转换。

2 == '2' // True
2 === '2' // False
undefined == null // True
undefined === null // False

类型转换有不少取巧的地方,要注意:

let a = '0';
console.log(Boolean(a)); // True
let b = false;
console.log(Boolean(b)); // False
```

你认为下面的相等判断会输出什么值呢?
```js
console.log(a == b);

 

实际上会返回true。知道为何吗?
若是你将一个布尔类型的和非布尔类型的判断,JavaScript会将布尔类型的转换为数字而后再比对。
执行过程以下:

'0' == false (1)
'0' == 0 (2)
0 == 0 (3)

 

因此,最终变成了0==0,固然返回true啦。

若是你想看完整的资料,请查看ES5的官方文档

若是想看cheat sheet, 点击这里

一些比较容易掉坑的比较,我在这里列出来:

false == "" // true
false == [] // true
false == {} // false
"" == 0 // true
"" == [] // true
"" == {} // false
0 == [] // true
0 == {} // false
0 == null // false

 

值 vs. 引用

对于基本类型的值,赋值是经过值拷贝的形式;好比:nullundefinedbooleannumberstring和ES6的symbol。对于复杂类型的值,经过引用拷贝的形式赋值。好比:对象、对象包括数组和函数。

var a = 2; // 'a' hold a copy of the value 2.
var b = a; // 'b' is always a copy of the value in 'a'
b++;
console.log(a); // 2
console.log(b); // 3
var c = [1,2,3];
var d = c; // 'd' is a reference to the shared value
d.push( 4 ); // Mutates the referenced value (object)
console.log(c); // [1,2,3,4]
console.log(d); // [1,2,3,4]
/* Compound values are equal by reference */
var e = [1,2,3,4];
console.log(c === d); // true
console.log(c === e); // false

若是想对复杂类型的值进行值拷贝,你须要本身去对全部子元素进行拷贝。

const copy = c.slice() // 'copy' 即便copy和c相同,可是copy指向新的值
console.log(c); // [1,2,3,4]
console.log(copy); // [1,2,3,4]
console.log(c === copy); // false

做用域(Scope)

做用域值程序的执行环境,它包含了在当前位置可访问的变量和函数。

全局做用域是最外层的做用域,在函数外面定义的变量属于全局做用域,能够被任何其余子做用域访问。在浏览器中,window对象就是全局做用域。

局部做用域是在函数内部的做用域。在局部做用域定义的变量只能在该做用域以及其子做用域被访问。

function outer() {
let a = 1;
function inner() {
let b = 2;
function innermost() {
let c = 3;
console.log(a, b, c); // 1 2 3
}
innermost();
console.log(a, b); // 1 2 — 'c' is not defined
}
inner();
console.log(a); // 1 — 'b' and 'c' are not defined
}
outer();

你能够将做用域想象成一系列不断变小的门。若是一个个子不高的人能够穿过最小的门(局部最小做用域),那么必然能够穿过任何比它大的门(外部做用域)。

提高(Hoisting)

在编译过程当中,将varfunction的定义移动到他们做用域最前面的行为叫作提高。

整个函数定义会被提高。因此,你能够在函数还未定义以前调用它,而不用担忧找不到该函数。

console.log(toSquare(3)); // 9

function toSquare(n){
return n*n;
}

变量只会被部分提高。并且只有变量的声明会被提高,赋值不会动。

letconst不会被提高。

{  /* Original code */
console.log(i); // undefined
var i = 10
console.log(i); // 10
}

{ /* Compilation phase */
var i;
console.log(i); // undefined
i = 10
console.log(i); // 10
}
// ES6 let & const
{
console.log(i); // ReferenceError: i is not defined
const i = 10
console.log(i); // 10
}
{
console.log(i); // ReferenceError: i is not defined
let i = 10
console.log(i); // 10
}

函数表达式和函数声明

  • 函数表达式

一个函数表达式是在函数执行到函数表达式定义的位置才开始建立,并被使用。它不会被提高。

var sum = function(a, b) {
return a + b;
}
  • 函数声明

函数声明的函数能够在文件中任意位置调用,由于它会被提高。

function sum(a, b) {
return a + b;
}

变量:var,let和const

在ES6以前,只能使用var来声明变量。在一个函数体中声明的变量和函数,周围的做用域内没法访问。在块做用域iffor中声明的变量,能够在iffor的外部被访问。

注意:若是没有使用var,let或则const关键字声明的变量将会绑定到全局做用域上。

function greeting() {
console.log(s) // undefined
if(true) {
var s = 'Hi';
undeclaredVar = 'I am automatically created in global scope';
}
console.log(s) // 'Hi'
}
console.log(s); // Error — ReferenceError: s is not defined
greeting();
console.log(undeclaredVar) // 'I am automatically created in global scope'

ES6的letconst都是新引入的关键字。它们不会被提高,并且是块做用域。也就是说被大括号包围起来的区域声明的变量外部将不可访问。

let g1 = 'global 1'
let g2 = 'global 2'
{ /* Creating a new block scope */
g1 = 'new global 1'
let g2 = 'local global 2'
console.log(g1) // 'new global 1'
console.log(g2) // 'local global 2'
console.log(g3) // ReferenceError: g3 is not defined
let g3 = 'I am not hoisted';
}
console.log(g1) // 'new global 1'
console.log(g2) // 'global 2'

一个常见的误解是:使用const声明的变量,其值不可更改。准确地说它不能够被从新赋值,可是能够更改。

const tryMe = 'initial assignment';
tryMe = 'this has been reassigned'; // TypeError: Assignment to constant variable.
// You cannot reassign but you can change it…
const array = ['Ted', 'is', 'awesome!'];
array[0] = 'Barney';
array[3] = 'Suit up!';
console.log(array); // [“Barney”, “is”, “awesome!”, “Suit up!”]
const airplane = {};
airplane.wings = 2;
airplane.passengers = 200;
console.log(airplane); // {passengers: 200, wings: 2}
相关文章
相关标签/搜索