Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

js 基础语法 #11

Open
adodo0829 opened this issue Feb 26, 2020 · 0 comments
Open

js 基础语法 #11

adodo0829 opened this issue Feb 26, 2020 · 0 comments

Comments

@adodo0829
Copy link
Owner

基础语法

介绍

动态: 在运行期间才去做数据类型检查
弱类型: 赋值时可以修改数据类型
解释型语言: 不需要进行编译可以直接运行
运行在浏览器端, 当然现在也可以运行在服务端的 node 环境下

  • 组成
javascript由三部分组成:ECMAScript、DOM和BOM

[1]ECMAScript由ECMA-262定义,提供核心语言功能(ECMA是欧洲计算机制造商协会)
[2]DOM(Document Object Model)文档对象模型,提供访问和操作网页内容的方法和接口
[3]BOM(Browser Object Model)浏览器对象模型,提供与浏览器交互的方法和接口
  • 作用
js 用来增强页面动态效果,实现页面与用户之间的实时、动态交互

基础

标识符&变量

标识符: 就是一个名字,用来对变量、函数、属性、参数进行命名,或者用做某些循环语句中的跳转位置的标记

// 变量
var Identifier = 123;
// 属性
(new Object).Identifier = 'test';
// 函数及参数
function IdentifierName(Identifier1){};
...

变量(variable)是一个用于保存值的占位符,可以通过变量名称来获得对值的引用
推荐命名方式: 变量的命名要使用名词,而函数应该是动词+名称的形式

  • 变量声明
# 声明
使用一个变量之前应当先声明(declare),变量是使用关键字var(variable的缩写)来声明的
var v;

# 赋值
把值存入变量的操作称为赋值(assignment)。一个变量被赋值以后,我们就说该变量包含这个值
给变量第一次赋值的过程,叫初始化
var v = 'hello world'
未在var声明语句中给变量指定初始值时, 其值为 undefined

# 重复声明
使用var语句重复声明变量是合法且无害的,如果重复声明且带有赋值操作,相当于重新赋值
严格模式下使用未声明确赋值了的变量会报错
  • 变量作用域
变量的作用域(scope)是程序源代码中定义这个变量的区域; 分为全局和局部(函数)

全局作用域: 是最外围的一个执行环境,在web浏览器中,全局执行环境被认为是window对象。所有全局变量和函数都是作为window对象的属性和方法创建的。全局变量拥有全局作用域,在javascript代码中的任何地方都是有定义的。全局作用域直到应用程序退出例如关闭网页或浏览器时才会被销毁

局部作用域: 在函数内声明的变量只在函数体内有定义。它们是局部变量,作用域是局部性的。函数参数也是局部变量,它们只在函数体内有定义。函数作用域中的所有代码执行完毕后,该作用域被销毁,保存在其中的所有变量和函数定义也随之销毁
  • 变量声明提升
全局作用域下的变量也会提升到顶部
JS函数里声明的所有变量(不涉及赋值)都被提前到函数体的顶部
var scope = 'global';
function f(){
    console.log(scope);// undefined
    var scope = 'local';
    console.log(scope);// 'local'
}
f()

表达式

js 表达式有操作符合语句组成; 分为原始表达式和复杂表达式

原始表达式

原始表达式是表达式的最小单位, 分为字面量、关键字和变量;详细来说包括this关键字、标识符引用、字面量引用、数组初始化、对象初始化和分组表达式

  • this关键字和标识符
this;// 返回当前对象
i;   // 返回变量i的值
  • 字面量
字面量(literal),又翻译成直接量,就是程序中直接使用的数据值, 包括:
null;
undefined;
true;
false;
1;
'abc';
/pattern/;
  • 数组和对象初始化
数组初始化和对象初始化实际上是一个以字面量的方式描述的初始化的过程。这两个初始化表达式有时称做"对象字面量"和"数组字面量"
[];
[1,2,3];
{};
{a:1};
  • 分组表达式
分组表达式实际上就是括号,用于重写运算符的优先级

复杂表达式

复杂表达式由原始表达式和操作符(operator)组合而成,包括属性访问表达式、对象创建表达式和函数表达式

  • 属性访问表达式
