# 面向对象是现实的抽象方式
# 创建对象
# 通过new Object()
var obj = new Object()
obj.name = "okarin"
obj.age = 18
obj.height = 1.88
obj.running = function(){
console.log(this.name + "在跑步")
}
1
2
3
4
5
6
7
2
3
4
5
6
7
# 通过字面量
var info = {
name:"okarin",
age:18,
height:1.88,
eating:function(){
console.log(this.name + "在吃东西")
}
}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# 创建多个对象
# 工厂模式
function createPerson(name,age,address){
var p ={}
p.name = name
p.age = age
p.address = address
p.eating = function(){
console.log(this.name + "在吃东西~")
}
return p
}
var p1 = createPerson("张三",18,"成都")
var p2 = createPerson("李四",20,"上海")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
工厂模式的缺点:获取不到对象最真实的类型
# 构造函数
构造函数是在创建对象时会调用的函数。
# JS中的构造函数
当通过 new关键字 调用一个函数,那么这个一个函数就是一个构造函数了。
# 构造函数创建对象
function Person(name,age,address){
this.name = name
this.age = age
this.address = address
this.eating = function(){
console.log(this.name + "在吃东西~")
}
}
var p1 = new Person("张三",18,"成都")
console.log(p1)
//Preson { name: '张三', age: 18, address: '成都', eating: [Function] }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
- 构造函数名字首字母要大写
- 构造函数不需要return 就可以返回结果
- 调用构造函数 必须使用 new
- 只要调用函数就创建一个对象
- 属性和方法前面必须添加 this
# 构造函数的缺点
当对象值是函数时,创建的每一个对象的函数是不一样的,这样如果创建很多个对象,也会创建多个新的函数,这是不必要的。
# 原型加构造函数
function Person(name,age,address){
this.name = name
this.age = age
this.address = address
}
Person.prototype.eating = function(){
console.log(this.name + "在吃东西~")
}
var p1 = new Person("张三",18,"成都")
console.log(p1)
console.log(p1.__proto__)
//Person { name: '张三', age: 18, address: '成都' }
//Person { eating: [Function] }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 对对象属性的操作
# Object.defineProperty
Object.defineProperty() 方法会直接在一个对象上定义一个新的属性,或者修改一个对象的现有属性,并返回此对象。
var obj = {
name:"okarin",
age:18,
eating:function(){
console.log(this.name + "在吃东西")
}
}
Object.defineProperty(obj,"name",属性描述符) //修改
Object.defineProperty(obj,"like ",属性描述符) //添加
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
添加的属性默认是不可枚举的
var obj = {
name:"okarin",
age:18,
eating:function(){
console.log(this.name + "在吃东西")
}
}
Object.defineProperty(obj,"height",{
value:1.88
})
for(var key in obj){
console.log(key , ":",obj[key]) //这时的height是不可枚举的 不会打印height
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 属性描述符分类
# 数据属性描述符
var obj = {
name:"okarin",
age:18,
eating:function(){
console.log(this.name + "在吃东西")
}
}
//数据属性描述符
Object.defineProperty(obj,"address",{
//配置
value:"chengdu", //默认值 undefined
configurable:false,//属性是否是可配置的 默认 false 不能删除也不能更改
enumerable:false,//属性是否是可枚举的 默认 false 不能枚举 也不能遍历
writable:false,//属性是否是可以写入的 默认 false 不能写入
})
delete obj.age
console.log(obj.age) //undefined
delete obj.address
console.log(obj.address)//chengdu
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 存取属性描述符
var obj = {
name:"okarin",
age:18,
_address:"chengdu",
eating:function(){
console.log(this.name + "在吃东西")
}
}
//存取属性描述符
Object.defineProperty(obj,"address",{
//配置
configurable:true,//属性是否是可配置的 默认 false 不能删除也不能更改
enumerable:true,//属性是否是可枚举的 默认 false 不能枚举 也不能遍历
get:function(){
return this._address
},
set:function(value){
this._address = value
}
})
console.log(obj.address) //chengdu
obj.address = "shanghai"
console.log(obj.address)//shanghai
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
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
- 隐藏某一个私有属性不希望直接被外界使用和赋值
- 如果希望截获某一个属性的访问和设置值的过程时,也会使用存取属性描述符
# 定义多个属性描述符
Object.defineProperties()
var obj = {
_age : 18,
}
Object.defineProperties(obj,{
name:{
value:"Okarin",
configurable:true,
enumerable:true,
writable:true,
},
age:{
configurable:false,
enumerable:false,
get:function(){
return this._age
},
set:function(value){
this._age = value
},
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 获取属性描述符
- Object.getOwnPropertyDescriptor()
var obj = {
name:"okarin",
age:18,
eating:function(){
console.log(this.name + "在吃东西")
}
}
//数据属性描述符
Object.defineProperty(obj,"address",{
//配置
value:"chengdu",
configurable:false
})
console.log(Object.getOwnPropertyDescriptor(obj,"age"))
//{ value: 18, writable: true, enumerable: true, configurable: true }
console.log(Object.getOwnPropertyDescriptor(obj,"address"))
// {
// value: 'chengdu',
// writable: false,
// enumerable: false,
// configurable: false
// }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
- Object.getOwnPropertyDescriptors()
var obj = {
name:"okarin",
age:18,
eating:function(){
console.log(this.name + "在吃东西")
}
}
//数据属性描述符
Object.defineProperty(obj,"address",{
//配置
value:"chengdu",
configurable:false
})
console.log(Object.getOwnPropertyDescriptors(obj))
// {
// name: {
// value: 'okarin',
// writable: true,
// enumerable: true,
// configurable: true
// },
// age: { value: 18, writable: true, enumerable: true, configurable: true },
// eating: {
// value: [Function: eating],
// writable: true,
// enumerable: true,
// configurable: true
// },
// address: {
// value: 'chengdu',
// writable: false,
// enumerable: false,
// configurable: false
// }
// }
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
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
# 对对象进行限制
# 禁止对象继续添加新的属性
Object.preventExtensions()
var obj = {
name:"okarin",
age:19
}
Object.preventExtensions(obj)
obj.address = "chengdu"
console.log(obj)
//{ name: 'okarin', age: 19 }
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
# 禁止对象配置/删除里面的属性
Object.seal()
var obj = {
name:"okarin",
age:19
}
Object.seal(obj)
delete obj.name
console.log(obj)
//{ name: 'okarin', age: 19 }
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
# 禁止对象修改属性
Object.freeze()
var obj = {
name:"okarin",
age:19
}
Object.freeze(obj)
obj.name = "Retr0"
console.log(obj)
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# 对象的原型
JavaScript中每个对象都有一个特殊的内置属性[[prototype]],这个属性可以称之为对象的原型(隐式原型),这个特殊的对象可以指向另外一个对象。
早期的ECMA没有规范如何查看[[prototype]],浏览器提供了一个
__proto__
属性便于查看。
var obj = { name: "okarin" }
console.log(obj.__proto__)//{}
1
2
3
4
2
3
4
ES5推出了Object.getPrototypeOf() 获取原型 方法可以查看[[prototype]]
var obj = { name: "okarin" }
console.log(Object.getPrototypeOf(obj))//{}
1
2
3
2
3
# 对象的原型的作用
当我们从一个对象中获取某一个属性是,它会触发[[get]]操作。
- 在当前对象中去查找对应的属性,如果找到就直接使用
- 如果在
__proto__
没有找到,就会沿着它的原型链去查找
# 函数的原型
函数作为对象来说,也是有[[prototype]]隐式原型。
function foo(){
}
console.log(foo.__proto__)//{}
1
2
3
4
5
6
2
3
4
5
6
因为函数是一个函数,所以会多出来一个显示原型属性:prototype
function foo(){
}
console.log(foo.prototype)//foo {}
1
2
3
4
5
6
2
3
4
5
6
函数的显示原型 prototype
会指向函数默认的原型对象
这个对象包括 constructor
在内的很多属性,通过构造函数创建的对象,对象中的__proto__
会指向函数的prototype
。
# 函数原型的属性
# constructor属性
function foo(){
}
console.log(Object.getOwnPropertyDescriptors(foo.prototype))
// {
// constructor: {
// value: [Function: foo],
// writable: true,
// enumerable: false,
// configurable: true
// }
// }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
prototype.constructor 指向构造函数本身
# 给prototype添加属性
function foo(){
}
foo.prototype.name = "okarin"
var f1 = new foo()
console.log(f1.name)//okarin
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# 直接修改整个prototype对象
function foo(){
}
foo.prototype = {
constructor:foo,
name:"okarin"
}
var f1 = new foo()
console.log(f1.name)//okarin
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
# 通过Object.defineProperty方式添加constructor
function foo(){
}
Object.defineProperty(foo.prototype,"constructor",{
enumerable:false,
configurable:true,
writable:true,
value:foo
})
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10