prototype实现继承
原型链继承的主要思想是:让子类型的引用指向父类型的实例。
每次在函数(类)中定义了成员方法,都会导致实例有副本,因此可以借助prototype原型,进行改进
先访问自己本身的方法,没有再访问自己原型的方法,本身原型没有访问父类,父类没有,访问父类的原型方法...继续往上
Object.prototype.say=function () { //最上层定义say的方法
alert("我是顶层的方法");
}
function person () {
this.say=function () {
alert("我是父类的方法");//先访问本身方法,再访问原型方法
}
}
person.prototype.say=function () {
alert("我是父类原型的方法");
}
function study () {
this.say=function () {
alert("本身的方法");
}
}
//继承person
study.prototype=new person();
study.prototype.say=function () {
alert("本身原型的方法");
}
var zhangsan=new study ();
alert(zhangsan.say)//我是父类原型的方法 父类有方法,不再向顶层找方法
使用这种方式,生成的实例既是子类实例,又是父类的实例
子类访问父类型原型链属性和方法
通过原型链继承的子类,可以直接访问到父类原型链上新增的方法和属性。
原型链继承缺点:
无法实现多继承
从原型链继承的代码来看,子类的prototype属性只能指向一个父类的实例,因此只能实现单继承。
父类引用属性是共享的
父类的值类型属性在生成的每个子实例中是独有的,而对应的引用类型属性则是每个实例共享的,这个问题对于原型链继承的影响是致命的。
引用类型属性共享问题
通过call方法调用父类的构造方法,并通过this改变构造方法的指向,this就指向了cat了。
var obj1={
name:"java"
}
window.name="javascript";
var func=function(){
console.log(this.name);
}
func(); //javasript
func.call(obj1); //java
name属性的修改,两者子类型实例name属性是不同的;而对于features属性的修改,两者features属性的值是相同的
create()实现继承
create的第二参数是一个对象,其中的属性如果和person重名,则会覆盖person的属性。
var person={
name:"Tom",
age:23,
job:"厨师"
};
var anotherPerson=Object.create(person,{
name:{
value:"Mike"
}
});
alert(anotherPerson.name);
apply()实现属性和方法继承全部继承
apply:调用一个对象的一个方法,用另一个对象替换当前对象。例如:B.apply(A, arguments);即A对象应用B对象的方法。
apply(thisArg [,argArray] ); // 参数数组,argArray
只接收两个参数,其中第二个参数必须是一个数组或者类数组
作用都是将函数绑定到另外一个对象上去运行,内部的this指针,都会被赋值为thisArg,这可实现将函数作为另外一个对象的方法运行的目的
function add(a,b){
return a+b;
}
function sub(a,b){
return a-b;
}
var a1 = add.apply(sub,[4,2]); //sub调用add的方法
var a2 = sub.apply(add,[4,2]);
alert(a1); //6
alert(a2); //2
/*call的用法*/
var a1 = add.call(sub,4,2);
apply : obj1.fun.apply(obj2,[参数1,参数2....]) 让对象1的方法冒充成对象2的方法。
function person (name) {
this.name=name;//this代表window this那个对象引用,就是那个对象的函数function person()
this.say=function () {
alert(this.name)
}
}
function student () {
window.person.cell(this)//this代表zhangsan
}
var zhangsan=new student ();
zhangsan.name;//张三
function student () {
window.person.apply(this,["zhangsan"])//参数以数组形式传递
}
var zhangsan=new student ();
zhangsan.name;
zhangsan.say();
js实现多态
<script type="text/javascript">
function Animal(name,age){
this.name=name;
this.age=age;
this.shout=function(){
alert("我是:"+this.name+",今年:"+this.age);
};
this.action=function(){
alert("会吃");
};
}
function Dog(name,age){
Animal.apply(this, [name,age]);
}
var jack=new Dog("jack",1);
alert(jack.name);
alert(jack.age);
jack.shout();
jack.action();
</script>
构造函数call()
call:调用一个对象的一个方法,用另一个对象替换当前对象。例如:B.call(A, args1,args2);即A对象调用B对象的方法。
function.call(obj[,arg1[, arg2[, [,.argN]]]]])
- 调用
call
的对象必须是个函数function -
call
的第一个参数将会是function改变上下文后指向的对象,如果不传,将会默认是全局对象window
- 第二个参数开始可以接收任意个参数,这些参数将会作为function的参数传入function
- 调用
call
的方法会立即执行
call : obj1.fun.call(obj2,参数1......).让对象1的方法冒充成对象2的方法。
function person () {
this.name="张三";
this.say=function () {
alert(this.name)
}
}
function student () {
this.name="李四";
}
var ren=new person ();
var zhangsan=new student ();//也有了say方法
ren.say.call(zhangsan)//李四
call的一个作用是可以改变函数运行的作用域
把Person的方法放到Student上执行,原来Student是没有say方法,现在是把Person的say方法放到student上来执行,所以this就指向了student对象
构造函数也可以通过子对象向父对象传递参数
function SuperType(name){
this.name=name
}
function SubType(){
SuperType.call(this,"Tom")//或者apply()
}
var instance1=new SubType();
alert(instance1.name);
由于可以改变this
的指向,所以也就可以实现对象的继承
function superClass () {
this.a = 1;
this.print = function () {
console.log(this.a);
}
}
function subClass () {
superClass.call(this);
this.print();
}
subClass();
// 1
subClass
通过call
方法,继承了superClass
的print
方法和a
变量,同时subClass
还可以扩展自己的其他方法
的意思就是使用superClass对象代替this对象,那么subClass中不就有superClass的所有属性和方法了吗,subClass对象就能够直接调用superClass的方法以及属性了
异同
相同点
都能够改变方法的执行上下文(执行环境),将一个对象的方法交给另一个对象来执行,并且是立即执行.
一般来说,this总是指向调用某个方法的对象,但是使用call()和apply()方法时,就会改变this的指向。
var Pet = {
words : '...',
speak : function (say) {
console.log(say + ''+ this.words)
}
}
Pet.speak('Speak'); // 结果:Speak...
var Dog = {
words:'Wang'
}
//将this的指向改变成了Dog
Pet.speak.call(Dog, 'Speak'); //结果: SpeakWang
---------------------
function Pet(words){
this.words = words;
this.speak = function () {
console.log( this.words)
}
}
function Dog(words){
//Pet.call(this, words); //结果: Wang
Pet.apply(this, arguments); //结果: Wang
}
var dog = new Dog('Wang');
dog.speak();
---------------------
不同点
call
方法从第二个参数开始可以接收任意个参数,每个参数会映射到相应位置的func的参数上,可以通过参数名调用,但是如果将所有的参数作为数组传入,它们会作为一个整体映射到func对应的第一个参数上,之后参数都为空
function func (a,b,c) {}
func.call(obj, 1,2,3)
// function接收到的参数实际上是 1,2,3
func.call(obj, [1,2,3])
// function接收到的参数实际上是 [1,2,3],undefined,undefined
apply
方法最多只有两个参数,第二个参数接收数组或者类数组,但是都会被转换成类数组传入func中,并且会被映射到func对应的参数上
func.apply(obj, [1,2,3])
// function接收到的参数实际上是 1,2,3
func.apply(obj, {
0: 1,
1: 2,
2: 3,
length: 3
})
// function接收到的参数实际上是 1,2,3
两个方法该如何选择?
跟简单,根据你要传入的参数来做选择,不需要传参或者只有1个参数的时候,用call
,当要传入多个对象时,用apply
或者,如果需要传入的参数已经是一个数组或者类数组了,就用apply
,如果还是单独的需要逐个传入的,可以考虑使用call
(如果你不嫌麻烦的话 )
标签:jquery,function,name,继承,源码,call,apply,参数,方法 From: https://blog.51cto.com/u_11837698/6081930