属性访问表达式运算可以得到一个对象属性或一个数组元素的值; 点和方括号.
var o = {x:1,y:{z:3}}; // 对象字面量
var a = [o,4,[5,6]];   // 包含对象的数组字面量
o.x;                   // 表达式o的x属性
o.y.z;                 // 表达式o.y的z属性
o['x'];                // 对象o的x属性
a[1];                  // 表达式a中索引为1的元素
注意: 
在'.'和'['之前的表达式总是会首先计算;
1. 如果计算结果是null或undefined,表达式会抛出一个类型错误异常,因为这两个值都不能包含任意属性
2.如果计算结果不是对象,javascript会将其转换为对象. 
3.如果对象表达式后跟随句点和标识符,则会查找由这个标识符指定的属性值,并将其作为整个表达式的值返回
4.如果对象表达式后跟随一对方括号,则会计算方括号内的表达式的值并将其转换为字符串

不论哪种情况,如果命名的属性不存在,那么整个属性访问表达式的值就是undefined
  • 对象创建表达式
    对象创建表达式创建一个对象并调用一个函数初始化新对象的属性
    new Object()
    Object 构造函数为给定值创建一个对象包装器。如果给定值是 null 或 undefined,将会创建并返回一个空对象,否则,将返回一个与给定值对应类型的对象。

function Person(name) {
this.name = name
}
new Person('huhua') // 返回一个Person实例对象

  • 函数表达式
函数表达式分为函数定义表达式和函数调用表达式

函数定义: 
function square(x){
    return x*x;
}
var square = function(x){return x*x;}
函数调用:
square(1)

严格模式

为了消除js语法的一些不合理、不严谨、不安全问题,减少怪异行为并保证代码运行安全
提高编译器效率,增加运行速度, 因此引入了严格模式

  • 使用
[1]整个脚本启用严格模式,在顶部执行:"use strict";
[2]在指定函数中执行严格模式,在函数体第一行:"use strict"
[3]不支持strict模式的浏览器把"use strict"当做一个字符串语句执行,支持strict模式的浏览器将开启strict模式
[4]支持严格模式的浏览器包括IE10+、Firefox4+、safari12+、opera12+、chrome
  • 相关规则
# 变量
1.不允许意外创建全局变量
"use strict";
a = 'hello world!';

2.不能对变量调用delete操作符
var color = 'red';
delete color;

3.不能为只读属性赋值
Object.defineProperty(person,'name',{
    writable: false
});
person 的 name 属性无法赋值

4.不能为不可配置的属性使用delete操作
5.函数参数必须唯一
6.修改函数的形参不会反映到arguments中
function showValue(value){
    value = "Foo";
    alert(arguments[0]);
    // 非严格模式:"Foo"
    // 严格模式:"Hi"
}
showValue("Hi");

7.不允许this值为null或undefined
全局下 this 为 undefined

8.不允许使用with语句

垃圾回收

垃圾回收机制的原理:找出那些不再继续使用的变量,然后释放其占用的内存,垃圾收集器会按照固定的时间间隔,或代码执行中预定的收集时间,周期性地执行这一操作

局部变量只在函数执行的过程中存在。而在这个过程中,会为局部变量在栈(或堆)内存上分配相应的空间,以便存储它们的值。然后在函数中使用这些变量,直到函数执行结束。此时,局部变量就没有存在的必要了。因此可以释放它们的内存以供将来使用。在这种情况下,很容易判断变量是否还有存在的必要;但并非所有情况下都这么容易就能得出结论

垃圾收集器必须跟踪哪个变量有用哪个变量无用,对于不再有用的变量打上标记,以备将来收回其所占用的内存。用于标识无用变量的策略通常有标记清除和引用计数两种

  • 程序内存管理
使用具备垃圾收集机制的javascript的主要问题在于:分配给web浏览器的可用内存数量通常要比分配给桌面应用程序的少,目的是防止运行javascript的网页耗尽全部系统内存而导致系统崩溃。内存限制问题不仅会影响给变量分配内存,同时还会影响调用栈以及在一个线程中能够同时执行的语句数量.

