认识对象
对象的创建方法
1、
var obj={};
对象字面量/对象直接量(plain Object)
2、
构造函数:
1、系统自带的构造函数 Object()
var obj=new Object
2、自定义构造函数 当函数前面加上new时此函数就成了构造函数
必须符合大驼峰式命名规则
构造函数同样可以传参
function Person(){
this.name='aaa';
this.sex='bbb';
this.age=66;
};
var person1=new Person();
构造函数内部原理
1、在函数体最前面隐式的加上var this={}
2、执行this.xxxx
3、在函数的最后隐式的加上return this;
对象的增删改查
1、增:对象名.属性名=值
var obj={
name:abc,
sex:male,
age:20,
}
obj.height=170;
2、删:delete 对象名.属性名
var obj={
name:abc,
sex:male,
age:20,
}
delete obj.name;
3、改:方法与增一样
4、查:对象名.属性名
var obj={
name:abc,
sex:male,
age:20,
}
console.log(obj.name);
对象枚举(遍历)
1、for in 循环
var obj={
name:'lihui',
age:22,
sex:'male',
}
for(var i in obj){
console.log(obj[i]);
}
2、hasOwnProperty()
此方法用于判断对象内属性是自己的属性还是原型的属性,返回值为布尔值
var obj={
name:'lihui';
age:22,
sex:'male';
__proto__:{
lastName='shengpi',
}
}
for(var i in obj){
if(obj.hasOwnProperty(i)){
console.log(obj[i]);
}
}
3、in
只能用于判断该属性能否被该对象所访问,能则返回true
var obj={
name:'lihui';
age:22,
sex:'male';
__proto__:{
lastName='shengpi',
}
}
console.log('name' in obj);
4、instanceof
//A instanceof B
//官方解释:A对象是否是B构造函数构造出来的
//实际:A对象的原型链上是否有B的原型
堆和栈
基本类型数据
number string boolean undefined null
引用类型数据
object array function
基本类型数据的变量名和值都存放于栈内存中
引用类型数据的变量名存放于栈内存中,真实值存放于堆内存中,栈内存中存放的只是一个指向堆内存内真实
包装类
基本类型数据没有属性也没有方法
例:当我们执行如下代码时 str本身是一个基本类型数据,它既没有属性也没有方法,当我们.length时,系统默认将字符串转换为对象,从而调用length属性;这个过程就是包装类;执行完毕后此过程会立即被删除。
这就造成了我们所看到的字符串类型数据能够直接调用length属性这一假象。
var str='abc'
console.log(str.length);
//new String('abc').length
练习
以下代码执行结果为 undefined
var str='abc';
str+=1;
var test=typeof(str);
if(test.length==6){
test.sign=('typeof的返回结果可能为String');
// new String('String').sign=xxxx -->delete
}
console.log(test.sign);
//new String('String').sign
拷贝
拷贝:复制数据的值
深拷贝:复制者与被复制者互不影响
var a=3;
var b=a;
a=20;
console(b);
此时b值依然为3,不随a的变化而变化
浅拷贝:复制者与被复制者相互影响
var obj={};
var c=obj;
obj.name='abc';
c.age=3;
console.log(obj);
console.log(c);
两者的值都改变了
深拷贝方法封装
function deepCopy(data){
var newCopy=[];
if(data.constractor.name==='Array'){
for(var i=0;i<data.length;i++){
newCopy.push(data[i]);
}
return newCopy;
}else{
var newCopy={};
for(var i in data){
newCopy[i]=data[i];
}
return newCopy;
}
}
原型
原型定义
原型时function对象的一个属性,它定义了构造函数制造出的对象的公共祖先。通过该构造函数产生的对象,可以继承该原型的属性和方法。原型也是对象。
原型中的属性不能通过他的后代修改和添加
//当一个对象通过构造函数Person被定义时 就产生了原型
//原型是构造函数Person下的一个对象 prototype={}
//我们可以人为给这个对象添加一些属性,而之后通过这个构造函数产生的对象都可以访问这个属性
Person.prototype.name='张旭';
function Person(){
}
var person=new Person();
var person1=new Person();
原型的用处
1、可以提取公有属性
原型中自带的属性
1、constructor属性
该属性会返回生成这个函数的构造器
我们可以手动修改这个属性的属性值 从而使其返回其他的构造函数
2、__ proto __ 属性:
这个属性指向的是原型对象 我们可以通过这个属性修改原型指向
原型链
如下代码所示,将对象son的原型设置为对象father,又将对象father的原型设置为对象test,这就构成了原型链;由此我们可以通过对象son访问以上两个对象的所有属性。
Test.prototype.sex='male';
function Test(){
}
var test=new Test();
Father.prototype=test;
function Father(){
this.name='aa';
}
var father=new Father;
Son.prototype=father;
function Son(){
this.hobbit='smoke';
}
var son=new Son();
绝大多数对象都最终继承自Object.prototype
然而当使用Object.create()创建对象时就出现了例外
//var obj=Object.create(null);
obj1={
name:'zhangxu',
age:22,
sex:'male',
}
var obj=Object.create(obj1);
注意:当使用该方法创建对象时()中只能写null或者原型,使用null所创建出来的对象是没有任何原型的,也就不继承于Object.prototype;即使我们人为的给其添加__ proto __属性,该属性也是不生效的。
undefined和null不能通过包装类转换成对象,因此也就不具有原型,更不可能继承于Object.prototype
原型中的方法 :
以toString()方法为例:Object.prototype下有toString()方法, Number.prototype,Stirng.prototype,Boolean.prototype,Array.prototype下都有toString()方法,不同原型中的toString()方法是不一样的,我们可以人为的对它进行删除或者重写,从而达到我们想要的效果。
var num=222;
//重写
Number.prototype.toString=function(){
return '张旭傻逼';
}
console.log(num.toString());//输出结果为 张旭傻逼
//删除
delete Number.prototype.toString;
判断对象和数组的方法
1、constructor
var obj={};
var arr=[];
console.log(obj.constructor);
console.log(arr.constructor);
2、instanceof
var obj={};
var arr=[];
console.log(arr instanceof Array);
console.log(obj instanceof Array);
3、toString
var obj={};
var arr=[];
console.log(Object.prototype.toString.call(obj));
console.log(Object.prototype.toString.call(arr));
继承发展史
1、传统形式---->原型链
过多的继承了没用的属性
2、借用构造函数(call/apply) 严格意义上讲不是继承
不能继承借用构造函数的原型
每次构造函数都要多走一个函数
3、共享原型
Father.prototype.name='wo';
function Father(){
}
function Son(){
}
Son.prototype=Father.prototype
var son=new Son();
共享原型继承方法封装
Father.prototype.lastName='aaa';
function Father(){
}
function Son(){
}
function inherit(Target,Orgine){
Target.prototype=Orgine.prototype;
}
inherit(Son,Father);
此时 我们就实现了将Son和Father的原型都指向了Father的原型,但是这个方法有一个弊端:
当我们改变Son的原型的时候 Father的原型也跟着改变了 ,这就引出了我们下面的:
4、圣杯模式
Father.prototype.lastName='aaa';
function Father(){
}
function Son(){
}
function F(){
}
function inherit(Target,Origin){
F.prototype=Origin.prototype;
Target.prototype=new F();
Target.prototype.constructor=Target;
Target.prototype.uber=Origin;
}
inherit(Son,Father);
此方法中可以看出 我们使用了一个第三方函数F
先将Father的原型赋给F,然后让Son继承于F,此时我们修改Son的原型时,F的原型会受到影响 但是不影响Father的原型