1.原型的指向问题
1.1原型链最终指向问题:
function Person(name, age) {
this.name = name;
this.age = age;
}
console.log(Person.prototype.constructor);
// 构造函数Person的实例化对象的__proto__属性与构造函数的prototype属性指向同一对象,而构造函数的prototype属性也是一个对象,那么他也有__proto__属性,指向哪里?
console.log(Person.prototype.__proto__.constructor); //打印结果是Object,Object也有prototype属性,Object的prototype属性也是一个对象,其上面也有__proto__属性
console.log(Object.prototype.__proto__); //打印结果为null,这说明这个属性是原型链的顶层
1.2给构造函数的prototype添加属性后,原型的指向问题
原型的指向问题
function Student(name, age) {
this.name = name;
this.age = age;
}
Student.prototype = {
say: function() {
console.log('说话');
}
}
var stu1 = new Student('张三', 14);
console.log(stu1);
console.log(stu1.__proto__.constructor); //打印结果为Object
console.log(Student.prototype.constructor); //打印结果为Object
在构造函数上面赋值方法,原型构造器指向Object,因为会改变指向问题,所以不推荐使用,常用的方法是在构造函数上面.属性就可以,不会改变原型的指向
function Student(name, age) {
this.name = name;
this.age = age;
}
Student.prototype.say = function() {
console.log('说话');
}
var stu1 = new Student('张三', 14);
console.log(stu1);
console.log(stu1.__proto__.constructor); //打印结果为Student
console.log(Student.prototype.constructor); //打印结果为Student
2.原型继承问题:
// 原型继承
function Person(name, age) {
this.name = name;
this.age = age;
}
function Student(name, age) {
this.name = name;
this.age = age;
}
Student.prototype.className = '一班';
Student.prototype.playLove = function() {
console.log(this.name + '爱搞对象');
}
Student.prototype = new Person('小王', 18); //改变Student的原型
console.log(Student.prototype.constructor == Person); //true
Student.playLove() //Student.playLove is not a function
Student的原型被改变,此时指向的是Person,而Person中并没有playLove的方法,所以会报错,怎么解决这个问题?
-->在Student原型中添加完属性后,把这一步骤放在改变Student原型指向的后面,这样,既可以获得最新指向的属性
,而能获取在Student原型中添加的属性
Student.prototype = new Person('lisi', 18); //改变Student的原型
Student.prototype.className = '一班';
Student.prototype.playLove = function() {
console.log(this.name + '爱搞对象');
} //在Student原型中添加属性,放在原型指向改变的后面,既可以得到Person中的属性,也可以得到,现在在原型中添加的属性
var stu1 = new Student('小明', 19)
console.log(Student.prototype.constructor == Person); //true
console.log(Student.prototype);
Student.prototype.playLove()
console.log(stu1);
stu1.playLove() //小明爱搞对象
3.构造函数继承
call,apply和bind
call方法的作用
1.1 函数名.call()可以实现函数的调用
function fn1() {
console.log('我是函数1');
}
fn1();
fn1.call()
1.2 call() 可以改变this的指向
var name = '张三';
var obj1 = {
name: '李四',
age: '12',
say: function() {
console.log(this.name + '学习');
}
};
obj1.say.call() //call里面不传递参数,this指向的是window
obj1.say.call(obj1) //call里面传递的第一个参数可以改变this指向,此时this指向的是obj1;
1.3 call() 方法实现继承
call会改变this的指向,如果有参数this指向该参数中的第一个参数,剩余的参数是一个参数列表
function Person(name, age) {
this.name = name;
this.age = age;
console.log(this); //Student {score: 100, name: "lilei", age: 13, study: ƒ} 通过Person.call()改变this指向,此时this指向的是实例化对象
};
function Student(score, name, age) {
this.score = score;
this.study = function() {
console.log(this.name + '爱学习');
}
console.log(this); //Student {score: 100, study: ƒ}
Person.call(this, name, age); //通过call方法,可以使Student继承Person里面的name和age的属性
console.log(this); //Student {score: 100, name: "lilei", age: 13, study: ƒ}
}
var stu1 = new Student(100, 'lilei', 13)
console.log(stu1);
apply方法的使用:apply可以改变this指向,但是apply方法里面只能传递两个参数,第一个是this的指向,第二个是数组
function Person(name, age) {
this.name = name;
this.age = age;
console.log(this);
};
function Student(score, name, age) {
this.score = score;
this.study = function() {
console.log(this.name + '爱学习');
}
console.log(this);
Person.apply(this, [name, age]);
console.log(this);
}
var stu1 = new Student(100, 'lilei', 13)
console.log(stu1);
bind方法的使用:bind可以改变this指向,但是bind方法返回的是一个函数,不能立即执行,需要调用(call和apply都能够立即执行)
var name = 'lilei';
var obj1 = {
name: 'zhangsan',
age: 15,
say: function() {
console.log(this.name + '说话');
}
};
obj1.say.bind()
var O1 = obj1.say.bind();
var O2 = obj1.say.bind(obj1)
console.log(O1);
//ƒ () { console.log(this.name + '说话');}
console.log(O2);
//ƒ () { console.log(this.name + '说话');}
// O1,和O2返回的都是一个函数
O1(); //lilei说话
O2(); //zhangsan说话