因此,确保占用最少的内存可以让页面获得更好的性能。而优化内存占用的最佳方式是:为执行中的代码只保存必要的数据。一旦数据不再有用,最好通过将其值设置为null来释放其引用,这种做法叫解除引用(dereferencing)。这一做法适用于大多数全局变量和全局对象的属性,局部变量会在它们离开执行环境时自动被解除引用

运算符

分类

  • 按操作数
# 一元运算符, 主要包括以下9个:
++ -- - + ~ ! delete typeof void

# 二元运算符, 它们的操作数都是两个,
如 1 + 1, 1 && 2

# 三元运算符, 条件判断运算符 ?:
2 > 1 ? 2 : 1;
  • 按优先级, 从高到低依次是
1  ++ -- - + ~ ! delete typeof void
2  * / %
3  + -
4  << >> >>>
5  < <= > >= instanceof in
6  == != === !==
7  &
8  ^
9  |
10 &&
11 ||
12 ?:
13 = *= /= %= += -= &= ^= |= <<= >>= >>>=
14 ,

一元运算符 > 算术运算符 > 比较运算符 > 逻辑运算符 > 三元运算符 > 赋值运算符 > 逗号运算符

算术运算符

算术运算符包括一元算术运算符和二元算术运算符两种

一元算术运算符

一元算术运算符用于一个单独的操作数,并产生一个新值。在javascript中,一元运算符具有很高的优先级,而且都是右结合(right-associative)

一元算术运算符包括一元加法(+)、一元减法(-)、递增(++)和递减(--)

  • 一元加(+)
在对非数值应用一元加运算符时,会调用Number()转型函数对这个值进行转换
var s1 = '01';
var s2 = '1.1';
var s3 = 'z';
var b = false;
var f = 1.1;
var o = {
    valueOf:function(){
      return -1;
    }
};
s1 = +s1;  // 1
s2 = +s2;  // 1.1
s3 = +s3;  // NaN
b = +b;    // 0
f = +f;    // 1.1
o = +o;    // -1

+new Date() // 1582719041912
在new Date()前面使用一元加符号,可以把日期字符串,转换为日期毫秒数
  • 一元减(-) 一元减运算符主要用于表示负数
一元加和一元减运算符主要用于基本的算术运算,也可以用于转换数据类型
var o = {
    valueOf:function(){
      return -1;
    }
};
o = -o;    // 1
  • 递增(++)
递增++运算符对其操作数进行增量(加1)操作,操作数是一个左值(lvalue)(变量、数组元素或对象属性)。运算符通过Number()转型函数将操作数转换为数字,然后给数字加1,并将加1后的数值重新赋值给变量、数字元素或者对象属性

var i = 1, j = ++i; // i=2 j=2
var i = 1, j = i++; // i=2 j=1
  • 递减(--)
递减--运算符的操作数也是一个左值,它通过Number()转型函数把操作数转换为数字,然后减1,并将计算后的值重新赋值给操作数

运算符的返回值依赖于它相对操作数的位置
var i = 1, j = --i; // i=0 j=0
var i = 1, j = i--; // i=0 j=1

二元算术运算符

  • 加法(+)
    加法运算有大量的特殊行为,不仅可以进行数值加法运算,也可以进行字符串连接
    加法运算遵循如下规则:
1.如果其中一个操作数是对象,则对象会转换为原始值:日期对象通过toString()方法执行转换,其他对象通过valueOf()方法执行转换。由于多数对象valueOf()方法无法返回一个原始值,于是会通过toString()方法来执行转换

注意: 除了单数值数组会转换为数字外,其他原生对象都会通过toString()方法转换为字符串形式

2.在进行了对象到原始值的转换后,如果其中一个操作数是字符串的话,另一个操作数也会转换成字符串,进行字符串连接

3.否则,两个操作数都将转换成数字或NaN,进行加法操作

// 单数值数组和valueOf()返回值为数值的自定义对象会转换为数值
console.log(1 + []); // 1
var o = {
    valueOf: function(){
        return -1;
    }
}
console.log(1 + o); // 0

