1.前言:
object function为js中的引用数据
引用数据 ==>是一种内存空间 是一种数据容器 数据容器就是可以存储很多数据的引用
- 数组是一种有下标的数据容器
- 对象是一种有键值对的数据容器
- 函数是一种有代码块和作用域的数据容器
函数的属性
name 保存了一个字符串 即函数的名字
length 保存了一个数字 即函数形参的个数
prototype 保存(引用)了一个系统内置的对象 这个对象是new Object()
构造函数
- 一般专门用于创建对象的函数 就是构造函数
- 同一个函数创建出来的对象们 具有相同的空间结构和功能
- 每一个函数创建出来的对象是不相同的
构造函数的分类
1.自定义构造函数
- 自定义构造函数的原型对象也是一个自定义构造函数创建的对象
实例:
function Kedou() {
this.life = 1
this.tail = 1
}
var k1 = new Kedou()
function Qingwa() {
this.leg = 4
this.eye = 2
}
var k2=new Kedou() //k1,k2 结构和原型对象相同 同一个函数创建的对象
Qingwa.prototype=k2
/* 分析:
Qingwa.prototype=由Qingwa()创建的对象的__proto__属性=k2
k2是Kedou()创建的对象 ==>k2.__proto__=Kedou.prototype=k1.__proto__
那么Qingwa.prototype=q1.__proto__=k2
==>q1.__proto__.__proto__=k2.__proto__=k1.__proto__
*/
var q1 = new Qingwa()
console.log(q1.life) //1
/* 找到life属性的步骤:q1.life==this.life
1.先去 Qingwa()中找是否有life属性 无
2.去q1的__proto__(Qingwa的prototype)即k2中找 k2对象有k2.life=1 找到
*/
//k1是不是q1的原型对象?-----不是
console.log(q1.__proto__==k1,q1.__proto__==k2) //false
//k1的原型对象是q1的原型对象的原型对象
console.log(k1.__proto__===q1.__proto__.__proto__) //true
2.官方提供的函数:Function String Number Boolean Object Array Date Math ...
2.原型
定义:原型是function对象的一个属性,它定义了构造函数制造出的对象的公共祖先。
基本思想:内存空间共用
使用构造函数创建对象:
- 任何函数都有一个属性 prototype 是一个对象 new Object()/{}
- 所有的对象都有一个属性 __proto__ 代表的是这个对象的原型对象
- 用函数创建对象 创建出来的原型对象就是prototype属性引用的对象
- prototype属性中引用了一个系统内置的对象:new Object()/{}
- 同一个函数创建出来的对象的原型对象是同一个对象
构造函数、原型、实例对象的关系:
- 实例对象都有__proto__属性 该属性指向构造函数的原型对象
- 构造函数都有prototype属性 这个属性是一个对象,是Object的实例
- obj.__proto__===Object.prototype
prototype与__proto__的关系:
- prototype是构造函数的属性
- __proto__是实例对象的属性
- 两者指向同一个对象
3.案例
function fn(firstName) {
this.life = 1
this.firstName = firstName
this.sayName = function () {
console.log(this.firstName)
}
}
var f1 = new fn("张") //{life:1,firstName:"张",sayName:f()}
var f2 = new fn("李") //{life:1,firstName:"李",sayName:f()}
f1.__proto__.age = 23
console.log(f2.age) //23
/*
f1 f2是两个内存空间 但f1 f2的原型对象是相等的(对象共用存储空间)
因为是同一个函数(fn)创建的对象 所以f2也能访问age属性 f2.age=f1.age=23
*/
function fn() {
this.life = 1
//隐式操作: fn.prototype={}
}
function fm() {
this.color = "black"
//隐式操作: fm.prototype={}
}
var f1 = new fn()
var f2 = new fm()
console.log(f1.__proto__ === f2.__proto__) //false 因为函数不是同一个内存空间
console.log(f1.__proto__ === fn.prototype) //true
console.log(f2.__proto__ === fm.prototype) //true
console.log(f1.__proto__ === fm.prototype) //false
//f1的原型对象是fn的prototype f2的原型对象是fm的prototype
function fn() {
this.life = 1
}
fn.prototype.color = "red"
var f1 = new fn()
f1.age = 21
var f2 = new fn()
var f3 = new fn()
console.log(f1.color, f2.color, f3.color) //都是red
console.log(f2.age) // undefined 只有f1能用
/* f1.__proto__.age = 21
console.log(f2.age) //21 此时f1,f2,f3均可用age
*/
function fn() {
this.a = 20
}
//隐式操作:fn.prototype={}
function fm() {
this.a = 30
}
//隐式操作:fm.prototype={}
fm.prototype.fn = new fn()
/* 分析:
fm.prototype.fn ==> 给fm.prototype添加成员fn ==>fm.prototype={fn:{a:20,__proto__:{}}}
new fn() ==> {__proto__:fn.prototype} ==> {a:20,__proto__:{}}
*/
var f1 = new fm()
//new fm() ==> {__proto__:fm.prototype,a:30} ==> {__proto__:{fn:{a:20,__proto__:{}}},a:30}
console.log(f1)
//{a:30,__proto__:{fn:{a:20,__proto__:{}}}}
4.对象和函数的关系(常出现在笔试题的选择题中)
通过案例分析理解:
Object.prototype.life = 1 //执行后用Object创建的对象的原型对象都有life属性 1
Function.prototype.life = 2 //执行后函数的原型对象都有life属性 2
function fn() {
this.name = "lusis"
}
var f1 = new fn()
console.log(f1.name, f1.life) //lusis 1
/* 分析:
f1.name=this.name = "jack"
f1.life ==> fn()函数中没有life属性
f1.__proto__=fn.prototype = new Object() => Object.prototype
Object.prototype有life属性为1
f1.life=Object.prototype.life=1
*/
console.log(fn.life, fn.name) //2 fn
/* 分析:
fn.life ==> fn函数中没有life属性 去到函数的原型对象
fn.__proto__=Function.prototype
Function.prototype有life属性为2
fn.life=2
fn.name ==> 函数的名字
*/
案例深入:
Object.prototype.life = 1 //执行后用Object创建的对象的原型对象都有life属性 1
function fn() {
this.name = "lusis"
}
var f1 = new fn()
console.log(f1.life) // 打印 1 fn.prototype = new Object() => Object.prototype
console.log(fn.life) /* 打印 1
Function.prototype = 函数的原型对象 => 原型对象(n层)
=> Object.prototype
*/
Function.prototype.life = 1 //所有的函数的原型对象都有life属性 1
function fn() {
this.name = "lusis"
}
var f1 = new fn()
console.log(f1.life) //undefined
/* 分析:
f1.life ==> fn()函数中没有life属性 去到原型对象
f1.__proto__=fn.prototype = new Object() => Object.prototype
Object.prototype没有定义life属性 再往上也没有life属性值 直到null
返回undefined
*/
console.log(fn.life) //1
/* 分析:
fn.life ==> fn函数中没有life属性 去到函数的原型对象
fn.__proto__=Function.prototype
Function.prototype有life属性为1
fn.life=1
*/
5.对象的成员操作
(1)基本操作:
var obj = {
name: "lusis"
}
obj.age = 20 //添加age属性
obj.name = "haha" //更新name属性
var re = obj.age //取出age属性的值
var re2 = obj.x //取出x属性的值 没有x 取出undefined
var re3 = obj.name //取出最后一次name属性修改的值
console.log(re, re2, re3) //20 undefined haha
(2)存值、取值:
function fn(name) {
this.name
}
var obj = new fn("lusis") //{name:"lusis",age:20,__proto__:{}}
//存值
obj.age = 20 //如果给一个对象存值 没有该属性就直接创建该属性
obj.name = "haha" //如果给一个对象存值 有该属性就更新该属性 但不会更新原型对象
//取值
var re=obj.age //取对象的属性值 先找原型对象的 没有再找原型的原型一直到null还没有就返回undefined
var re2 = obj.x //undefined
var re3 = obj.name //
console.log(re, re2, re3) // 20 undefined haha
6.原型对象的操作
实例:在以下程序中添加代码 使打印结果为20
function fn() {
this.a = 10
}
//fn.prototype.x=20 -->第一种
//fn.prototype={x:20} -->第二种
var f1 = new fn()
// f1.__proto__.x=20 -->第三种
//f1.__proto__={x:20} -->第四种
console.log(f1.x)
系统内置的构造函数的原型对象属性不可以修改 可以操作这个对象的属性
Array.prototype={name:"lusis"} //不会报错 但也不会生效 =>跳过编译
Array.prototype.age = 20 //所有数组都有age属性
var arr = [10, 203, 4]
console.log(arr.age, arr)
7.对象操作原型
实例:
function fn() {
this.age = 21
}
fn.prototype = {
life: 1,
fm: {
name: "lusis"
}
}
var f1 = new fn() // ==> {age:21,__proto__:{life:1,fm:{name:"lusis"}}
console.log(f1.life, f1.age) // 1 21
f1.age = 20 //更新属性值
f1.life = 2 //给自己添加life:2,不会修改原型中的life:1
// ==> {life:2,age:20,__proto__:{life:1,fm:{name:"lusis"}}
var re = f1.fm
console.log(re) // {name: "lusis"}
console.log(f1) // {age:20,life:2,__proto__:{life:1,fm:{name:"lusis"}}
f1.fm.name = "cici" //fm才是原型对象的属性 没有修改原型对象的成员就可以操作
var f2 = new fn() // ==> {age:21,__proto__:{life:1,fm:{name:"cici"}}
console.log(f2) // {age:21,__proto__:{life:1,fm:{name:"cici"}}
console.log(f2.fm.name) // cici