目录
2.让localStorage/sessionStorage可以存储对象。
Object.prototype.toString.call() 或 Object.prototype.toString.apply()
JSON.stringify()的运用
- JSON.stringify():把任何JavaScript对象变成JSON,就是把这个对象序列化成一个JSON格式的字符串,这样才能够通过网络传递给其他计算机。
- JSON.parse():如果我们收到一个JSON格式的字符串,只需要把它反序列化成一个JavaScript对象,就可以在JavaScript中直接使用这个对象了。
1.判断数组是否包含某对象,或者判断对象是否相等。
const z = [1,2,3];
const s = [1,2,3]
console.log(JSON.stringify(z) === JSON.stringify(s)) // true
const data = [{ name: "l" }, { name: "a" }, { name: "k" }];
const val = { name: "l" };
console.log(
typeof JSON.stringify(data),
JSON.stringify(data).indexOf(JSON.stringify(val)) !== -1
);
// string true
2.让localStorage/sessionStorage可以存储对象。
localStorage/sessionStorage默认只能存储字符串,而实际开发中,我们往往需要存储的数据多为对象类型,那么这里我们就可以在存储时利用json.stringify()将对象转为字符串,而在取缓存时,只需配合json.parse()转回对象即可。
3. 深拷贝
实际开发中,如果怕影响原数据,我们常深拷贝出一份数据做任意操作,其实使用JSON.stringify()与JSON.parse()来实现深拷贝是很不错的选择。(深拷贝的更多内容请见我的另一篇博客)
类数组对象。。
为什么要将类数组对象转化为数组
数组对象Array有很多方法:shift、unshift、splice、slice、concat、reverse、sort,ES6又新增了一些方法:forEach、isArray、indexOf、lastIndexOf、every、some、map、filter、reduce等。由于类数组不具有数组所具有的操作数组的方法,将类数组转换为数组之后就能调用这些强大的方法。
类数组转数组的方法:
判断值类型(判断数组是否为数组)
参考:https://segmentfault.com/a/1190000006150186#item-4
JavaScript有五种方法可以确定一个值到底是什么类型,分别是typeof运算符,constructor法,instanceof运算符,Object.prototype.toString方法以及Array.isArray法。
typeof
const s = 'hello';
console.log(typeof(s))//String
在参数为数组,对象或者null时,typeof返回的结果都是object,使用这种方法并不能识别出数组。
instanceof
instanceof运算符可以用来判断某个构造函数的prototype属性所指向的對象是否存在于另外一个要检测对象的原型链上。
const a = [];
const b = {};
console.log(a instanceof Array);//true
console.log(a instanceof Object);//true,在数组的原型链上也能找到Object构造函数
console.log(b instanceof Array);//false
使用instanceof运算符可以分辨数组和对象,可以判断数组是数组。
constructor
实例化的数组拥有一个constructor属性,这个属性指向生成这个数组的方法。
//定义一个数组
const a = [];
console.log(a.constructor == Array);//true
//作死将constructor属性改成了别的
a.contrtuctor = Object;
console.log(a.constructor == Array);//false (哭脸)
console.log(a.constructor == Object);//true (哭脸)
console.log(a instanceof Array);//true (instanceof火眼金睛)
Object.prototype.toString.call() 或 Object.prototype.toString.apply()
const isArray = (something)=>{
return Object.prototype.toString.call(something) === '[object Array]';
}
cosnt a = [];
const b = {};
isArray(a);//true
isArray(b);//false
toString方法返回的是反应这个对象的字符串,那为什么还要调用call()方法:
toString为Object的原型方法,而Array,function等类型作为Object的实例,都重写了toString方法。不同的对象类型调用toString方法时,根据原型链的知识,调用的是对应的重写之后的toString方法(function类型返回内容为函数体的字符串,Array类型返回元素组成的字符串......),而不会去调用Object上原型toString方法(返回对象的具体类型),所以采用obj.toString()不能得到其对象类型,只能将obj转化为字符串类型;因此,在想要得到对象的具体类型时,应该调用Object上原型toString方法。
var a = [1,2,3];
var b ={v:1};
var c = () => {}
console.log(a.toString()) // ‘1,2,3’
console.log(b.toString) // "[object Object]"
console.log(c.toString) // "()=>{}"
Array.isArray(最靠谱)
const ooo = ["zero", "a", "b", "c"]
Array.isArray(ooo) // true
原型和原型链
对原型链进行操作的示例
参考:https://juejin.im/post/5a94c0de5188257a8929d837
把bark()方法放入Dog构造函数的原型中:
function Dog(name, color) {
this.name = name
this.color = color
}
Dog.prototype.bark = () => {
console.log('wangwang~')
}
dog1.__proto__ === Dog.prototype // true
Dog.prototype.constructor === Dog // true
dog1.constructor === Dog // true ==> 实例的构造函数属性(constructor)指向构造函数。
dog1对象通过Dog 构造函数创建,所以dog1的原型(dog1.__proto__)就是Dog.prototype。
对于原型可以归纳出下面一些点:(区分prototype和__proto__)
- 所有的对象(包括函数对象和原型对象)都有"[[prototype]]"属性(通过__proto__访问),该属性对应对象的原型
- 所有的函数对象都有"prototype"属性,该属性的值会被赋值给该函数创建的对象的"__proto__"属性
- 所有的原型对象都有"constructor"属性,该属性对应创建所有指向该原型的实例的构造函数
- 函数对象和原型对象通过"prototype"和"constructor"属性进行相互关联
- 原型对象就是用来存放实例中共有的那部分属性。在上述例子中就是:Dog.prototype
- 在JavaScript中,所有的对象都是由它的原型对象继承而来,反之,所有的对象都可以作为原型对象存在。
- 访问对象的属性时,JavaScript会首先在对象自身的属性内查找,若没有找到,则会跳转到该对象的原型对象中查找。
- 当一个函数被用作构造函数来创建实例时,该函数的prototype属性值将被作为原型赋值给所有对象实例(也就是设置实例的__proto__属性) 对象.__proto__ === 函数.prototype
var arr = [1, 2, 3];的原型链是:arr ----> Array.prototype ----> Object.prototype ----> null
函数有prototype属性的原因:
通过原型链就可以在JavaScript中实现继承。与大部分面向对象语言不同,JavaScript中并没有引入类(class)的概念,但JavaScript仍然大量地使用了对象,为了保证对象之间的联系,JavaScript引入了原型与原型链的概念。JavaScript中的所有对象都来自
Object
;所有对象从Object.prototype
继承方法和属性,尽管它们可能被覆盖。JS通过
new
来生成对象,但是仅靠构造函数,每次生成的对象都不一样。有时候需要在两个对象之间共享属性,由于JS在设计之初没有类的概念,所以JS使用函数的
prototype
来处理这部分需要被共享的属性,通过函数的prototype
来模拟类:当创建一个函数时,JS会自动为函数添加
prototype
属性,值是一个有constructor
的对象。每一个实例对象都有一个私有属性_proto_,指向它的构造函数的原型对象(prototype)。原型对象也有自己的_proto_,层层向上直到一个对象的原型对象为
null
。这一层层原型就是原型链。
图中由相互关联的原型组成的链状结构就是原型链,也就是蓝色的这条线。
p1和p2的原型是people.prototype,所以p1和p2都可以直接访问到新增加的age。
查看people的prototype属性,此时新增了一个共享属性age。
不加age前仅有一个constructor
hasOwnProperty & Object.keys()
"hasOwnProperty"是"Object.prototype"的一个方法,该方法能判断一个对象是否包含自定义属性而不是原型链上的属性
对象的创建及访问
1. 字面量对象创建
var person = {
name: 'yibo',
age: 22,
hobby: ['play', 'sleep', 'eat']
hi() {
return 'hi I am yibo'
}
}
//person.name
//person.hobby[1]
//person.hi()
子命名空间:
可以用一个对象来做另一个对象成员的值。例如将name成员:
name: {
first: 'wang',
last: 'yibo'
}
访问: person.name.first & person.name.last
2. 构造函数创建
构造函数创建的方式更多用来在Javascript中实现继承,多态,封装等特性。
function Animal(name) {
this.name = name;
}
let cat = new Animal('Tom');
3. new Object()
var Person =new Object();
Person.name = 'Jason';Person.age = 21;
对象可以包含相关的数据和代码,这些代表现实世界模型的一些信息或者功能,或者它特有的一些行为. 对象数据(也经常称为函数) 可以有结构的存储 (官方术语为 封装) 在对象包内 (也可以给一个特殊的名字来表示,有时候也叫做命名空间), 可以使它容易组织和访问; 对象也通常用于存储数据,这样就可以很容易的在网络上传输.
闭包
闭包产生的目的:从外部读取局部变量。闭包的2种情况:函数作为返回值,函数作为参数传递。
闭包就是一种延缓垃圾回收的机制,一般一个函数执行完函数内部的变量会跟着销毁掉,但是有时候你还需要这个变量,为了不让这个变量被销毁掉,只要让这个变量有引用存在就行。
闭包的概念:通俗的讲就是函数a的内部函数b,被函数a外部的一个变量引用的时候,就创建了一个闭包。
function f1(){
var n=999;
nAdd=function(){n+=1} // 闭包
function f2(){
alert(n);
}
return f2;
}
var result=f1();
result(); // 999,闭包
nAdd();
result(); // 1000,闭包
闭包不会被垃圾回收机制回收,会一直保存在内存中。
闭包的最大特性就是,如果里函数引用(or访问,这俩词在这个语境下是等价的)了外函数的某个变量,那这个变量就能享受和全局变量一样的特权,不会被回收。
(function (){
var a = 10;
add.onclick = function (){
a++;
span.innerHTML = a;
}
})()
看一下例子:https://zhuanlan.zhihu.com/p/129022735
杂
const 常量,不可变。
let 变量,块作用域,不能重复声明覆盖。
var 变量,函数作用域,能重复声明覆盖。