js对象学习笔记

对象字面量

 var person = {
    name:"aa",
    age:20,
    job:"student",
    sayName:function(){
        alert(this.name);
    }
}

工厂模式

function createPerson(name.age,job){
    var o = new Object();
    o.name = name;
    o.age = age;
    o.job = job;
    o.sayName = function(){
        alert(this.name);
    };
    return o;
}
var person1 = createPerson("aa",20,"student");
var person2 = createPerson("bb",22,"teacher");

构造函数模式

function Person(name,age,job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = function(){
        alert(this.name);
    };
}
var person1 = new Person("aa",20,"student");
var person2 = new Person("bb",22,"teacher");

构造函数始终应以大写字母开头,非构造函数则以小写字母开头。
要创建Person的新实例,必须用new操作符。

person1和person2都有一个constructor(构造函数)属性,该属性指向Person。

person1.constructor == Person; //true

优于工厂模式:可以将他的实例表示为一种特定的类型而非只是Object。

 person1 instanceof Person //true

构造函数与其它函数的区别在于调用方式不同。任何函数通过new操作符调用都会作为构造函数,反之不通过new操作符调用那么就是普通函数。

//当做构造函数
var person1 = new Person("aa",20,"student");
person1.sayName(); //aa

//作为普通函数
Person("ee",20,"student");//添加到window
window.sayName();//ee

//在另一个对象的作用域中调用
var o = new Object();
Person.call(o,"cc",34,"mother");
o.sayName(); //cc

作为普通函数调用时,在全局作用域中调用的函数this指向window对象。

构造函数缺点:每个方法都会在每个实例上重新创造一遍。不同实例上的同名函数是不相等的。

原型模式

原型对象:包含所有实例共享的属性和方法。

function Person(){
}
Person.prototype.name = "aa";
Person.prototype.age = 20;
Person.prototype.job = "student";
Person.prototype.sayName = function(){
    alert(this.name);
};

var person1 = new Person();
person1.sayName(); //"aa"

var person2 = new Person();
person2.sayName(); //"aa"

person1.sayName == person2.sayName; //true

上例中所有实例访问同一组属性与方法。

原型对象.jpg

检测是否是实例的原型对象:

Person.prototype.isPrototypeOf(person1); //true

Object.getPrototypeOf(person1) == Person.prototype; //true

Object.getPrototypeOf方便地取得一个对象的原型。

搜索属性:
当代码读取某个对象的某个属性时,都会执行一次搜索。


原型属性搜索.jpg

对象实例可以访问原型中的值,但不能重写。若实例中添加了一个与原型中某一个属性同名的属性,则该属性会屏蔽原型中的同名属性:

function Person(){
}
Person.prototype.name = "aa";
Person.prototype.age = 20;
Person.prototype.job = "student";
Person.prototype.sayName = function(){
    alert(this.name);
};

var person1 = new Person();
person1.sayName(); //"aa"

var person2 = new Person();
person2.sayName(); //"aa"

person1.name = "bb" ;
person1.name; //"bb"---来自实例
person2.name; //"aa"---来自原型

使用delete操作符可以删除实例属性:

person1.name = "bb" ;
person1.name; //"bb"---来自实例
person2.name; //"aa"---来自原型

delete person1.name;
person1.name; //"aa" ---来自原型

hasOwnProperty:检测一个属性存在于实例还是存在于原型。

person1.hasOwnProperty("name"); //false

person1.name = "bb" ;
person1.name; //"bb"---来自实例
person1.hasOwnProperty("name"); //true

delete person1.name;
person1.name; //"aa" ---来自原型
person1.hasOwnProperty("name"); //false

单独使用in操作符:对象能访问给定属性时返回true,无论此属性是来自实例还是原型。

function Person(){
}
Person.prototype.name = "aa";
Person.prototype.age = 20;
Person.prototype.job = "student";
Person.prototype.sayName = function(){
    alert(this.name);
};

var person1 = new Person();
var person2 = new Person();

person1.hasOwnProperty("name"); //false
"name" in person1 //true

person1.name = "bb" ;
person1.name; //"bb"---来自实例
person1.hasOwnProperty("name"); //true
"name" in person1 //true

因此利用hasOwnProperty与in可以判断一个属性是来自实例还是原型。

function hasPrototypeProperty(object,name){
    return !object.hasOwnPeoperty(name)&&(name in object);
}

使用for-in时,返回的是对象能访问的,可枚举的属性,其中包括来自实例的也包括来自原型的。

Object.keys( )方法可返回对象上所有可枚举的实例属性:

function Person(){
}
Person.prototype.name = "aa";
Person.prototype.age = 20;
Person.prototype.job = "student";
Person.prototype.sayName = function(){
    alert(this.name);
};
var keys = Object.keys(Person.prototype); //["name", "age", "job", "sayName"]

