js面向对象的理解

属性理解

  1. 数据属性的4个特性

    • configurable: 表示能否用delete删除属性,能否修改属性的其他特性,能否把属性修改为访问器属性
    • enumerable: 表示能否通过for-in循环返回属性
    • writable: 表示能否修改属性的值
    • value:用来表示属性的值
  2. 修改数据属性默认特性的方法:Object.defineProperty(对象名, 属性名,描述符对象)
    举例:

var person = {};
// 该方法configurable,enumerable,writable的默认值是false(意思是说不传值的话默认会传false)
// value的默认值是undefined
// 将configurable值改为false后,经chrome59测试后发现改了之后所有特性值修改都会报错(当然如果传入的新值和旧值一样的话就不会报错)
// 不像红宝书里说的writable值还可以修改,实际上都不可修改
Object.defineProperty(person, 'name', {
    configurable: false,
    enumerable: true,
    writable: true,
    value: 'Stan'
});
// 小tip:使用chrome控制台查看对象属性时,有时会发现有些属性颜色比较淡,类似disable的状态,实际是因为该属性的enumerable特性为false

  1. 访问器属性的4个特性
    • configurable: 表示能否用delete删除属性,能否修改属性的其他特性,能否把属性修改为访问器属性
    • enumerable: 表示能否通过for-in循环返回属性
    • get: 读取属性时调用的函数,默认undefined
    • set: 写入属性时调用的函数,默认undefined
  2. 定义多个属性的方法Object.defineProperties()
    举例:
var book = {}; 
Object.defineProperties(book, { 
    _year: { 
        value: 2004 
    }, 
    edition: { 
        value: 1 
    }, 
    year: { 
        get: function(){ 
            return this._year; 
        }, 
        set: function(newValue){ 
            if (newValue > 2004) { 
                this._year = newValue; 
                this.edition += newValue - 2004; 
            } 
        } 
    } 
}); 
  1. 读取属性特性的方法Object.getOwnPropertyDescriptor
    举例:
var descriptor = Object.getOwnPropertyDescriptor(book, '_year');
alert(descriptor.value);
alert(descriptor.configurable);

创建对象

  1. 工厂模式
// 工厂模式解决了创建多个相似对象的问题,但没有解决对象识别的问题

function createPerson (name, age, job) {
    var o = {
        name: name,
        age: age,
        job: job,
        sayName: function () {
            alert(this.name);
        }
    }
    return o;
}

var person1 = createPerson('Stan', 25, 'Web front-ender');
var person2 = createPerson('Danny', 18, 'backender');
  1. 构造函数模式
// 构造函数模式解决了对象类型识别的问题,但不同实例的方法并不是同一个Function实例

function Person (name, age, job) {
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = function () {
        alert(this.name);
    }
}

var person1 = new Person('Stan', 25, 'Web front-ender');
var person2 = new Person('Danny', 18, 'backender');
person1.sayName === person2.sayName // false

// 把函数定义从构造函数里移出来,解决了同一个函数的问题,但全局函数的存在让其毫无封装性可言

function Person (name, age, job) {
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = sayName
}

function sayName () {
    alert(this.name);
}

var person1 = new Person('Stan', 25, 'Web front-ender');
var person2 = new Person('Danny', 18, 'backender');
person1.sayName === person2.sayName // true
  1. 原型模式

3.1 理解原型对象
任何一个函数都有一个prototype属性,该属性的值是一个原型对象。这个原型对象自动拥有一个constructor属性,属性值为这个函数。开发者可以给函数的原型对象添加属性和方法。使用这个函数创建的实例拥有__proto__属性(Firefox、Safari、Chrome支持),该属性值指向构造函数的原型对象。举例:

function Person () {
    
};
Person.prototype.name = "Nicholas"; 
Person.prototype.age = 29; 
Person.prototype.job = "Software Engineer"; 
Person.prototype.sayName = function(){ 
    alert(this.name); 
}; 
var person1 = new Person(); 
person1.sayName(); //"Nicholas" 
var person2 = new Person();
person2.sayName(); //"Nicholas" 
alert(person1.sayName == person2.sayName); //true 

