前端知识学习 - JS语法的相关学习

本文知识记录一些简单的js语法,和一些tips

2017-02-09 | 阅读

字面量

字面量是一个常量。

Number类型,可以是整数或者小数,或者是科学计数如 123e6

String 类型,可以用单引号或者双引号,单引号表示内部内容不需要转义,而双引号表示内容需要转义。'a\n\b' ,用双引号与单引号不同。

字面量是常量,我们也可以用new来创建一个对象变量,但是new生成的是对象Object

var x = "John";              
var y = new String("John");
(x === y) // 结果为 false,因为 x 是字符串,y 是对象

===表示绝对相等,必须数据类型和值都相等,这里虽然两者值相等,但是类型不同.

变量与其作用域

变量必须以字母、下划线(_)或美元符号($)开始,后续字母是 字母、数字、下划线或美元符。

变量不声明,无法使用,会报错变量未定义 ,但是以下函数却不会报错:

console.log(v);
var v = "world";

输出结果是 undefined ,因为js的变量提升特性hoisting ,js引擎会把所有变量的声明提升到当前作用域的最前面, 即上述代码相当于 :

var v;
console.log(v);
v = "world";

而在以下写法中 :

var v = "hello";
if(true){
  console.log(v);
  var v = "world";
}

输出的是hello,而不是 undefined , 即在js中的var是没有块级作用域的,只有函数才拥有作用域。

var v = "hello";
(function(){
  console.log(v);
  var v = "world";
})();

这种情况输出的是 undefined

javascript是动态语言,变量没有固定类型,其存储空间会随着初始化和赋值而变化。

函数表达式与函数声明的提升不同 :

(function(){
  f1(); 
  f2();
  var f1 = function(){};
  function f2(){}
})();

这里对于f1 、 f2提升的结果为 :

var f1,function f2(){};

这里 f1会报错ReferenceError: f1 is not defined, 由于f1是变量,向上提升时,作为一个 undefined变量,所以无法执行函数,而f2却以函数定义的方式被提升,所以函数可以正常调用。

在一个函数中,作用域中命名优先级顺序如下:

  1. 语言内置 : 所有作用域都有thisarguments关键字
  2. 形式参数 : 函数的参数
  3. 函数声明 : 内部函数的声明
  4. 变量声明

命名优先级较高的名字会覆盖较低优先级的命名,如:

(function(){
    var foo;
    console.log(typeof foo); //function
	 foo = "foo";
    function foo(){}
})();

虽然代码中好像先声明了foo,但是函数声明会被提到最前面,并覆盖foo的声明。

javaScript中,直接赋值给未声明的变量,则该变量被视为全局变量声明,如 :

hello = "world"
console.log(hello)

这样是可以正常执行的, 且即使该赋值位于函数中,也视为全局变量。但是以下形式 :

console.log(hello)
hello = "world"

就会报错,因为这里没有显式的变量声明,也就是没有变量hoisting, 所以会报错 变量not defined

全局变量,在html中挂载在window对象上,而在node.js中挂载于 global对象

类型与类型判断

js中有5种不同的数据类型:string,number,boolean,object,function

三种对象类型 : Object,Date,Array .

2个不包含任何值的数据类型 : null ,undefined

通过 constructor属性可以获取所有变量的构造函数,以上各种类型的构造函数分别为 : String(),Number(),Boolean(),Object(),Function(),Date(),Array函数,而nullundefined没有。

我们可以这样校验一个对象是否是数组 :

function isArray(myArray) {
    return myArray.constructor.toString().indexOf("Array") > -1;
}

一般我们使用 typeof来获取类型:

typeof "John"                // 返回 string 
typeof 3.14                  // 返回 number
typeof false                 // 返回 boolean
typeof [1,2,3,4]             // 返回 object

数组是一个特殊的对象类型,所以类型是 object.

null 在js中表示空值。但使用 typeof(null)结果为object

undefined表示没有设置值,类型为undefined

需要注意的是

null == undefined

所以如果要判断变量是否为 undefined时,需要校验type,而不是直接判断是否等于undefined

正则表达式

在js中,正则表达式如下 :

/正则表达式主体/修饰符(可选)

而修饰符有以下几种 :

  • i : 表示执行对大小写不敏感的匹配
  • g : 执行全局匹配(默认是查找到第一个匹配后结束)
  • m : 执行多行匹配

使用test()方法,用于检测字符串是否匹配指定模式 :

/[a-z]*/.test('hello')

使用exec()方法,检索字符串中所有匹配,该函数返回一个数组,如果未匹配到,返回值为null。

严格模式

严格模式是在ECMAScript5中新增的,使用指令use strict,它不是一条语句,而是一个字面量表达式。如 :

"use strict";
x = 3.14;       // 报错 (x 未定义)

使用严格模式,来消除语法中的不合理不严谨的地方,保证代码的安全运行。

严格模式的一些内容与es6语法相关。

使用误区

在常规的比较中,数据类型是被忽略的, 如 :

var x = 10;
var y = "10";
if (x == y) // 返回的是true。

所以要进行严格的判断时,需要使用 ===,同时校验表达式的类型和值。

js中所有的数据类型都是以64为浮点型数据来存储的,而所有编程语言中,对float的精确度是很难确定的,所以 :

var x = 0.1;
var y = 0.2;
console.log((x + y) == 0.3)

以上代码输出的是 false

this

在js中,this指向调用函数的对象。

如果纯粹的函数调用,属于全局性调用,因此this代表Global

如果被某个对象的方法调用,则执行该对象。

如果作为构造函数调用,则通过这个函数生成了一个新的对象,而this指向这个新对象 :

function test(){ 
    this.x = 1; 
} 
var o = new test(); 

如果被applycall函数调用,则this指向其第一个参数。

call与apply

callapply用于调用函数,两者的区别,在于call将自身函数第二个参数开始的参数传入到函数中,而apply将第二个参数作为数组解析,传入到函数中:

myFunction.call(myObject, 10, 2);
myArray = [10, 2];
myFunction.apply(myObject, myArray)

逻辑运算符

在js逻辑运算中,0、”“、null、false、undefined、NaN都会判为false

使用 &&||能够美化代码。

a = b && c
d = e || f

&&中,如果第一个表达式为假,就不会处理第二个表达式, 所以在a = b && c, 如果b不为空,则返回 C,否则返回b.

||中,如果第一个表达式为真,就不会处理第二个表达式,所以在 d = e || f中,如果 e为空,则返回f。

所以,我们可以用这个特性来美化代码,如 :

if(a >=5){ 
	alert("你好"); 
} 

可以简写成:

a >= 5 && alert("你好"); 

闭包

闭包是能够读取其他函数内部变量的函数:

function f1(){
    var n=999;
    function f2(){
      alert(n); 
    }
    return f2;
  }

这里 f2函数就是一个闭包,它读取了f1函数内部的值 n.

闭包最大的两个用处:

  1. 读取函数内部的变量
  2. 让这些变量的值始终保持在内存中。

如在上述函数中,如果我们:

globalvar = f1();

便将f2的函数保存在一个全局变量中,而f2依赖于函数f1,所以f1函数始终在内存中,不会在调用后,被垃圾回收,而f1中的局部变量也持久保存了。