## **3.2.1 变量**
变量本质是一个空盒子,里面记录了一个内存地址,使能找到内存中的对象,保存了指向具体的实在的东西的地址,变量存在栈中,对象存在堆中;
变量的意义:方便我们去操作对象。变量的几种引用方式
- 指针(C语言中叫法)
- 引用(Java)
- 变量
> 例如:
> var b = document.body 含义:把body这个对象在内存中的地址放到b变量里面,变量b(b是内存地址的别名)本身也存在内存中,以后的操作是针对body这个地址
变量命名规范
- 由字母(a-zA-Z)数字(0-9)下划线(_)以及美元符号($)
- 不能由数字开头
- 命名尽量用英文并且具有一定的含义
- 如果有多个英文单词,后面单词的首字母大写
- 不能使用关键字
- 首字母不要大写,大写是有特殊含义的
<br/>
## **3.2.2 JS数据类型**
**Javascript的数据类型有六种(ES6新增了第七种Symbol)**
- 数值(number):整数和小数(比如1和3.14)
- 字符串(string):字符组成的文本(比如”Hello World”)
- 布尔值(boolean):true(真)和false(假)两个特定值
- undefined:表示 未定义 或不存在,即此处目前没有任何值
- null:表示空缺,即此处应该有一个值,但目前为空
- 对象(object):各种值组成的集合
通常,我们将数值、字符串、布尔值称为原始类型(primitive type)的值,即它们是最基本的数据类型,不能再细分了。
而将对象称为合成类型(complex type)的值,因为一个对象往往是多个原始类型的值的合成,可以看作是一个存放各种值的容器。至于undefined和null,一般将它们看成两个特殊值
> 内存中一共分为几种对象:1.变量 2.DOM对象 3.常量 4.自定义对象
<br/>
## **3.2.3 如何判断js中的数据类型**
typeof、instanceof、 constructor、 prototype方法比较
~~~js
如何判断js中的类型呢,先举几个例子:
var a = "i am string.";
var b = 222;
var c= [1,2,3];
var d = new Date();
var e = function(){alert(111);};
var f = function(){this.name="22";};
~~~
- 最常见的判断方法:typeof
~~~js
alert(typeof a) ------------> string
alert(typeof b) ------------> number
alert(typeof c) ------------> object
alert(typeof d) ------------> object
alert(typeof e) ------------> function
alert(typeof f) ------------> function
其中typeof返回的类型都是字符串形式,需注意,例如:
alert(typeof a == "string") -------------> true
alert(typeof a == String) ---------------> false
另外typeof可以判断function的类型;在判断除Object类型的对象时比较方便。
~~~
- 判断已知对象类型的方法:instanceof
~~~js
alert(c instanceof Array) ---------------> true
alert(d instanceof Date) ---------------> true
alert(f instanceof Function) ------------> true
alert(f instanceof function) ------------> false
注意:instanceof后面一定要是对象类型,并且大小写不能错,该方法适合一些条件选择或分支。
~~~
- 根据对象的constructor判断:constructor
~~~js
alert(c.constructor === Array) ----------> true
alert(d.constructor === Date) -----------> true
alert(e.constructor === Function) -------> true
注意: constructor 在类继承时会出错
例子:
function A(){};
function B(){};
A.prototype = new B(); //A继承自B
var aObj = new A();
alert(aobj.constructor === B) -----------> true;
alert(aobj.constructor === A) -----------> false;
而instanceof方法不会出现该问题,对象直接继承和间接继承的都会报true:
alert(aobj instanceof B) ----------------> true;
alert(aobj instanceof A) ----------------> true;
言归正传,解决construtor的问题通常是让对象的constructor手动指向自己:
aobj.constructor = A; //将自己的类赋值给对象的constructor属性
alert(aobj.constructor === A) -----------> true;
alert(aobj.constructor === B) -----------> false; //基类不会报true了;
~~~
- 通用但很繁琐的方法: prototype
~~~js
alert(Object.prototype.toString.call(a) === ‘[object String]’) ------> true;
alert(Object.prototype.toString.call(b) === ‘[object Number]’) ------> true;
alert(Object.prototype.toString.call(c) === ‘[object Array]’) -------> true;
alert(Object.prototype.toString.call(d) === ‘[object Date]’) -------> true;
alert(Object.prototype.toString.call(e) === ‘[object Function]’) ---> true;
alert(Object.prototype.toString.call(f) === ‘[object Function]’) ---> true;
大小写不能写错,比较麻烦,但胜在通用。
通常情况下用typeof判断就可以了,遇到预知Object类型的情况可以选用instanceof或constructor方法
~~~
<br/>
## **3.2.4 数据类型转换**
- **转换函数**
- `toString()` 转换为字符串,在JavaScript中所有数据类型都可以转换为`string`类型
- `parseInt()`解析出一个`string`或者`number`类型的整数部分,如果没有可以转换的部分,则返回`NaN`(`not a number`)
~~~js
var n1 = "12";
var n2 = "23hello";
var n3 = "hello";
parseInt(n1); //12
parseInt(n2); //23
parseInt(n3); //NaN
~~~
- parseFloat()解析出一个`string`的浮点数部分,如果没有可以转换的部分,则返回`NaN`(not a number)
~~~js
var n1 = "1.2.3";
var n2 = "1.2hello"
var n3 = "hello"
parseFloat(n1); //1.2
parseFloat(n2); //1.2
parseFloat(n3); //NaN
~~~
- ##### **强制类型转换**
- ##### `Boolean(value)`- 把给定的值转换成`Boolean`型
- ##### `Number(value)`-把给定的值转换成数字(可以是整数或浮点数)
- ##### `String(value)`- 把给定的值转换成字符串
- ##### **隐式转换**
- 数字+字符串:数字转换为字符串 console.log(12+"12"); //1212
- 数字+布尔值:true转换为1,false转换为0 console.log(12+true); //13
- 字符串+布尔值:布尔值转换为true或false
console.log("hello"+true); //hellotrue
- 布尔值+布尔值 console.log(true+true); //2
- **null和undefined**
undefined 表示一种未知状态,声明了但没有初始化的变量,变量的值时一个未知状态。访问不存在的属性或对象window.xxx)方法没有明确返回值时,返回值是一个undefined.当对未声明的变量应用typeof运算符时,显示为undefined。
null表示尚未存在的对象,null是一个有特殊意义的值。可以为变量赋值为null,此时变量的值为“已知状态”(不是undefined),即null。(用来初始化变量,清除变量内容,释放内存)
> undefined==null //结果为true,但含义不同。
> undefined===null //false,两者类型不一致,前者为“undefined”,后者为“object”
<br/>
#### 3.2.5 **运算符**
1.算术运算符(+, -, *, /, %, ++, --)
- 字符串和数字相加的情况:
- 左右都是数字:数字相加
- 左右有一个字符串:字符串拼接
- 左右边有一个null:null看做0
- 左右边有一个undefined:结果是NAN(not a number)
2.赋值运算符(=, -=, +=, *=, /=, %=)
3.比较运算符(\==, ===, !=, >, <, >=, <=)
> 先执行表达式计算再赋值
> \==和!=在比较之前首先让双方的值做隐士类型转换,===不转换
4.逻辑运算符(||, &&, !)
- || 在js中和PHP中是不一样的 js中返回逻辑或的左边或右边的一个结果;PHP返回||或出来以后的结果即:true false
> 特殊性(注意):一定要记住(这个特性和其他编程语言不一样):在js里返回不是布尔值
>
> || 短路运算,第一个条件为真,后面不执行
- &&把表达式最后一个值返回(注意这里)
条件运算符`(表达式1?表达式2:表达式3)`三元运算符
==表达式1?表达式2:表达式3==,表达式1为真,返回表达式2,否则返回表达式3
三元运算符可以多层次嵌套使用
- **在js中,有四种被认为是非**:
- `undefined`
- `null`
- `false`
- `0`
例子:`var age = prompt("温馨提示:","请输入您的年龄")||0`
当点击取消的时候,如果出现`undefined` `null` `fasle` `0` 表示非的逻辑 那么`||`就会过滤,取右边的值`0`
<br/>
## 3.2.6循环
>[info]console.log调试程序,开发中大量使用这个 而不用`alert`
- **js的断点调试方法:**
1. 运行程序,按F12键或者右键鼠标找到“检查”网页
2. 在弹出的窗体选择sources,点开源代码,在想要设置断点的地方的左边代码行单击设置断点
3. 然后要刷新一下页面,页面标题处于“圆圈”状态,表明进入调试模式
4. 拉开最右边的窗体,找到“watch”,可以添加想要检测的变量。
- 条件结构
if
if...else
if...else if...else
当通过判断返回某个值的时候,优先使用三元表达式
当通过判断执行N段逻辑代码的时候,只能用条件结构
- switch
switch case break default 条件 判断 退出 默认
- a.只要匹配上一个case,那么它下面的所有的case都会执行包括default
- b.break的意思跳出当前结构
- for
for循环有三个要素
- a.循环变量
- b.判断(循环体)
- c.改变循环变量
> continue 结束本次循环,继续下一次循环,当前这次循环不做,直接做下面的
> break 跳出本层循环(只跳出一层)
- **while/do...while 没有谁好谁坏 只有适应场景不同**
- 比如:先吃饭 在买单 do..while 用户体验高 有风险 扫雷游戏也是先体验 在问是否退出 提高体验
- 比如:先买单 在吃饭 while 用户体验不高
> 一般情况下,如果条件判断是数字的比较`== <>`,for循环优先.
> 如果是非数值相关的比较循环,while优先
<br/>
## 3.2.7 Object对象
1.JS对象
JS对象有内置对象,宿主对象(JS运行环境提供的对象 BOM DOM)和用户自定义对象,自定义对象通过new关键字来创建,之后内存会为对象开辟一个新的内存空间,位于堆(heap)里面;
for...in 语句循环遍历对象的属性。
new关键字代表的是新开辟一块内存空间,没有被引用的内存空间,会在适当的时候被销毁
以下两句代码含义等同
- var person = new Object();
- var person = {};
访问对象的属性除了用 对象引用`.属性 key`以外,还可以使用对象引用`[属性key]`
~~~js
<body>
<!--prototype 属性允许您为对象构造器添加新属性:-->
<script type="text/javascript">
function Person(){
name="hello";
age=11;
}
Person.prototype.nation="中国";
Person.prototype.eyecolor="black";
//构造器可以通过 构造器名.prototype 来拿到,或者添加原型属性/方法
//由Person构造器实例化的对象通过.__proto__ 去拿到或者添加原型属性。
var p1=new Person();
var p2=new Person();
//alert(Person.prototype == p1.__proto__);
p1.__proto__.eyecolor="黑色";
//alert(p2.__proto__.eyecolor);
/*你也可以直接通过对 象名.属性名 去拿到构造器中已有的原型属性
如果对象本身就有,则直接使用,如果没有,对象会自动向上查找(构造器)
如果最后构造器中也没有,才会返回undefined*/
//alert(p1.nation);
alert(p1.hhh+"没找到此属性");
//var arr=[1,2,3,5];
var arr=new Array();
arr[0]=1;
arr[1]=2;
arr[2]=3;
for (var s in arr) { //此时s就代表arr数组的下标
alert(arr[s]); //通过arr[下标]就可以得到数组的元素值
}
</script>
</body>
~~~
<br/>
2.new 原理详细解析
------
- 无论什么时候,只要创建一个新函数,就会根据一组特定的规则为该函数创建一个`prototype`属性,这个属性指向函数的原型对象。
- 在默认情况下,所有原型对象都会自动获得一个`constructor`(构造函数)属性,这个属性包含一个指向`prototype`属性所在函数的指针(就是指向新创建的函数)。
- 通过这个构造函数(原型对象的构造函数),可以继续为原型对象添加其他属性和方法。
- >当调用构造函数创建一个新实例后,该实例的内部将包含一个指针(内部属性),指向构造函数的原型对象。`ECMA-262`第5版管这个指针叫 `[[Prototype]]`。脚本中没有标准的方式访问`[[Prototype]]`,但`Firefox`、`Safari`和`Chrome`在每个对象上都支持一个属性`__proto__`;而在其他实现中,这个属性对脚本是完全不可见的。不过,要明确的真正重要的一点就是,这个连接存在于实例和构造函数的原型对象之间,而不是存在于实例和构造函数之间
3.new创建对象的步骤
------
- 创建一个新的对象
- 将构造函数的作用域赋给新对象
- 执行构造函数的代码,为这个新对象添加属性
- 返回新对象
**4.使用工厂方法创建对象**
~~~js
使用工厂方法创建对象,通过该方法可以大批量的创建对象
function createPerson(name , age ,gender){
//创建一个新的对象
var obj = new Object();
//向对象中添加属性
obj.name = name;
obj.age = age;
obj.gender = gender;
obj.sayName = function(){
alert(this.name);
};
//将新的对象返回
return obj;
}
var obj2 = createPerson("猪八戒",28,"男");
var obj3 = createPerson("白骨精",16,"女");
var obj4 = createPerson("蜘蛛精",18,"女");
/*
* 使用工厂方法创建的对象,使用的构造函数都是Object
* 所以创建的对象都是Object这个类型,
* 就导致我们无法区分出多种不同类型的对象
*/
~~~
**5.构造器**
~~~js
<script type="text/javascript">
//构造器constructor
function person(name,age,sex){
this.name=name;
this.age=age;
this.sex=sex;
this.work=function () {
alert("人都要工作");
};
}
var tom=new person("tom",23,"男");
var bill=new person("bill",25,"男");
var jessie=new person("jessie",20,"女");
//tom instanceof person 表示判断左边的对象是否属于右边的类
alert(tom instanceof person); //true
</script>
~~~