构造函数的继承
1. 包装对象
非空对象可以添加属性或者方法
var arr = [];
arr.a = 10;
alert(arr.a);
但是基本数据类型也有自身的方法和属性,这些属性是如何调用的呢?
var str = "abc";
str.charAt(1);
当尝试去调用简单类型的属性或者方法的时候,这个数据类型会找到自身的构造函数身上的属性或者方法,返回查找的属性或方法之后,构造函数自动销毁。这个过程叫做包装对象。
那么上面的字符串调用方法的过程就是这样:
var str = "abc";
str.charAt(1);
str -> str的构造函数 String -> 找到charAt方法并调用 ->销毁这个new String
2.hasOwnProperty
作用:
判断参数是否为自身的私有属性
语法:
obj/fn.hasOwnProperty(属性名);
返回值为Boolean
如果是调用者自身的私有属性,返回true
,否则返回false
注意,判断的参数只能是调用者 自身 的私有属性,如果是它的原型或者原型链上的属性也会返回false
function fn1(name){
this.name = name;
}
fn1.prototype.age = function(){
console.log(1);
}
var f1 = new fn1('cat');
console.log(fn1.hasOwnProperty('name')); //true
console.log(fn1.hasOwnProperty('age')); //false
console.log(fn1.prototype.hasOwnProperty('age')) //true
3.constructor
作用:
查看某个对象的构造函数是谁
当一个对象实例化之后,浏览器会为它自动加上这个属性。constructor
很容易被修改。当构造函数的原型赋值对象的时候,那么constructor
就被修改了,指向Object
这个方法可以手动修正constructor
指向(指向正确的构造函数的名称)。
4. instanceof
作用:
这是一个二元运算符
可以用来判断左边的实例化对象是不是右边的构造函数构造出来的
语法:
t2 instanceof t1
t2:实例化对象
t1:构造函数
返回值:
返回一个Boolean,如果t2是t1构造出来的,返回true
,否则返回false
5. call,apply
这两个方法都是改变函数中this的指向
语法:
函数名.call(this指向的对象,函数的参数1,函数的参数2,···函数的参数n);
函数名.apply(this指向的对象,[函数的参数1,函数的参数2,···,函数的参数n])
call
方法有无限个参数,其中第一个参数是想要个改变的this指向,剩下的参数是函数的实参
apply
方法有2个参数,其中给第一个参数是想要改变的那个this指向,第二个参数是一个数组,数组中的每一项数据都是函数的实参
function fn1(a,b){
alert(a+b);
alert(this);
}
fn1.call(document,2,3);
fn1.apply(document,[1,2]);
6.继承
6.1 拷贝继承
原理:
属性继承 + 方法继承
如果有一个构造函数init,这个时候需要继承这个init
那么可以创建一个构造函数init2,调用init,修改init2的this
指向,这样就可以完成属性继承(使用call
或者apply
方法)、
那么接下来我们要完成的是方法继承
如果直接让
init2.prototype = init.prototype;
由于构造函数的原型是是一个对象,是引用类型数据。由JS的数据类型的存放我们可以知道,如果这样写,只是把init的prototype
的地址指向复制给了init2的prototype
,这样如果对init2的prototype
进行修改的话,init的prototype
也会同步进行修改。因为他们指向的是同一个对象。
所以我们需要使用for··in对init的prototypr
进行遍历,逐一取出它的方法赋值给init2的prototype
,这样就可以是两个prototype
指向不同的对象,两个原型互不干涉。这样就完成了一次拷贝继承。
function Init(){
this.name = "a";
}
Init.prototype.a = function(){
console.log("这是原型a");
};
//拷贝继承
function Init2(){
Init.call(this);
}
for(var attr in Init.prototype){
Init2.prototype[attr] = Init.prototype[attr];
}
Init2.prototype.b = function(){
console.log("这回是init2的原型B,Init1没有");
};
var in1 = new Init();
var in2 = new Init2();
in2.a();
in2.b();
in1.b(); //这个会报错
6.2 类式继承
原理:
原型链的查找
现在我们有一个构造函数
function Init(){
this.name = "init1";
}
Init.prototype.a = function(){
console.log("这里是init的a方法");
}
如果我们想要继承这个构造函数Init的属性,同时不能使用拷贝继承,那么我们可以使用下面这种方法:
首先创建好这个init2
function Init2(){
//这里同样需要修改init2的this指向来继承init的属性
Init.call(this);
}
我们需要创建一个空的函数
function F(){};
然后修改这个函数的原型
F.prototyep = Init.prototype;
然后使用new生成这个F的实例化对象
var objF = new F();
最后,我们把这个实例化对象赋值给Init2
的prototype
,并且手动修正constructor
Init2.prototype = objF;
Init2.constructor = Init2;
//实例化对象,调用
Init2.prototype.b = function () {
console.log("this is Init2.b");
};
var in2 = new Init2();
var in1 = new Init();
in2.a();
in2.b();
in1.b(); //这个会报错
原理:
使用一个空的构造函数作为桥梁,然后把空的构造函数的实例化对象赋值给需要继承的构造函数,这样,当调用in2的a方法的时候,由于它本身没有a方法,通过__proto__
去向上找他的构造函数init2.prototype
,但是Init2.prototype = objF
这个实例化对象,那么会通过__proto__
去向上找他的构造函数F
和F
的prototype
,但是F.prototype = init.prototype
,这样就通过原型链找到了a方法。
in2.a -> objF ->objF.__protot__ -> F ->F.prototype ->init.prototype
这个时候,init.prototype和F.prototype指向同一个对象,init2的prototype和objF指向同一个对象。
6.3 对象继承
如果现在有一个对象obj1
var obj1 = {
"name":"momo",
"age":20,
"say":function(){
alert(1);
}
};
利用类式继承的原理,我们可以完美继承这个对象,方法如下
var obj2 = {};
function F(){};
F.prototype = obj1;
var objF = new F;
obj2 = objF;
这个时候调用obj2.say方法,可以alert(1);
给obj2添加新得key也不会影响到obj1
通过原型链的查找顺序为:
obj2.a -> objF ->objF.__proto__ ->F ->F.prototype ->obj1
7 toString
作用:把数据转成字符串。
每个数据类型自身都有toString
方法
只要使用alert
弹出引用类型的数据,那么就会调用toString
方法。
Array.prototype.toString = function () {
return 'aaa';
};
var arr = [1,2,3];
alert(arr);
但是弹出基本类型就不会调用toString
方法
如果为数字类型,那么在toString的括号中写进制,那么就会转成对应的进制结果。(转基数)
var num = 255;
var num2 = "11001000"; //200
console.log(num.toString(2)); //11111111
console.log(parseInt(num2,2)); //200
7.1 判断数据类型
1.typeof
typeof 数据
缺点是没办法判断数组的数据类型
2.instanceof
数据 instanceof 数据类型(构造函数)
3.constructor
数据.constructor
返回一个数据的构造函数,但是这个对于判断ifream中的内容有问题
4.Object.prototype.toString.call(数据)
Object.prototype.toString.call(数据)
这个方法会返回一个[object 数据构造函数];
精确返回,即使在ifream中的数据也没有问题
8.forEach
将一个类数组转换为数组
var boxs = document.querySelectorAll("div");
var boxarr = Array.prototype.slice.call(boxs);
//这样就可以使用forEach来循环类数组啦
boxarr.forEach(function(elem,i){
elem.onclick = function(){
alert(i);
}
});
问题:Object.prototype.toString和Array.prototype.slice这两个都是通过改变this的指向来实现效果,那么Array.prototype.slice的this原来是谁? 是它的实例化对象? 还是window?
上一篇: 构造函数的继承
下一篇: JS实现倒计时三秒钟跳转到新的页面