var person1 = new Person();
var keys = Object.keys(person1 );//[]

person1.name = "bb";
person1.age = 23;
var keys = Object.keys(person1 );//["name", "age"]

获取所有实例属性而无论其是否可枚举:Object.getOwnPropertyNames( )

var keys = Object.getOwnPropertyNames(Person.prototype);//["constructor", "name", "age", "job", "sayName"]

结果中包含了不可枚举的constructor属性。
Object.keys与Object.getOwnPropertyNames均可替代for-in。

更简单的原型语法

function Person(){
}
Person.prototype = {
    name:"aa",
    age:20,
    job:"student",
    sayName:function(){
        alert(this.name);
    }
}

但是在这种语法下,本质上是完全重写了默认的prototype对象,因此constructor属性也就不再指向Person而是Object。
若constructor属性十分重要,则可以像下面这样:

function Person(){
}
Person.prototype = {
    constructor:Person,
    name:"aa",
    age:20,
    job:"student",
    sayName:function(){
        alert(this.name);
    }
}

而此时由用户重设的constructor属性已经变成了可枚举的了。

由于在原型中查找值的过程是一次搜索,因此对原型对象所做的任何修改都能够立即从实例上反映出来,即使是先创建实例后修改原型。

function Person(){}
var friend = new Person();
Person.prototype.sayHi =function(){
    alert("Hi");
}
friend.sayHi(); //Hi

由于实例和原型间是松散连接关系,其间不过是一个指针,因此通过上面的搜索属性就可以在原型中找到新的方法。

但是如果重写整个原型对象的话(如上面的更简单的原型语法),由于调用构造函数时会为实例添加一个指向最初原型的指针,如果把原型指向另一个对象就等于切断了新原型与已经存在的实例之间联系,也切断了构造函数与旧原型的联系。已经存在的实例引用的仍是最初的原型。

function Person(){}
var friend = new Person();
Person.prototype = {
    constructor:Person,
    name:"aa",
    age:20,
    job:"student",
    sayName:function(){
        alert(this.name);
    }
}
friend.sayName(); //error

下图展示了上列过程:

重写原型对象.jpg

原生对象如Object,Array,String等都是在其构造函数的原型上定义了方法。我们也可以用此方法定义新方法:

String.prototype.startWith = function(text){
    return this.indexOf(text)==0;
}
var msg = "hello world";
alert(msg.startWith("hello")); //true

原型对象也有缺点:
1.省略了为构造函数传递初始化参数这一环节,结果所有实例在默认情况下都会取得相同的属性值。
2.原型中的属性是被多实例共享的,对于基本值属性还好,因为可以同名重写,但对于包含引用类型值的属性来说,就会有如下问题:

function Person(){
}
Person.prototype = {
    constructor:Person,
    name:"aa",
    age:20,
    job:"student",
    friends:["bb","cc"],
    sayName:function(){
        alert(this.name);
    }
}
var person1 = new Person();
var person2 = new Person();

person1.friends.push("dd");

person1.friends;//"bb,cc,dd"
person2.friends;//"bb,cc,dd"
person1.friends == person2.friends; //true

组合使用构造函数模式与原型模式

创建自定义类型的最常见方式,构造函数用于定义实例属性,原型用于定义方法和共享的属性。结果,每个实例都会有自己的一份实例属性同时又共享者对方法的引用,最大限度地节省了内存。

function Person(name,age,job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.friends = ["bb","cc"];
}

Person.prototype = {
    constructor:Person,
     sayName:function(){
        alert(this.name);
    }
}

var person1 = new Person("alice",30,"students");
var person2 = new Person("bob",34,"ceo");

person1.friends.push("dd");
person1.friends;//"bb,cc,dd"
person2.friends;//"bb,cc"

person1.friends == person2.friends; //false
person1.sayName == person2.sayName; //true

动态原型模式

把所有信息都封装在构造函数中,通过在构造函数中初始化原型,同时保证了构造函数和原型的优点。

function Person(name,age,job){
    //属性
    this.name = name;
    this.age = age;
    this.job = job;
  
    //方法
    if(typeof this.sayName != "function"){
        Person.prototype.sayName = function(){
            alert(this.name);
        };
    }
}

var friend = new Person("alice",30,"students");
friend.sayName(); //alice

if检测那段代码只会在初次调用构造函数时执行,此后原型已经完成初始化,之后调用构造函数创建的实例都会有sayname属性,不会走if里面的语句。if语句检查的可以是初始化之后应该存在的属性或方法。

使用动态函数模型时不能使用对象字面量重写原型,否则会切断现有实例与新原型之间的联系。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,980评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,178评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,868评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,498评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,492评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,521评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,910评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,569评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,793评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,559评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,639评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,342评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,931评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,904评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,144评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,833评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,350评论 2 342

推荐阅读更多精彩内容