构造函数约定( 首字母大写 )
new 的作用过程:
创建一个新对象
将构造函数的作用域赋给新对象(因此 this 指向这个新对象)
执行构造函数中的代码(为这个新对象添加属性)
返回新对象
1、(注:此方法渐渐淘汰了)
//创建构造函数
function Person () {
var obj = new Object()
//属性
obj.name = null
obj.age = null
obj.sex = null
//方法
obj.play = function () {
console.log(this.name + '在玩')
}
obj.sleep = function () {
console.log(this.name + '在睡觉')
}
//返回
return obj
}
//调用构造函数
var p = Person()
p.name = 'lucy'
p.age = '18'
p.sex = 'girl'
console.log(p) // {name: "lucy", age: "18", sex: "girl", play: ƒ, sleep: ƒ}
p.play() // lucy在玩
2、(相比较1,可以清楚看出构造的是什么函数,且更加简易)
函数中的 this:
this 所在的函数在哪个对象中,this就代表这个对象
谁调用 this 就指代谁(例如:p.sayhi() 中若调用 this,则指代 p)
构造函数中 this,始终是 new 的当前对象
//创建构造函数
function Dog (json) {
//属性
this.name = json.name
this.age = json.age
this.dogFriends = json.dogFriends
//方法
this.eat = function (something) {
console.log(this.name + '在吃' + something)
}
}
//调用构造函数
var smallDog = new Dog({ name: 'lucy', age: '18', dogFriends: 'dd,xx' })
smallDog.age = 5 // 改值
console.log(smallDog) // Dog {name: "lucy", age: 5, dogFriends: "dd,xx", eat: ƒ}
smallDog.eat('奶') // lucy在吃奶
3、(推荐)
//创建构造函数
function Dog (json) {
this._init(json)
}
Dog.prototype = {
_init: function (json) {
this.name = json.name
this.age = json.name
this.dogFriends = json.dogFriends
},
eat: function (something) {
console.log(this.name + '在吃' + something)
},
}
//调用构造函数
var smallDog = new Dog({ name: 'lucy', age: '18', dogFriends: 'dd,xx' })
smallDog.age = 5 // 改值
console.log(smallDog) // Dog {name: "lucy", age: 5, dogFriends: "dd,xx", eat: ƒ}
smallDog.eat('奶') // lucy在吃奶
// 创建静态方法
Dog.staticFun = function () {
console.log('我是静态方法')
}
Dog.staticFun()
面向对象
function Fun() { }
Fun.prototype.get = function () { }
let fun = new Fun()
/* 以下都为 true */
console.log(fun.constructor.prototype === fun.__proto__);
console.log(fun.constructor.prototype.get === Fun.prototype.get);
console.log(fun.get === Fun.prototype.get);
console.log(fun.constructor === Fun);
var Dog = function () {
return new Dog.prototype.init()
}
Dog.prototype = { //定义原型属性和方法
constructor: Dog, //指向Dog函数
//属性
init: function () {
this.name = 'lucy'
this.age = '18'
},
//方法
about: function () {
console.log(this.name + '今年已经' + this.age + '了')
},
}
Dog.prototype.init.prototype = Dog.prototype // 右边黑色转换为红色指向线
var dog = new Dog()
dog.name = 'bob' // 定义实例方法(bob代替了lucy)
dog.about() // bob今年已经18了
访问时,若是实例中有属性,则直接使用实例,否则找它的原型
继承
创建构造函数
function BigDog (json) {
this.name = json.name
this.age = json.age
this.eat = function (something) {
console.log(`${this.age} 岁大的 ${this.name} 在吃 ${something}`)
}
}
BigDog.prototype.play = function (something) {
console.log(`${this.name} 在玩 ${something}`)
}
继承 BigDog 的方法
对象冒充
function SmallDog1 (json) {
BigDog.call(this, json) // 对象冒充继承
}
// 在实例化子类时可以给父类传参
let dog1 = new SmallDog1({ name: 'lucy', age: 10 })
// 问题:对象冒充可以继承构造函数里面的属性和方法,但无法继承原型链的
// dog.play('ball') // 报错
dog1.eat('零食')
原型链
function SmallDog2 () {}
SmallDog2.prototype = new BigDog({ name: 'bob', age: 20 })
// 问题:在实例化子类时无法给父类传参
let dog2 = new SmallDog2()
// 原型链实现继承:可以继承构造函数里面的属性和方法,也可以继承原型链上面的属性和方法
dog2.play('ball')
dog2.eat('foods')
原型链 + 对象冒充
function SmallDog3 (obj) {
BigDog.call(this, obj)
}
// SmallDog3.prototype = new BigDog()
// 推荐选用这种原型链继承,避免重复继承构造函数里面的属性和方法从而浪费性能
SmallDog3.prototype = BigDog.prototype
let dog3 = new SmallDog3({ name: 'tom', age: 66 })
dog3.play('game')
dog3.eat('banana')
补充
- 原型链上面的属性会被多个实例共享,构造函数不会