// 确定函数原型对象和实例之间的关系
alert(Person.prototype.isPrototypeOf(person1)); //true 
alert(Person.prototype.isPrototypeOf(person2)); //true 
// es5
alert(Object.getPrototypeOf(person1) == Person.prototype); //true 
alert(Object.getPrototypeOf(person1).name); //"Nicholas" 

// 对象实例添加的同名属性会屏蔽对象实例的原型对象中的属性,因为属性值会先从对象实例的属性里面查找,找不到才会去原型对象里面去找,想解除屏蔽,只有delete掉那个属性
// 在chrome59中可以通过修改person1.__proto__对象改变原型对象的值,与红宝书所说不符
person1.name = "Greg"; 
alert(person1.name); //"Greg"——来自实例
alert(person2.name); //"Nicholas"——来自原型
delete person1.name; 
alert(person1.name); //"Nicholas"——来自原型

// 判断属性是不是对象实例的
alert(person1.hasOwnProperty("name")); //false 
person1.name = "Greg"; 
alert(person1.name); //"Greg"——来自实例
alert(person1.hasOwnProperty("name")); //true 
alert(person2.name); //"Nicholas"——来自原型
alert(person2.hasOwnProperty("name")); //false 
delete person1.name; 
alert(person1.name); //"Nicholas"——来自原型
alert(person1.hasOwnProperty("name")); //false 

// in操作符单独使用可以用来判断某属性是否存在于对象实例或原型对象中
alert('name' in person1)

// for-in循环返回的是所有能够通过对象访问的、可枚举的(enumerated)属性,其中既包括存在于实例中的属性,也包括存在于原型中的属性
person1.age = 20;
for (let k in person1) {
  console.log(k + ':' + person1[k])
}
// age:20
// name:Nicholas
// job:Software Engineer
// sayName:function (){ 
//   alert(this.name); 
// }

// 想要获取对象上所有可枚举的实例属性,可以使用Object.keys()
var keys = Object.keys(Person.prototype); 
alert(keys); //["name", "age", "job", "sayName"]
var p1 = new Person(); 
p1.name = "Rob"; 
p1.age = 31; 
var p1keys = Object.keys(p1); 
alert(p1keys); //["name", "age"]

// 想要获取对象上所有实例属性,无论是否是可枚举的,可以用Object.getOwnPropertyNames(),__proto__获取不到
var keys = Object.getOwnPropertyNames(Person.prototype); 
alert(keys); //["constructor", "name", "age", "job", "sayName"]

/********************************************************************************/
/*
 * 原型的动态性
 */
// 即使创建实例在添加方法之前,但只要调用放在后面,都可以成功执行
var friend = new Person(); 
Person.prototype.sayHi = function(){ 
 alert("hi"); 
}; 
friend.sayHi(); //"hi"(没有问题!)

// 但是重写整个原型对象的话就不一样了,这时现有实例的__proto__属性值指向的是以前的原型对象,而以前的原型对象是没有sayName方法的
function Person(){ 
} 
var friend = new Person(); 
Person.prototype = { 
  constructor: Person, 
  name : "Nicholas", 
  age : 29, 
  job : "Software Engineer", 
  sayName : function () { 
    alert(this.name); 
  } 
}; 
friend.sayName(); //error 

/*
 * 原生对象的原型
 */
// 虽然可以给原生构造函数的原型对象添加方法,但不推荐在生产环境使用,有可能命名冲突

/*
 * 原型模式的缺点
 */
// 原型模式的优势在于共享,但缺点也是由于共享导致的。如下,引用类型使得对一个实例的值做出改变,其他所有实例的值都会发生改变
function Person(){ 
} 
Person.prototype = { 
  constructor: Person, 
  name : "Nicholas", 
  age : 29, 
  job : "Software Engineer", 
  friends : ["Shelby", "Court"], 
  sayName : function () { 
    alert(this.name); 
  } 
}; 
var person1 = new Person(); 
var person2 = new Person(); 
person1.friends.push("Van"); 
alert(person1.friends); //"Shelby,Court,Van" 
alert(person2.friends); //"Shelby,Court,Van" 
alert(person1.friends === person2.friends); //true 
  1. 组合使用构造函数模式和原型模式,这样的话将和数值有关的放在构造函数里面,将方法放在原型对象里面,举例:
