参考学习:https://www.cnblogs.com/lisha-better/p/5684844.html
1.普通函数调用(window)
2.作为构造函数调用()
3.作为方法调用
4.使用call/apply/bind调用
5.ES6箭头函数调用(this取决于包裹箭头函数的第一个普通函数)
**setTimeout()由window对象调用
call()参数为空,this指向window
匿名函数,this也指向window
在事件中,this指向触发这个事件的对象,特殊的是,IE中的attachEvent中的this总是指向全局对象Window
参考学习:https://www.cnblogs.com/chenwenhao/p/6980401.html
https://www.imooc.com/article/20162
https://www.cnblogs.com/humin/p/4556820.html
关于Function和Object创建实例之间的关系
基于原型链继承的链图,对继承有个具体化的概念: (这个是核心继承部分)
上图整体的继承链
js继承:
1.原型链继承
特点;
1.要想为子类新增属性和方法,必须要在new Animal()这样的语句之后执行,不能放到构造器中
2.无法实现多继承
3.来自原型对象的所有属性被所有实例共享
4.创建子类实例时,无法向父类构造函数传参
function SuperType () {
this.property = true;
}
SuperType.prototype.getSuperValue = function() {
return this.property;
};
function SubType() {
this.subproperty = false;
}
//继承SuperType
**SubType.prototype = new SuperType();**
SubType.prototype.getSubValue = function() {
return this.subproperty;
}
var instance =new SubType();
console.log(instance.getSuperValue()); // true
存在问题:
1.包含引用类型值的原型属性会被所有实例共享(修改),而在构造函数中的基本类型和引用类型属性均不可改变(const附体)
2.创建子类型的实例时,不能向超类的构造函数中传递传递参数
3.无法实现多继承
2.构造函数继承(在子类型构造函数的内部调用超类型)
子类型构造函数中向超类型构造函数传参
问题:函数无法复用
function SuperType() {
this.colors = ["red","blue","green"];
}
function SubType() {
//继承了SuperType --重新创建SuperType构造函数属性的副本
SuperType.call(this);
}
var instance1 = newe SubType();
instance1.colors.push("black");
console.log(instance1.colors); //"red,blue,green,black"
var instances2 = new SubType();
console.log(instance2.colors); //"red,blue,green" --完美实现了继承构造函数属性
3.组合继承(避免了原型链和构造函数继承的缺陷)
弥补了方式2的缺陷,可以继承实例属性/方法,也可以继承原型属性/方法
既是子类的实例,也是父类的实例
不存在引用属性共享问题
可传参
函数可复用
缺点:
调用了两次父类构造函数,生成了两份实例(子类实例将子类原型上的那份屏蔽了)
function SuperType(name) {
this.name = name;
this.colors = ["red","blue","green"];
}
SuperType.prototype.sayName = function() {
console.log(this.name);
};
function SubType(name,age){
//继承属性 --重新创建SuperType构造函数属性的副本
SuperType.call(this,name);
this.age = age;
}
//继承方法
SubType.prototype = new SuperType();
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function() {
console.log(this.age);
};
var instance1 =new SubType("Nicholas",29);
instance1.colors.push("black");
console.log(instance1.colors); // "red,blue,green,black"
instance1.sayName(); // "Nicholas"
instance1.sayAge(); // 29
var instance2 = new SubType("Greg",22);
console.log(instance2.colors); // "red,blue,green"
instance2.sayName(); // "Greg"
instance2.sayAge(); // 22
4.实例继承
特点:
不限制调用方式,不管是new 子类()还是子类(),返回的对象具有相同的效果
缺点:
实例是父类的实例,不是子类的实例
不支持多继承
// 定义一个动物类
function Animal (name) {
// 属性
this.name = name || 'Animal';
// 实例方法
this.sleep = function(){
console.log(this.name + '正在睡觉!');
}
}
// 原型方法
Animal.prototype.eat = function(food) {
console.log(this.name + '正在吃:' + food);
};
function Cat(name){
var instance = new Animal();
instance.name = name || 'Tom';
return instance;
}
// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); // false
5.拷贝继承
特点:
支持多继承
缺点:
效率较低,内存占用高(因为要拷贝父类的属性)
无法获取父类不可枚举的方法(不可枚举方法,不能使用for in 访问到)
function Cat(name){
var animal = new Animal();
for(var p in animal){
Cat.prototype[p] = animal[p];
}
Cat.prototype.name = name || 'Tom';
}
// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // false
console.log(cat instanceof Cat); // true
6.寄生组合继承
function Cat(name){
Animal.call(this);
this.name = name || 'Tom';
}
(function(){
// 创建一个没有实例方法的类
var Super = function(){};
Super.prototype = Animal.prototype;
//将实例作为子类的原型
Cat.prototype = new Super();
})();
// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); //true