一、 题目
- 如何准确判断一个变量是数组类型
- 写一个原型链继承的例子
- 描述new一个对象的过程
二、知识点
1.构造函数
function Foo(name, age){
this.name = name
this.age = age
this.class = 'class-1'
// return this //默认有这一行
}
var f = new Foo('zhangsan', '20')
//var f1 = new Foo('lisi', 22) //可创建多个对象
特点:默认函数首字母大写,构造函数并没有显示返回任何东西。new 操作符会自动创建给定的类型并返回他们,当调用构造函数时,new会自动创建this对象,且类型就是构造函数类型。
2.构造函数—扩展
var a = {} 其实是 var a = new Object()的语法糖
var a = [] 其实是 var a = new Array()的语法糖
function Foo(){…} 其实是 var Foo = new Function(){…}
使用instanceof判断一个函数是否是构造函数
3.原型规则和示例
原型规则是原型链的基础
- 所有引用类型(数组、对象、函数),都具有对象特性,即可自由扩展属性(除‘null’以外)
- 所有引用类型(数组、对象、函数),都具一个_proto_ (隐式原型)属性,属性值是一个普通对象
- 所有函数,都有一个prototype(显式原型)属性,属性值也是一个普通对象
- 所有引用类型(数组、对象、函数),_proto_ (隐式原型)属性值指向它的构造函数的prototype(显式原型)属性值
- 当试图得到一个对象的某个属性时,如果这个对象本身没有这个属性,那么会去它的_proto_ (即它的构造函数的prototype)中寻找
var obj = {}; obj.a = 100;
var arr = []; arr.a = 100;
function fn(){}
fn.a = 100; // 所有引用类型都能拓展属性
console.log(obj.__proto__)
console.log(arr.__proto__)
console.log(fn.__proto__) //所有引用类型都有_proto_(隐式原型)属性
console.log(fn.prototype) //所有函数,都有一个prototype(显式原型)属性
console.log(obj.__proto__ === Object.prototype)// true 引用类型_proto_(隐式原型)属性值指向它的构造函数的prototype(显式原型)属性值
//当试图得到一个对象的某个属性时,如果这个对象本身没有这个属性,那么会去它的*_proto_* (即它的构造函数的prototype)中寻找
//构造函数
function Foo(name, age){
this.name = name;
}
Foo.prototype.alertName = function(){
alert(this.name)
}
//创建实例
var f = new Foo('zhangsan');
f.printName = function(){
console.log(this.name);
}
//测试
f.printName(); //f自身有printName这个属性,所以直接可以调用
f.alertName(); //f自身没有alertName这个属性,所以会去它的_proto_(即它的构造函数的prototype)中寻找
tips:循环对象自身的属性时,建议加上hasOwnProperty来保证程序的健壮性
var item;
for(item in f){
//高级浏览器已经在for in 中屏蔽了来自原型的属性
//但是这里建议大家还是加上这个判断,保证程序的健壮性
if(f.hasOwnProperty(item)){
console.log(item)
}
}
4.原型链
还是采用上面构造函数的例子来解释原型链
//构造函数
function Foo(name, age){
this.name = name;
}
Foo.prototype.alertName = function(){
alert(this.name)
}
//创建实例
var f = new Foo('zhangsan');
f.printName = function(){
console.log(this.name);
}
//测试
f.toString(); //要去f._proto_._proto_中查找
/*
f自身没有toString这个属性, 那么f会去它的隐式原型_proto_(即它的构造函数的prototype)中寻找,而f的构 造函数也没有toString这个属性,那该往哪里找?
原型规则中第二、三条提到:所有引用类型(数组、对象、函数),都具一个_proto_(隐式原型)属性,属性值是一个普通对象,意思f._proto_(f.prototype)是个对象
f._proto_是个对象,那么该往f._proto_隐式原型中寻找,即f._proto_._proto_ (f._proto_寻找其对象的构造函数也就是Object)
* */
5.instanceof
用于判断引用类型属于哪个构造函数的方法
f instanceof Foo的判断逻辑:
f的proto一层一层往上,能否找到Foo.prototype
再试着判断f instanceof Object
三、解答
1.如何准确判断一个变量是数组类型
var arr = []
arr instanceof Array //true
typeof arr // Object typeof是无法判断是否是数组的
2.写一个原型链继承的例子
//写一个封装DOM的例子
function Elem(id){
this.elem = document.getElementById(id);
}
Elem.prototype.html = function (val) {
var elem = this.elem;
if(val){
elem.innerHTML = val;
return this; //链式操作, 可有可无
}else{
return elem.innerHTML;
}
}
Elem.prototype.on = function(type, fn){
var elem = this.elem;
elem.addEventListener(type, fn);
return this;
}
var div1 = new Elem('div1');
//console.log(div1.html())
div1.html('<p>hello world<p>').on('click', function(){
alert('clicked');
}).html('<p>javascript<p>')
3.描述new一个对象的过程
- 创建空对象;
var obj = {}; 设置新对象的constructor属性为构造函数的名称,设置新对象的_proto_属性指向构造函数的prototype对象;
obj._proto_ = ClassA.prototype;使用新对象调用函数,函数中的this被指向新实例对象:
ClassA.call(obj); //{}.构造函数();将初始化完毕的新对象地址,保存到等号左边的变量中
tips:若构造函数中返回this或返回值是基本类型(number、string、boolean、null、undefined)的值,则返回新实例对象;若返回值是引用类型的值,则实际返回值为这个引用类型。