function Person(name, age, job){ 
  this.name = name; 
  this.age = age; 
  this.job = job; 
  this.friends = ["Shelby", "Court"]; 
} 
Person.prototype = { 
  constructor : Person, 
  sayName : function(){ 
    alert(this.name); 
  } 
} 
var person1 = new Person("Nicholas", 29, "Software Engineer"); 
var person2 = new Person("Greg", 27, "Doctor"); 
person1.friends.push("Van"); 
alert(person1.friends); //["Shelby", "Court", "Van"]
alert(person2.friends); //["Shelby", "Court"]
alert(person1.friends === person2.friends); //false 
alert(person1.sayName === person2.sayName); //true 
  1. 寄生构造函数模式和稳妥构造函数模式
    没有看出这两种模式有什么实际意义,仅记录

继承

  1. 组合继承
    是将原型链和借用构造函数的技术组合到一块的继承方式,举例:
function SuperType(name) {
  this.name = name;
  this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function() {
  alert(this.name);
};

function SubType(name, age) {
  //继承属性
  SuperType.call(this, name);

  this.age = age;
}
//继承方法
SubType.prototype = new SuperType();
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function() {
  alert(this.age);
};
var instance1 = new SubType("Nicholas", 29);
instance1.colors.push("black");
alert(instance1.colors); //["red", "blue", "green", "black"]
instance1.sayName(); //"Nicholas"; 
instance1.sayAge(); //29 
var instance2 = new SubType("Greg", 27);
alert(instance2.colors); //["red", "blue", "green"]
instance2.sayName(); //"Greg"; 
instance2.sayAge(); //27
  1. 原型式继承
    只是用来创建一个类似对象
function object(o) {
  function F() {}
  F.prototype = o;
  return new F();
}
var person = {
  name: "Nicholas",
  friends: ["Shelby", "Court", "Van"]
};
var anotherPerson = object(person);
anotherPerson.name = "Greg";
anotherPerson.friends.push("Rob");
var yetAnotherPerson = object(person);
yetAnotherPerson.name = "Linda";
yetAnotherPerson.friends.push("Barbie");
alert(person.friends); //"Shelby,Court,Van,Rob,Barbie"

// 可用Obect.create()实现类似功能
var person = {
  name: "Nicholas",
  friends: ["Shelby", "Court", "Van"]
};
var anotherPerson = Object.create(person, {
  name: {
    value: "Greg",
    enumerable: false
  }
});

alert(anotherPerson.name); //"Greg"
  1. 寄生组合式继承
    最有效的方式
function SuperType(name) {
  this.name = name;
  this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function() {
  alert(this.name);
};

function SubType(name, age) {
  SuperType.call(this, name);
  this.age = age;
}
inheritPrototype(SubType, SuperType);
SubType.prototype.sayAge = function() {
  alert(this.age);
};

var instance = new SubType('Stan', 25);
alert(instance);

function inheritPrototype (subType, superType) {
  var prototype = object(superType.prototype);
  prototype.constructor = subType;
  subType.prototype = prototype;
}
function object(o) {
  function F() {}
  F.prototype = o;
  return new F();
}

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

推荐阅读更多精彩内容

  •   面向对象(Object-Oriented,OO)的语言有一个标志,那就是它们都有类的概念,而通过类可以创建任意...
    霜天晓阅读 2,093评论 0 6
  • 本章内容 理解对象属性 理解并创建对象 理解继承 面向对象语言有一个标志,那就是它们都有类的概念,而通过类可以创建...
    闷油瓶小张阅读 841评论 0 1
  • 1.理解对象 创建自定义对象的最简单方式就是创建一个Object 的实例,然后再为它添加属性和方法 用对象字面量语...
    Zoemings阅读 504评论 0 2
  • 博客内容:什么是面向对象为什么要面向对象面向对象编程的特性和原则理解对象属性创建对象继承 什么是面向对象 面向对象...
    _Dot912阅读 1,401评论 3 12
  • 从1月 8号晚上知道PRS 在交易所上线 ,我就赶紧买入 ,当时看到价格的时候是一直在涨先后买入了3次 ,用了一半...
    贾小萍阅读 156评论 1 1