复习....创建对象的三种方式:
<script> /* * * 创建对象的三种方式: * 1.new Object()----内置构造函数创建 * 2.字面量方式创建 * 3.自定义构造函数创建 * * 对象:特指的某个事务,有属性和方法 * 小明: * 姓名,年龄,身高,体重,---特征,属性 * 吃饭,唱歌,逛街,打球----行为,方法 * * * */ // 1.系统内置构造函数创建 var obj = new Object(); obj.name = "小明"; obj.age = 12; obj.sayHi = function () { console.log("你好,我叫小明"); }; console.log(obj.name); obj.sayHi(); //2.字面量方式创建 var obj1 = { name: "小黄", age: 16, eat: function () { console.log("恰饭"); }, sleep: function () { console.log("小黄爱睡觉!"); } } console.log(obj1.name); obj1.eat(); // console.log(obj1 instanceof Object); //3.自定义构造函数创建 // ①创建自定义构造函数 function Person(name, age) { this.name = name; this.age = age; this.play = function () { console.log("打豆豆"); } } //② 实例化对象 var obj2 = new Person("小明", 16); console.log(obj2.name); var obj3 = new Person("小黄", 16); console.log(obj3.name); console.log(obj3 instanceof Person); /* * * 自定义构造函数做了四件事: * 1.在内存中开辟空间,存储对象 * 2.将this指向当前对象 * 3.设置属性和方法的值 * 4.把this对象返回。 * * * */ /* 使用工厂函数批量创建对象*/ function createObjs(name, age) { var obj = new Object(); obj.name = name; obj.age = age; obj.sayHi = function () { console.log("你好,我叫" + this.name + ",很高兴认识你!") } return obj; } var obj4 = createObjs("小绿", 18); console.log(obj4.name); obj4.sayHi(); </script>
原型:用原型来解决数据共享的问题
原型链:
<script>
//创建对象:第一步,添加自定义构造函数----构造函数首字母大写,普通函数驼峰命名法
function Person(name,age) {
this.name=name;
this.age=age;
this.eat=function () {
console.log("吃饭");
};
};
//原型的作用之一:数据共享,节省内存空间
Person.prototype.height=180;
Person.prototype.sleep=function () {
console.log("每天都要睡够八小时");
};
//实例化对象
var obj=new Person("小明",12);
console.dir(Person);
console.dir(obj);
//构造函数中的原型对象(prototype)和实例对象中的原型对象(__proto__)是相同的.
//实例对象中的原型对象(__proto__)指向构造函数中的原型对象(prototype)
console.log(Person.prototype==obj.__proto__);
</script>
原型对象最终指向了哪里:
<div id="dv"></div> <script> function Person() { } Person.prototype.eat=function () { console.log("盘他"); }; var obj =new Person(); console.dir(obj); console.dir(Person); //实例对象中__proto__指向原型对象中 prototype console.log(obj.__proto__==Person.prototype); //原型对象是一个对象,有一个__proto__指向Object这个构造函数中的原型对象prototype,最终指向null. console.log(Person.prototype.__proto__==Object.prototype); console.log(Object.prototype.__proto__);//null //实例对象中的__proto__--->Person.prototype ----->Object.prototype,最终指向null console.log(Person.prototype.__proto__==Object.prototype); console.log(Object.prototype.__proto__)//null //实例对象中的__proto__ ---->Person.prototype ----->Object.prototype---->null; var dvObj = document.getElementById("dv"); console.dir(dvObj); //dvObj.__proto__--->HTMLDivElement.prototype的__proto__ ---->HTMLElement---->Element---> Node----->EventTarget----->Object---null///最终都指向null; </script>
原型指向发生改变如何添加属性和方法:
//人的构造函数 function Person(age) { this.age=age; } //学生的构造函数 function Student(score) { this.score=score; } //原型的指向可以发生改变,指向人的实例对象------先一步改变指向 Student.prototype=new Person(12); //通过原型对象添加eat方法----实现方法共享,节省内存空间 Student.prototype.study=function () { console.log("敲代码敲代码"); } Student.prototype.weight=180; //实例化学生 var stu = new Student(80); stu.study(); console.log(stu.weight); //总结:如果原型的指向发生了改变,但是又需要用原型对象中的方法和属性,可以将指向发生改变的放在最前面,发生改变后,再添加属性和方法,这样就可以使用了. </script>
继承:
//使用修改原型对象的指向来实现继承 //人的构造函数 function Person(name,age,sex) { this.name=name; this.age=age; this.sex=sex; } Person.prototype.eat=function () { console.log("吃饭"); }; //学生的构造函数 function Student(score) { this.score=score; } //改变原型指向 Student.prototype=new Person("小红",18,"女"); //通过原型添加study方法 Student.prototype.study=function () { console.log("打代码,敲代码"); } //实例化学生对象 var hhh = new Student(80); console.log(hhh.name); console.log(hhh.age); console.log(hhh.sex); hhh.eat(); console.log("学生对象下自己的属性======="); console.log(hhh.score); hhh.study(); var hhh1 = new Student(50); console.log(hhh1.name,hhh1.age,hhh1.sex,hhh1.score); var hhh2 = new Student(50); console.log(hhh2.name, hhh2.age, hhh2.sex, hhh2.score); //缺陷:因为改变了原型指向的同时实现的继承,直接初始化了属性,继承过来的属性的值都是一样的. </script>
借用构造函数继承:
//人的构造函数 function Person(name,age) { this.name=name;//this指的是当前的实例对象 this.age=age; } //通过原型对象添加eat方法 Person.prototype.eat=function () { console.log("吃饭"); } //学生的构造函数 function Student(score,name,age) { Person.call(this,name,age); this.score=score; } Student.prototype.study=function () { console.log("敲代码"); }; var stu1=new Student(80,"小明",18); console.log(stu1.name,stu1.age,stu1.score); var stu1=new Student(90,"小白",19); console.log(stu1.name,stu1.age,stu1.score); var stu1=new Student(100,"小红",20); console.log(stu1.name,stu1.age,stu1.score); </script>
组合继承:
<script> //添加人的构造函数 function Person(name,age) { this.name=name; this.age=age; } Person.prototype.eat=function () { console.log("吃饭"); } //创建学生的构造函数 function Student(name,age,score) { Person.call(this,name,age); this.score=score; } //修改原型指向 Student.prototype=new Person();//不传值 Student.prototype.study=function () { console.log(this.name+"敲代码,敲到老"); }; var stu1=new Student("小红",16,100); console.log(stu1.name,stu1.age,stu1.score); stu1.study(); stu1.eat(); var stu2=new Student("小白",17,90); console.log(stu2.name,stu2.age,stu2.score); stu2.study(); stu2.eat(); </script>
拷贝继承:
<script> // var obj1={ // name:"李靖", // age:18, // sex:"nan", // tuoTa:function () { // console.log("托塔李天王"); // } // } // //改变了 // var obj2 =obj1; // console.log(obj2.name,obj2.age,obj2.sex); // obj2.tuoTa(); function Person() { } Person.prototype.name="李靖"; Person.prototype.age=18; Person.prototype.sex="男"; Person.prototype.tuoTa=function () { console.log("托塔李天王"); } var obj2={}; for(var key in Person.prototype) { obj2[key]=Person.prototype[key]; } console.dir(obj2); var key="name属性"; var key="age属性"; var key="sex属性"; var key="tuota方法名"; //获取对象的属性 对象.属性名 对象["属性"] for(var key in Person.prototype){ console.log(key+"======="+Person.prototype[key]); } </script>
总结:
/* * 继承
* 1.修改原型对象的指向实现继承 * 缺陷:属性重复
* 2.借用构造函数实现继承 * 要继承的子构造函数:父构造函数.call,(this属性1,属性2) * 缺陷:方法不能继承
* 3.组合继承:原型对象+构造函数
* 属性可以不重复,方法也可以继承
* 4.拷贝继承:把一个对象中的属性和方法直接拷贝到另一个对象中
* 使用 for-in循环,将一个对象中的所有属性和方法赋值给另一个对象 * */