1.1 创建对象的几种方式
1.1.1 通过字面量创建对象
var person = {
name: "tom",age: 23,read: function () {
console.log(name,": read book")
}
}
1.1.2 通过系统的构造函数
var person2 = new Object()
person2.name = "jerry"
person2.age = 23
person2.say = function () {
console.log(person2.name,": say hello")
}
1.1.3 通过自定义构造方法
function Person(name,age,sex) {
this.name = name
this.age = age
this.sex = sex
this.say = function () {
console.log(this.name," :say hello")
}
}
// 创建对象时,使用 new 关键字
p = new Person("tom",23,"man")
console.log(p instanceof Person)
- 开辟空间
- 将this设置成当前对象
- 初始化属性和方法
- 将this返回
1.1.4 工厂模式创建对象
function Person(name,sex) {
// new Object 作为当前的返回值
var obj = new Object()
obj.name = name
obj.age = age
obj.sex = sex
obj.say = function () {
console.log(this.name," :say hello")
}
// 手动将对象返回出去
return obj
}
// 工厂模式创建对象,不需要使用new 关键字
var p = Person("tom","man")
console.log(p instanceof Person) // false
1.2 构造函数与实例对象
// 构造函数和实例的关系
function Person(name) {
this.name = name
this.say = function () {
console.log(this.name," :say hello")
}
}
// 对象p是通过 自定义的构造函数Person创建出来的
var p = new Person("tom")
console.dir(p)
console.dir(Person)
- 实例对象的
__proto__
属性中有constructor属性,上面记录着自己的构造方法。
- Person是构造方法,也是对象,我们直接打印Person得到的结果中有个属性prototype,它里面也有个属性叫做 constructor。里面记录着构造方法就是自己本身。
- 结合上面的例子,我们其实可以得到这样的推断,实例对象的原型属性 和 构造函数的原型属性中的constructor都指向了同一个构造方法 ,然后可以进一步推断
p是Person类型
。
console.log(p.constructor === Person) // true
console.log(p.__proto__.constructor == Person) // true
console.log(p.__proto__.constructor == Person.prototype.constructor) // true
// 由此推断出,p === Person
console.log(p instanceof Person) // true
2.1 引入原型的必要性
// 构造函数创建对象带来的问题
function Person(name) {
this.name = name
this.say = function () {
console.log(this.name,": say hello")
}
}
var p1 = new Person("tom")
var p2 = new Person("jerry")
p1.say() // tom : say hello
p2.say() // jerry : say hello
// todo 返回false, 表示说,p1和p2的say方法,并不是同一份, 其实这并不是一件好事
console.log(p1.say == p2.say)
// 共享函数,引出原型
function Say() {
console.log(this.name,": say hellp")
}
function Person(name) {
this.name = name
this.say = Say
}
var p1 = new Person("tom")
var p2 = new Person("jerry")
p1.say()// tom : say hellp
p2.say()// jerry : say hellp
// 这样的话,确实能实现节省空间,但是容易出问题
console.log(p1.say == p2.say) // ture
2.2 认识原型
function Person(name) {
this.name = name
}
// 在原型上添加方法
// 为什么可以说原型是对象呢? 想想js中一个对象可以通过 点 , 动态点添加属性和方法?
Person.prototype.say = function () {
console.log(this.name,":say hello")
}
var p1 = new Person("tom")
var p2 = new Person("jerry")
p1.say()//tom :say hello
p2.say()//jerry :say hello
console.log(p1.say == p2.say) // true
console.dir(p1)
console.dir(p2)
console.dir(Person)
- 实例对象中的直接拥有的标准属性,比如name, 这些都是直接出现在构造方法中的属性,而且这些属性是js对象所私有的。
- 上图中实例对象有个属性叫做:
__proto__
,这个属性是用来给浏览器使用的,而不是给程序员使用,所以我们称它为非标准属性。 此外谷歌浏览器是支持这个属性的,但是在IE8浏览器中,我们执行这句console.log(p1.__proto__)
会报错,说undefined
2.3 原型,实例对象,构造函数之间到底是什么关系呢?
-
-
-
-
-
-
2.4 关于this对象
function Person(name) {
// 考虑一下,这个this是谁?
this.name = name
console.log(this)
}
var p = new Person("tom")
function Person(name) {
// 考虑一下,这个this是谁?
this.name = name
console.log("n10: ",this)
}
Person.prototype.say = function () {
// todo 这里的this指的是谁呢?
// 首先,方法是添加在原型对象上, 那么this指的是原型对象吗?
// 通过控制台可以看到,this.name ,其实不是原型对象,而是say()方法的调用者(实例对象)
console.log("n16: ",this.name,": say hello")
}
var p1 = new Person("tom")
var p2 = new Person("jerry")
p1.say()
p2.say()
// 用面向对象的方式封装构造函数
function ChangeStyle(btnId,dvId,color) {
this.btnObj = document.getElementById(btnId)
this.dv = document.getElementById(dvId)
this.color = color
}
// 在构造方法的原型上添加方法
ChangeStyle.prototype.init = function () {
// 这里面的this表示的是 调用init方法的实例对象
var that = this
this.btnObj.onclick = function () {
// todo 为什么原型中的函数中,就不能使用this,而是that呢???
// todo 或者问下,当前函数中的this是谁呢?
that.dv.style.backgroundColor = that.color
}
}
2.5 其他原型的写法
- 最常见的写法就是像下面这样,在当前原型的基础上添加属性或者方法
function Person(name) {
this.name = name
}
// 前面的例子中我们都是像下面这样写代码, 这其实是对原来的 原型对象属性的累加
// 原来的原型对象中有个属性,叫做consturctor
Person.prototype.say = function(){
//todo
}
Person.prototype = {
constructor:Person,// 手动修改构造器的指向
height:"20",weight:"20",say:function () {
// todo
}
}
2.6 方法之间的相互访问
function Person(name) {
this.name = name
this.say = function () {
console.log("say")
// 通过这个例子,可以看到,对象的方法中可以直接调用对象的方法
this.eat()
}
this.eat = function () {
console.log("eat")
}
}
function Person(name) {
this.name = name
}
Person.prototype.say = function(){
console.log("say")
// 原型中的方法也可以相互访问
this.eat()
}
Person.prototype.eat = function(){
console.log("eat")
}
var p1 = new Person("tom")
p1.say()
2.7 覆盖内置对象原型中的方法
// 在现有的js封装类上干这件事,也算是在修改源码
String.prototype.myReverse = function () {
for (var i = 0; i < this.length; i++) {
console.log("发生倒叙")
}
}
var str = "123"
str.myReverse()