JavaScript 语言基础
声明变量
三种方式声明变量; var , let, const.
其中var 用来声明 全局变量,let 用来声明变量只能在块级作用域内部有效。
const用于声明变量为一个不可以修改的值。而且必须初始化,也就是要给个值,不然会报错。类似于JAVA中的 final 关键字。
三种方式声明全局变量: 第一种: 使用var 声明。 第二种:不用声明,直接为隐式全局变量。 第三种: 使用全局对象来声明变量也为全局变量。
var num=100; //显示全局变量
text="hello world!"; //隐式全局变量
window.test="hi"; //使用全局对象来声明全局变量
数据类型
JS语言是区分大小写的。JS是一门弱类型语言。就是对类型的约束比较弱。比如其他语言JAVA中数字类型会有float double int 类型。JS语言中只有 Number 类型。所有 的数字统统是Number 类型。
JS每个结束语句都需要写上分号 ";"
JS语言的原始基本类型: null 关键字。表示为空。
undefined 声明未定义的属性。
String 用于存放字符串。如 var t=“text”;
Number 数值类型。用于存放数值如 3,3.555;
Boolean 布尔类型,只有false 和true 。其中 “”(空字符串) , null ,0 ,undefined 四中情况下都是false
**Symbol(ES6 新增) **一种数据类型,它的实例是唯一且不可改变的。
其中基本包装类型含有: String ,Number ,Boolean .
引用数据类型: Object;
**其中原始的基本类型的标识符和变量的值都是存储于栈中,而引用类型的存储通过 栈和堆来进行。其中栈用来存对象的地址,堆中用来存储对象的值。如下图所示。
按值传递 VS. 按引用传递
按值传递(call by value)是最常用的求值策略:函数的形参是被调用时所传实参的副本。修改形参的值并不会影响实参。
按引用传递(call by reference)时,函数的形参接收实参的隐式引用,而不再是副本。这意味着函数形参的值如果被修改,实参也会被修改。同时两者指向相同的值。
按引用传递会使函数调用的追踪更加困难,有时也会引起一些微妙的BUG。
按值传递由于每次都需要克隆副本,对一些复杂类型,性能较低。两种传值方式都有各自的问题。
特点: 原始数据类型的不变性。
如何理解基本数据类型的不变性。到底不变的是什么?
demo:
var str="hello world!";
str[0]="i";
console.log(str); //结果仍然是 “hello world!”;
var str="hello world!";
str="hi";
console.log(str); //结果 "hi"
看看上面两个案列,可以看出对全局变量str 进行第一个元素进行修改为"i"字符的时候,不起作用。 第二个是直接采用重新赋值的方式,让 str变量的值发生改变,使得结果发生变化。这里的不变性是指,一旦基本类型的值进行的设置或者是初始化赋值操作后,这个变量的值是不可以进行修改操作的。即使做了修改,也不会有效果。但可以通过重新赋值来完成。重新赋值的过程就是创建一个新的值。
基本类型不能有属性和方法。
引用数据类型的值是可以改变的, 当形参为引用类型的时候,引用类型的实参执行函数之后,实参的值会发生变化。
demo:
function fun(param) //相对于fun方法来说 param是形参
{
param[0]=99;
return param;
}
var num=[10,100]; //定义一个数组。
var result=fun(num); //相对于fun方法来说 num是实参
console.log(num[0]); //99
console.log(result);//[99,100]
三大对象
看图。其中DOM为文档对象模型。
BOM是浏览器对象模型。这两个比较重要。
创建对象的三种方式
三种方式用于创建对象:
第一种: 字面量的方式创建对象
var obj={
name:"tangsir",sex:"male",age:18,
getName:function () {
return this.name;
}
};
console.log(obj.getName()); // “tangsir”
第二种:通过new Object() 来创建对象; //工厂模式。
function person (name, age, sex) {
var O = new Object();
O.name = name;
O.age = age;
O.sex = sex;
O.sayName =function(){
console.log(this.name);
}
return O;
}
var per = person("per",10,"male"); //不需要用new,因为有return,就是个普通函数
console.log(per instanceof person); //false
第三种:自定义创建对象
function Person (name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
this.sayName =function(){
console.log(this.name);
}
}
var per =new Person("per",10,"male"); //没有了return 但是需要new 来创建对象。
console.log(per instanceof Person); //true
工厂模式和自定义构造函数模式对比: 1、没有显式的创建对象 2、直接将属性和方法赋给了this对象 3、没有return语句
要创建person的实例,必须使用new操作符,以这种方式调用构造函数实际上会经历4个步骤:
1、创建一个新对象
2、将构造函数的作用域赋给新对象
3、执行构造函数中的代码
4、返回新对象
创建自定义的构造函数可以将它的实例标识为一种特定的类型。然而工厂模式是无法来设为一个特定的类型。
构造函数的缺点:
每个方法都有在每个实例上重新创建一遍。person1和person2都有一个sayName()的方法,但两个方法不是同一个Function实例。不同实例上的同名函数是不相等的。
创建两个完成同样任务的Function实例没有必要,而且还有this对象在,不需要在执行代码前就把函数绑定在特定对象上,创建自定义类型的最常用的方式,就是组合使用构造函数模式与原型模式。构造函数模式用于定义实例属性,原型模式用于定义方法和共享的属性,这样每个实例都有自己的一份实例属性的副本,又同时共享着对方法的引用,最大限度的节省了内存。
常用的自定义创建对象的方式:
function CreatStudent(name,age,sex) { //构造模式
this.name=name;
this.age=age;
this.sex=sex;
}
CreatStudent.prototype={ //原型模式 用于公共方法和共享的属性。
constructor:CreatStudent,
GetName:function () {
return this.name;
}
};
var stud1=new CreatStudent("li",22,"男");
var stud2=new CreatStudent("lisumei",21,"男");
var stud3=new CreatStudent("lilaoshi",29,"女");
console.log(stud1.GetName()); //"li"
console.log(stud2.GetName()); //"lisumei"
console.log(stud3.GetName()); //"lilaoshi"
ES6的书写方式:
class Point{
constructor(x, y) { //相当于java中的构造函数,如果不写默认为空
this.x = x; //x,y定义在对象自身上面
this.y = y;
}
add() { //该方法定义在Point.prototype上
console.log(this.x + this.y);
}
}
var p = new Point(2, 3);
p.add(); //输出5 //ES5动态原型模式。
JavaScript注意点
1. 在一对script 的标签中有错误的js代码,会直接略过,并且该script块中错误代码的后面都不会执行,但并不会影响后面script标签的代码实现。一个html文档中可以存在多个script 标签对
2 变量名命名,一般以字母和下划线、$开头,其中 $ 、字母、数字这个可以存在于变量名的中间和末尾。不可以使用 “*” . 书写变量名称,使用驼峰规范,并且需要保证变量名称有意义。比如function getPassword(){}; 定义一个获取密码的函数表达式
3 全局变量不可以进行删除,但是隐式全局变量是可以进行删除的。