// 其他原生对象则转换为字符串
console.log(1 + {});//'1[object Object]'
console.log(1 + [1,2]);//'11,2'
console.log(1 + new Date());//'1Thu Jun 16 2016 10:27:13 GMT+0800 (中国标准时间)'
console.log(1 + /0/);//'1/0/'

// 如果进行算术加法运算,undefined转换为NaN,null转换为0,false转换为0,true转换为1

// 如果进行字符串连接,undefined转换为'undefined',null转换为'null',false转换为'false',true转换为'true'
  • 减法(-)
    相对于加法,减法就简单的多,只涉及到数字的减法运算。使用Number()转型函数将非数值类型转换为数值或NaN
console.log(1 - {});//NaN
console.log(1 - [1,2]);//NaN
console.log(1 - /0/);//NaN
console.log(1 - []);//1
  • 乘法()
    乘法操作符由一个星号(
    )表示,用于计算两个数值的乘积,会通过Number()转型函数将非数值类型转换为数值或NaN

  • 除法(/)
    除法操作符由一个斜线(/)表示,执行第一个操作数除以第二个操作数的运算,也会通过Number()转型函数将非数值类型转换为数值或NaN

  • 求模(%)
    求模(余数)操作符是由一个百分号(%)表示,是第一个操作数除以第二个操作数的余数

关系运算符

===、!==、==、!=、<、<=、>、>= 8个关系运算符

不恒等运算符下的 两个操作数比较存在隐式转换

以 == 为例, 当两个操作数类型不同时:

1.如果一个值是对象类型,另一值是原始类型,则对象类型会先使用valueOf()转换成原始值,如果结果还不是原始值,则再使用toString()方法转换,再进行比较

2.在对象转换为原始值之后,如果两个操作数都是字符串,则进行字符串的比较

3.在对象转换为原始值之后,如果至少有一个操作数不是字符串,则两个操作数都将通过Number()转型函数转换成数字进行数值比较

逻辑运算符

  • 逻辑非
逻辑非对操作数转为布尔类型的转换类型与Boolean()转型函数相同,只不过最后再将其结果取反。

// 7 个假值
console.log(!!undefined);  //false
console.log(!!null);       //false
console.log(!!0);          //false
console.log(!!-0);         //false
console.log(!!NaN);        //false
console.log(!!'');         //false
console.log(!!false);      //false
  • 逻辑与
逻辑与运算符由两个和号(&&)表示,有两个操作数,只有在两个操作数都为true时,结果才返回true,否则返回false


// 利用短路运算特性
1.可以使用逻辑与运算符来取代if结构
(a == b) && doSomething();

2.逻辑与运算符常常用于回调函数使用中
function fn(a){
    a && a();
}
  • 逻辑或
逻辑或运算符由两个竖线(||)表示,有两个操作数,只有在两个操作数都是false时,结果才返回false,否则返回true

1.逻辑或运算符常用于为变量设置默认值
function fn(p){
    p = p || {};
}

位运算符

  • 按位非(~)
按位非操作符由一个波浪线(~)表示,执行按位非的结果就是返回数值的反码。其本质是操作数的负值减1
var num1 = 25;
var num2 = ~num1;
console.log(num2);//-26

对一个整数两次按位非,可以得到它本身;对一个小数两次按位非,可以得到取整效果
console.log(~~3);//3
console.log(~~3.1);//3
  • 按位与(&) 按位或(|)
按位与操作符由一个和号符号(&)表示,它有两个操作符数。从本质上讲,按位与操作就是将两个数值的每一位对齐,然后根据下表中的规则,对相同位置上的两个数执行AND操作

| 第一个数值的位 | 第二个数值的位 | 结果 |
| :------------- | :------------- | :--- |
| 1              | 1              | 1    |
| 1              | 0              | 0    |
| 0              | 1              | 0    |
| 0              | 0              | 0    |

按位或(|)规则与上相反

25 = 0000 0000 0000 0000 0000 0000 0001 1001
 3 = 0000 0000 0000 0000 0000 0000 0000 0011
