一、JS中this的四种使用情况
在函数执行时,this总是指向调用该函数的对象;判断this的指向,即判断this所在的函数属于谁
1.当函数有所属对象时,指向所属对象:
例如 var object=document.getElementById("object");
object.onclick=function(){
console.log(this); //这里this指向object 事件执行对象
}
2.当函数没有所属对象:指向window
例如 function fn(){
console.log(this.value); //未定义undefined
console.log(this); //输出window
}
fn();
与直接在<script></script>内写console.log(this)都会输出window;
3.构造函数中的this:指向新对象
Js中通过new关键字调用构造函数,this会绑定在该新对象上;
例如
function animal(){
this.value=100; //this代表当前实例化的对象 cat
}
var cat=new animal();//实例化一个对象 实例化即new...
console.log(cat.value); //100
var fn=function(){
this.value=100;
}
var fun=new fn();
console.log(fun.value); //100
4.apply和call调用以及bind绑定:指向绑定的对象
apply()方法:两个参数 函数运行作用域 参数数组
call()方法:两个参数 函数运行作用域 参数列举
二者用法一致都是替换对象, 不同的是第二个参数apply需传递array形式的数组给它,二者可以互相转换,call方法更接近一般调用函数;
bind()方法会返回一个新方法,新方法的this会绑定传入对象;
例如
var object={value:1};
var fn=function(){
console.log(this);//this指fn
};
fn(); //window
fn.apply(object);//object={value:1}
fn.call(object); //object={value:1}
//apply()与call()都是将object对象复制到fn()中
var newfn=fn.bind(object);
console.log(newfn);//输出函数
newfn();//object={value:1}
//bind返回的是新方法 调用需要添加()
二、JS几种继承 继承简单来说即子类继承父类的方法/属性
添加类的方法有两种方法:实例方法 原型方法
首先定义一个父类:
function animal(name){
//添加类的属性
this.name=name;
this.sex=”公”;
//添加类的方法一 实例方法
this.eat=function(){
Return this.name+”正在吃饭”;
}
}
//添加类的方法二 原型方法
animal.prototype.snidelcolor=function(){
return this.name+”的毛色是白色”;
}
1.原型链继承:将父类的实例作为子类的原型
优点:纯粹的继承关系,实例是子类的实例,也是父类的实例,父类新增原型方法、属性,子类都可以调用(访问);
缺点:为子类新增属性和方法,需在实例化(new 方法()语句)之后执行,不能放到构造器中无法实现继承;?
创建子类实例时,无法向父类构造函数传参;
例如
//创建一个子类
function cat(){
this.weight="20kg";
this.sleep=function(){
return this.name+"正在睡觉";
}
}
//原型继承 cat继承animal方法属性
cat.prototype=new animal("猫");
//子类新增属性和方法需在实例化之后
cat.prototype.type=function(){
return this.name+"是猫科动物";
};
var Cat=new cat();
//访问继承的父类的属性 方法
console.log(Cat.name);
console.log(Cat.sex);
console.log(Cat.eat());
console.log(Cat.snidelcolor());
//访问子类本身的属性 方法
console.log(Cat.type());
console.log(Cat.sleep());
console.log(Cat.weight);
//验证 实例是子类的实例,也是父类的实例
console.log(Cat instanceof animal); //true
console.log(Cat instanceof cat); //true
2.构造继承:在子类构造函数内部调用父类,通过使用call()和apply()方法在新创建的对象上执行构造函数;即可以理解为使用父类的构造函数增强子类实例,复制父类的实例属性方法给子类(未用到原型)
优点:创建子类实例时,可向父类传递参数,可实现多继承(call多个父类对象)
缺点:实例只是子类的实例,不是父类的实例;只能继承父类的实例属性和方法,不能继承原型方法的属性/方法;无法实现函数复用,每个子类都有父类实例函数的副本,影响性能;
例如
//创建子类
function dog(name){
animal.call(this);//复制父类属性给子类
this.name=name;
}
var Dog=new dog("狗");
//访问继承的父类的属性和方法
console.log(Dog.eat());
console.log(Dog.name);
console.log(Dog.sex);
/* console.log(Dog.snidelcolor());//报错 构造函数无法调用到原型方法*/
//构造函数只能继承父类的实例属性和方法,不能继承原型属性/方法
//实例只是子类的实例,不是父类的实例
console.log(Dog instanceof dog); //true
console.log(Dog instanceof animal);//false
3.实例继承:
优点:不限制调用方式,不管是new子类()还是子类(),返回的对象都具有相同的效果
缺点:实例是父类的实例,不是子类的实例;
例如
function cat(name){
var newcat=new animal();//子类中实例化父类
newcat.name=name;
Return newcat;
}
var Cat=new cat("tom");//实例化 子类
console.log(Cat.name);//tom name实参传给子类输出 父类undefinded
console.log(Cat.sex);//
console.log(Cat.eat());
console.log(Cat.snidelcolor());
console.log(Cat instanceof cat); //false
console.log(Cat instanceof animal);//true
//实例继承中 实例只是父类的实例不是子类的实例
4.组合继承:将原型链和构造继承组合一起,弥补构造继承不能访问原型方法的缺点;
实例即使子类的实例也是父类的实例;
缺点:生成两个实例,消耗内存;
例如
function dog(name){
animal.call(this);//构造继承
this.name=name;
}
dog.prototype=new animal();//原型链继承
var Dog=new dog("tom");//实例化子类 传参只能传给子类
console.log(Dog.name);
console.log(Dog.sex);
console.log(Dog.eat());
console.log(Dog.snidelcolor());
console.log(Dog instanceof animal);//true
console.log(Dog instanceof dog);//true
5.原型式继承:通过原型可基于已有对象创建新对象,同时 还不必须因此创建自定义的类型;
例如
var cat={
name:"tom",friend:["jery"]
};
var anothercat=Object(cat);//原型式继承
anothercat.name="john";
anothercat.friend.push("Bob");
console.log(cat.friend);// ["jery", "Bob"]
ECMscript5通过新增Object.create()方法规范了原型式继承,两个参数 用作新对象原型的对象和作为新对象定义额外属性的对象;
例如
var cat={
name:"tom",friend:["jery"]
};
var anothercat=Object.create(cat);//原型式继承
anothercat.name="john";
anothercat.friend.push("Bob");
console.log(cat.friend);// ["jery", "Bob"]
6.寄生式继承:创建一个仅用于封装继承过程的函数,该函数内部以某种方法增强对象,最后返回对象;
例如
function creat(res) {
var a=Object(res);
a.say = function () { //构造方法
alert("hi");
};
return a;
}
var cat={
name:"tom",friend:["jery"]
};
var anthor=creat(cat);//将cat对象作为参数传递给create()
anthor.say();//弹出hi
7.寄生组合式继承:组合式指构造函数属性的继承和建立子类和父类原型的链接两部分。
通过借用构造函数来继承属性;通过原型链来继承方法。
实例即使子类的实例 也是父类的实例;
constructor 属性返回对创建此对象的数组函数的引用;
语法:object.constructor
例如
function addPrototype(son, father){
var protoType = Object.create(father.prototype); //创建对象
//Object.create()方法参数 用作新对象原型的对象
protoType.constructor = son; //增强对象
//constructor 属性返回对创建此对象的数组函数的引用;
son.prototype = protoType; //指定对象
}
/*定义一个父类*/
function father(name){
this.name = name;
this.colors = ["red", "blue", "green"];
}
father.prototype.sayName = function(){ //父类添加原型方法
return this.name;
};
/*定义一个子类*/
function son(name, age){
father.call(this, name); //构造继承
this.age = age;
}
addPrototype( son, father); //调用addPrototype函数
son.prototype.sayAge = function(){ //添加子类原型方法
return this.age;
};
var newson = new son("Bob", 18); //实例化子类
console.log( newson.sayName());
console.log( newson.sayAge());
console.log(newson instanceof son); //true
console.log(newson instanceof father);//true