js面向对象类

类的概念

两种形式

第一种,工厂模型形式

1
2
3
4
5
6
7
8
9
10
11
12
13
function createPerson(name,sex,age) {
var obj = new Object();
obj.name = name;
obj.sex = sex;
obj.age = age;
obj.say = function(){
console.log('hi');
};
return obj;
}

var p1 = createPerson('alice','female',18);
p1.say();

第二种,构造函数式

函数的第一个字母大写,约定俗成认为是一个类的模板

1
2
3
4
5
6
7
8
9
10
11
12
13
function Person(name,age,sex){
this.name = name;
this.age = age;
this.sex = sex;
this.say = function(){
console.log('hi');
};
}

var p = new Person('jack',18,'male');
p.say();

console.log(p instanceof Person);

创建对象实例的方式

1
2
3
4
5
6
7
8
9
10
11
12
13
//接上述代码
//创建对象的方式:
//1当作构造函数使用
var p = new Person('jack',18,'male');

//2作为普通函数去调用
//在全局环境下定义属性并赋值,直接定义在window上
Person('jack',18,'male');

//3在另一个对象的作用域中调用
var obj = new Object;
Person.call(obj,'jack',18,'male');
console.log(obj.name);

prototype原型

概念

Object.getPrototypeof():根据实例对象获得原型对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function Person(){
}
Person.prototype.name = 'jack';
Person.prototype.age = 18;
Person.prototype.say = function(){
console.log('hi');
};
var p1 = new Person();
console.log(p1.name);

var prototypeObj = Object.getPrototypeOf(p1);
console.log(prototypeObj);

var p2 = new Person();
p2.name = 'alice';
//delete p2.name;
console.log(p2.name);

判断一个对象属性是属于原型属性还是属于实例属性

1
2
3
//接上述代码
var p3 = new Person();
console.log(p3.hasOwnPrototype('name'));

in:判断属性是否存在实例对象和原型对象中

1
2
3
4
5
6
7
8
9
10
function Person(){

}
Person.prototype.name = 'jack';

var p1 = new Person();
console.log('name' in p1);
var p2 = new Person();
p2.name = 'alice';
console.log('name' in p2);
1
2
3
4
5
6
7
8
9
10
11
//检测是否是原型对象的属性
function test(obj,attr) {
return !obj.hasOwnProperty(attr) && attr in obj;
}
function Person(){}
//Person.prototype.name = 'jack';
var p1 = new Person();
p1.name = 'jack';

var z = test(p1,'name');
console.log(z);

ecma5 Object.keys();拿到当前对象的所有keys,返回一个数组

在ecma5中,constructor属性是不能被枚举的

Object.getOwnPropertyNames的作用就是枚举对象所有的属性,不管该内部属性能否被枚举

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function Person(){};
Person.prototype.name = 'jack';
Person.prototype.age = 18;

var p1 = new Person();
p1.sex = 'male';
var attr = Object.keys(p1);
console.log(attr);//输出['sex']

var attr2 = Object.keys(Person.prototype);
console.log(attr2);//输出['name','age']

var attr3 = Object.getOwnPropertyNames(Person.prototype);
console.log(attr3);//输出["constructor", "name", "age"]

demo each方法实现

功能:遍历数组,包括多维数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
var arr = [1,2,3,4,[5,6,[7,8]]];

Array.prototype.each = function(fn){
try {
//目的是遍历数组每一项,则做一个计数器,记录当前遍历元素的位置
this.i || (this.i = 0);//this就是arr,arr.i是否存在,如果不存在,则this.i初始化为0

if(this.length>0 && fn.constructor == Function) {//数组存在并且传进的fn是函数

//循环遍历数组的每一项

//for(i in this) {}
//在写底层代码的时候,能不用for in循环就不要用for in循环
//如果代码结构层次深了,然后i和其他代码冲突了,会使得代码抛机

while(this.i < this.length) {
//核心代码
var e = this[this.i];
if(e && e.constructor == Array) {
e.each(fn);
}else{
fn.apply(e,[e]);
}
this.i++;
}
//i到此已经完成使命
this.i = null;//释放内存,垃圾回收机制会处理

}
}catch(error){

}
return this;
};

arr.each(function(item) {
console.log(item);
});

for in循环的作用域了解一下以及所有的循环

ecma5 Object.defineproperty();

三个参数:1.重设构造器的对象。 2.设置什么属性。 3.options配置项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function Person(){};
Person.prototype = function(){
name:'jack',
say:function(){
console.log('hi');
}
}
Object.defineProperty(Person.prototype,'constructor',{
enumerable:false,
value:Person
});
var p1 = new Person
for(attr in p1){
console.log(attr);
}

原型的动态特性

1
2
3
4
5
function Person () {}
var p1 = new Person();
//原型对象的构造器默认为Person
Person.prototype.say = function () {console.log('hi')};
p1.say();//输出hi
1
2
3
4
5
6
7
function Person(){}
var p1 = new Person();
Person.prototype = {
constructor:Person,
say:function(){console.log('hi')}
};
p1.say();//报错p1.say is not a function

原型概念

原型对象的所有属性和方法,被所有构造函数实例化出来的对象所共享

原型对象虽然可以对所有的实例的属性和方法共享,但是它的局限性也是很明显的。

我们一般组合使用构造函数式和原型模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function Person(name,age) {
this.name = name;
this.age = age;
}
Person.prototype = {
constructor:Person,
say:function(){
console.log(this.name);
}
}

var p1 = new Person('jack',18);
var p2 = new Person('alice',18);
p1.say();
p2.say();

开发模式

动态原型模式(代码封装到一起)

1
2
3
4
5
6
7
8
9
10
11
12
13
function Person(name,age) {
this.name = name;
this.age = age;

//动态原型方法

//一开始没有say方法,则生成;第二次有了就不用生成了
if(typeof this.say != 'function') {
Person.prototype.say = function() {
console.log(this.name);
}
}
}

稳妥构造函数式 (适合安全的环境中使用)

没有公共属性,其他方法也不引用this对象。如果你的程序对于安全性要求很高,那么适合这种模式

1
2
3
4
5
6
7
8
9
10
11
12
13
function Person(name) {
var obj = new Object();

var name = name;
obj.say = function() {
console.log(name);
}

return obj;
}

var p1 = new Person('name');
p1.say();