之前有篇博客曾提到过一点js的面向对象编程:js面向对象编程.

这里就结合js高程详细剖析一下javascript的面向对象编程.

前序:

1⃣️Object.defineProperty()

    var obj = {
_name:'jack'
};
Object.defineProperty(obj,'name',{
configurable:false,//表示能否通过delete删除属性从而重新定义属性,默认值true
value:'orange',//属性的数据值,默认值undefined
writable:false,//表示能否修改属性的值,默认值为true
enumerable:false,//是否可枚举,能否通过for-in循环返回属性,默认值为true
get:function(){//getter
return this._name;
},
set:function(newval){//setter
this._name = newval;
}
})

vue2.x版本的双向数据绑定就是基于该API和订阅/发布模式实现的;

如果同时定义多个属性,可通过如下API:

Object.defineProperties(book, {
_year: {
value:
},
edition: {
value:
},
year: {
get: function(){
return this._year;
},
set: function(newValue){
if (newValue > ) {
this._year = newValue;
this.edition += newValue - ;
}
}
}
});

2⃣️读取属性的特性Object.getOwnPropertyDescriptor() 

var descriptor = Object.getOwnPropertyDescriptor(book, "_year");
alert(descriptor.value); //
alert(descriptor.configurable); //false

正文:

3⃣️创建对象

3.1 工厂模式

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("Nicholas", , "Software Engineer");
var person2 = createPerson("Greg", , "Doctor");

工厂模式创建了n个互不关联的对象,但是却没有解决对象识别的问题(即怎样知道一个对象的类型) .

3.2 构造函数模式

function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
this.sayName = function(){
alert(this.name);
}; }
var person1 = new Person("Nicholas", , "Software Engineer");
var person2 = new Person("Greg", , "Doctor");

因为函数也是一个对象,所以可以通过该方式创建一个Person对象;

按照惯例,构造函数始终都应该以一个 大写字母开头,而非构造函数则应该以一个小写字母开头 ;

要创建 Person 的新实例,必须使用 new 操作符。以这种方式调用构造函数实际上会经历以下 4 个步骤:

(1) 创建一个新对象;
(2) 将构造函数的作用域赋给新对象(因此 this 就指向了这个新对象);
(3) 执行构造函数中的代码(为这个新对象添加属性);
(4) 返回新对象。

alert(person1.constructor == Person); //true
alert(person2.constructor == Person); //true
alert(person1 instanceof Object);  //true
alert(person1 instanceof Person); //true
alert(person2 instanceof Object); //true
alert(person2 instanceof Person); //true

构造函数模式虽然好用,但也并非没有缺点。使用构造函数的主要问题,就是每个方法都要在每个实例上重新创建一遍,不能共享。虽然我们可以将该方法写到全局作用域,然后在构造函数内部调用,但是这种做法显然耦合度过高.

3.3 原型模式

可以顺便参照之前的博客:js继承的实现.

function Person(){
}
Person.prototype.name = "Nicholas";
Person.prototype.age = ;
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

可以看到,原型属性上的属性值和属性方法是被所有实例共享的.

3.3.1实例属性和原型属性

person1.name = "Greg";
alert(person1.name); //"Greg"——来自实例
alert(person2.name); //"Nicholas"——来自原型 delete person1.name;
alert(person1.name); //"Nicholas"——来自原型

我们看到访问实例属性的时候,优先级是实例属性-->原型属性,删除属性的时候优先级也是如此;

实例上有该属性,就直接拿实例的该属性,没有的话就去原型上找.

3.3.2 hasOwnProperty() 判断属性是不是来自于实例

var person1 = new Person();
var person2 = new Person();
alert(person1.hasOwnProperty("name")); //false
person1.name = "Greg";
alert(person1.name); //"Greg"——来自实例
alert(person1.hasOwnProperty("name")); //true

实例的原型属性不可枚举:

var keys = Object.keys(Person.prototype);
alert(keys); //"name,age,job,sayName" var p1 = new Person();
p1.name = "Rob";
p1.age = ;
var p1keys = Object.keys(p1);
alert(p1keys); //"name,age"

最新文章

  1. Codeforces Round #383 (Div. 1)
  2. snoopy采集
  3. POSTGRES与JDBC对照
  4. QT 初阶 1.3 节 控件的几何排列
  5. TimeVal类——Live555源码阅读(一)基本组件类
  6. a byte of python(摘02)
  7. 字符串—strcpy
  8. java jps命令
  9. 多进程和atexit清理函数
  10. php不使用copy()函数复制文件的方法
  11. nginx缓存优先级(缓存问题者必看)
  12. button倒计时可点击
  13. Cobar是提供关系型数据库(MySQL)分布式服务的中间件
  14. JavaScript 多级联动浮动(下拉)菜单 (第二版)
  15. nopCommerce 3.9 大波浪系列 之 汉化-中文语言
  16. 201521123037 《Java程序设计》第2周学习总结
  17. Postgresql中的explain
  18. static_cast, dynamic_cast, const_cast 类型转换如何使用?
  19. java线程入门一
  20. SpringBoot之文件上传

热门文章

  1. linux内核 进程调度
  2. numpy的ndarray数组如何reshape成固定大小
  3. Machine Learning(Andrew Ng)学习笔记
  4. 移动端rem使用及理解
  5. BZOJ 4388 [JOI2012春季合宿]Invitation (线段树、二叉堆、最小生成树)
  6. python-获取程序的路径
  7. Python 之类与对象及继承
  8. CentOS 7下使用Apache2部署Django项目,解决文件名中含有中文报错的问题
  9. Python学习笔记—条件判断和循环
  10. java list对象按照某个属性去重