一、 引言
- Javascript的简单类型包括
1.数字 number
两个浮点数相加,精度不够
JS不分整型与浮点型
2.字符串 string
3.布尔值 boolean
4.null
5.undefined
6.symbol(新增)
研究一下 前五个貌似是对象,因为他们拥有方法?
但其实基本类型不是对象,使用基本类型变量可以调用方法是因为产生了包装对象(临时的)。
ES6中基本数据类型有六种:undefined、null、string、number、boolean、symbol(新增)。另外一个复杂数据类型就是object了。基本数据类型没有方法和属性,有时候我们看见可以直接调用string.length的长度,其实是包装对象的作用。
其他都是对象 如:Function Array等。
二、Javascript中的对象
1. 对象字面量
对象字面量的定义方式,可以轻松搞定函数大量参数需要一一对应输出的情况。他的对策就是给函数传入一个对象,而这个对象是用字面量的方式定义的,属性和值对应的方式可以一目了然,属性的值可以从包括另一个对象字面量在内的任意表达式中获得。且对象是可嵌套的。
let tt = {
name :'Tendo',
age: 19,
hometown : {
c : 'china',
p : 'jiangxi'
}
}
2. 检索
若检索不存在的成员属性的值,则返回undefined,检索 undefined 值会导致 TypeError 异常,可通过 && 运算符避免
要检索对象中包含的值的方式有两种:传统的'.'
例如:tt.name
以及数组方式,只不过用数组方式输出时,方括号里面要用引号括起来
例如: tt['name']
console.log(tt.age); //19
console.log(tt['name']); //Tendo
3. 更新
对象中的值可以通过赋值语句来更新。如果属性名已经存在于对象中,那么这个属性的值被替换。
tt['age'] = 19.5;
tt.hometown.p = 'fuzhou';
console.log(tt.age); //19.5
console.log(tt.hometown.p); //fuzhou
4. 引用
js中对象引用出现的问题
let a = [1, 2, 3];
let b = a;
let c = [1, 2, 3];
let d = 1;
let e = 1;
console.log(d == e); //true
console.log(a == b); //true;
console.log(a == c); //false;
//b是a赋值过去的,现在更改b的内容,再看看a
b.push(4);
console.log(a); // [1, 2, 3, 4] a也变了啊,这里对我们对a没有操作呀!!!
上面的代码,a不是基本类型,是个数组对象,赋给b的时候,改动b也改动了a!!!这就是在js中,当a不是基本类型数据时,内存中a存的是一个内存地址,a赋值给b时候,ab共同指向一个内存地址,改动了a,也就改动了b,改动了b,也就改动了a
所以对象通过引用来传递,他们永远不会被拷贝,因为复制的只是对内存中对象的地址。
再看一段代码
b = [1, 2, 3, 4, 5]; //这里不用b.push(5);看看什么变化
console.log(a); // [1, 2, 3, 4 ] a不变
console.log(b); // [1, 2, 3, 4, 5 ]
是不是很困惑,不是说了改动b,a也跟着动吗?其实不是b对象改动,而是又重新赋值一个对象给了b,b是数组对象的另一个对象实例(只要程序中出现赋值,那就是重新生成),他俩也就没关系了,如果用b的某个方法,改动的b的值,那a和b仍然指向同一个地址!
5. 原型
- 什么是原型
原型是Javascript中的继承的基础,JavaScript的继承就是基于原型的继承。
- 函数的原型对象
在JavaScript中,我们创建一个函数A(就是声明一个函数), 那么浏览器就会在内存中创建一个对象B,而且每个函数都默认会有一个属性 prototype 指向了这个对象( 即:prototype的属性的值是这个对象 )。这个对象B就是函数A的原型对象,简称函数的原型。这个原型对象B 默认会有一个属性 constructor 指向了这个函数A ( 意思就是说:constructor属性的值是函数A )。
- 看以下代码
function gg () { }
//给gg函数的原型对象中添加一个属性 name并且值是 "张三",age值为20
gg.prototype.name = '张三';
gg.prototype.age = 20;
let g1 = new gg();
console.log(g1.age); //20
访问g1对象的属性age,虽然在g1对象中我们并没有明确的添加属性age,但是 g1的 [[prototype]] 属性指向的原型中有age属性,所以这个地方可以访问到属性age的值。
6. 反射
- 一般情况,反射的目标是数据,可使用tyepof 操作符筛选想要的属性类型
7. 枚举
- 但是特殊情况:
例如一个对象能够在运行时知道自己有哪些方法和属性。
现在就要用到反射机制(枚举):指的是程序在运行时能够获取自身的信息。
在JavaScript中利用for(…in…)语句实现反射,代码如下:
for (let p in tt) {
if (typeof (tt[p]) == "function") {
tt[p]();
} else {
console.log(tt[p]);// Tendo 19.5 {c: "china", p: "fuzhou"}
}
}
8. 删除
delete运算符可以移除对象中的属性,它将会移除对象中确定包含的属性。但它不会触及原型链中的任何对象,删除对象的属性可能会原型链中的属性浮现出来。
以下是应该注意的情况
- 如果你试图删除的属性不存在,那么delete将不会起任何作用,但仍会返回true
- 如果对象的原型链上有一个与待删除属性同名的属性,那么删除属性之后,对象会使用原链上的那个属性(也就是说,delete操作只会在自身的属性上起作用)
- 任何使用 var 声明的属性不能从全局作用域或函数的作用域中删除。这样的话,delete操作不能删除任何在全局作用域中的函数(无论这个函数是来自于函数声明或函数表达式)除了在全局作用域中的函数不能被删除,在对象(object)中的函数是能够用delete操作删除的。
- 任何用let或const声明的属性不能够从它被声明的作用域中删除。不可设置的属性不能被移除。这意味着像Math, Array, Object内置对象的属性以及使用Object.defineProperty()方法设置为不可设置的属性不能被删除。
- delete可以删除数组但是数组的长度不会改变,想要删除数组可以使用splice
9. 减少全局变量污染
- 为何要尽量避免全局变量污染呢?
一. 全局变量减少了js的灵活性,增加了耦合性。
二. 若一个项目是由多人合作完成,全局变量容易造成变量名冲突。
三. 根据垃圾回收机制,一个变量的生命周期的结束要等到不再使用该变量,而全局变量
则要到关闭浏览器页面才会被回收,所以及其占用内存。
- 方法
一. 定义全局变量命名空间
只创建一个全局变量,并定义该变量为当前应用容器,把其他全局变量追加在该命
名空间下
二 . 利用匿名函数将脚本包裹起来