---------------------------------------------
 & = 0000 0000 0000 0000 0000 0000 0000 0001 // 1
 | = 0000 0000 0000 0000 0000 0000 0001 1011 // 27

一个整数与0按位或运算可以得到它本身,一个小数与0按位或运算可以得到取整效果
console.log(3.1 | 0);//3
console.log(3.9 | 0);//3

其他运算符

逗号运算符

逗号运算符是二元运算符,它的操作数可以是任意类型。它首先计算左操作数,然后计算右操作数,最后返回右操作数的值,用逗号运算符可以在一条语句中执行多个运算

逗号运算符最常用的场景是在for循环中,这个for循环通常具有多个循环变量
//for循环中的第一个逗号是var语句的一部分
//第二个逗号是逗号运算符
//它将两个表达式(i++和j--)放在一条语句中
for(var i=0, j=10;i<j;i++,j--){console.log(i+j);}

逗号运算符还可以用于赋值,在用于赋值时,逗号运算符总是返回表达式中的最后一项
var num = (1,2,3,4,5);
console.log(num);//5

void运算符

void是一元运算符,它出现在操作数之前,操作数可以是任意类型,操作数会照常计算,但忽略计算结果并返回undefined。由于void会忽略操作数的值,因此在操作数具有副作用的时候使用void来让程序更具语义

1.替代undefined
由于undefined并不是一个关键字,其在IE8-浏览器中会被重写,在高版本函数作用域中也会被重写;所以可以用void 0 来替换undefined
function t(){
var undefined = 10;
console.log(undefined);
}
t() // 10

语句

javascript程序无非就是一系列可执行语句的集合,javascript解释器依照语句的编写顺序依次执行。

  • 表达式语句
赋值、delete、函数调用这三类即是表达式,又是语句,所以叫做表达式语句
  • 声明语句
声明语句包括变量声明和函数声明,分别使用var和function关键字

函数声明语句和函数定义表达式包含相同的函数名,但二者有所不同
// 变量声明语句
var f = function(x){return x+1;}
// 声明式语句
function f(x){return x+1;}

函数定义表达式只有变量声明提前了,变量的初始化代码仍然在原来的位置;
而函数声明语句的函数名称和函数体均提前,脚本中的所有函数和函数中所有嵌套的函数都会在当前上下文中其他代码之前声明,也就是说,可以在声明一个javascript函数之前调用它

// 这种只会提升变量, 函数体不会
console.log(f1(0));//Uncaught TypeError: f1 is not a function
var f1 = function(x){return x+1;}

console.log(f2(0));//1
function f2(x){return x+1;}
  • 条件语句
if 语句;

switch (express)
  // case的值不一定是常量,可以是变量或表达式
  case value || express1:
    doSomething
    break;
  default:
  • 循环语句
while(){}, do{}while(), for(){}
  • 跳转语句
break; 跳出循环

continue
for(i = 0; i < 5; i++){
    if(i % 2 === 0)continue;
    console.log(i); // 1, 3
}

return 函数中的返回值, 函数终止执行
  • eval语句
eval()是一个全局函数,javascript通过eval()来解释运行由javascript源代码组成的字符串
eval()只有一个参数
如果传入的参数不是字符串,它直接返回这个参数。
如果参数是字符串,它会把字符串当成javascript代码进行编译。
如果编译失败则抛出一个语法错误(syntaxError)异常。
如果编译成功,则开始执行这段代码,并返回字符串中的最后一个表达式或语句的值,如果最后一个表达式或语句没有值,则最终返回undefined

eval()使用了调用它的变量作用域环境
  • with
定义with语句的目的主要是为了简化多次编写同一对象的工作
with语句将object添加到作用域链的头部,然后执行statement,最后把作用域链恢复到原始状态

with(object){
  statement;
}
在对象嵌套层次很深的时候通常会使用with语句来简化代码编写。而本质上是通过将一个对象的引用当作作用域来处理,将对象的属性当作作用域中的标识符来处理,从而创建了一个新的词法作用域
with语句提供了一种读取对象的属性的快捷方式,但它并不能创建对象的属性

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant