您的位置:首页 > 职场人生

JS面试题—原型和原型链

2017-08-08 17:19 309 查看
一、 题目

如何准确判断一个变量是数组类型

写一个原型链继承的例子

描述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)的值,则返回新实例对象;若返回值是引用类型的值,则实际返回值为这个引用类型。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  面试题