# JS面试题(二)

# 一、原型原型链

(1) 每个函数|构造函数都有一个原型prototype,用来存储公有的属性和方法

(2) 每个原型对象都有一个constructor属性,指向函数本身

(3) 每个实例都有__ proto __ 隐式指向所在类的原型

原型链的机制是:当成员访问的时候,首先查找自身的私有属性,如果没有会隐式查找所在模块原型上的属性和方法,再查不到会一直通过__ proto __ 向上查找,一直找到Object.prototype 为止。最终原型链指向null结束,这种机制称为原型链机制

1、下面代码运行的结果

function fun(){
    this.a=0;
    this.b=function(){
        alert(this.a);
    }
}
fun.prototype={
    b:function(){
        this.a=20;
        alert(this.a);
    },
    c:function(){
        this.a=30;
        alert(this.a)
    }
}
var my_fun=new fun();  
my_fun.b();
my_fun.c();

结果:

"0" "30"

分析:

var my_fun=new fun(); => { a:0 , b: function(){ alert(this.a)}}

my_fun.b(); => 此时 this=> my_fun , 所以结果为"0"

my_fun.c(); => 此时my_fun中没有c这个属性,去原型中查找,打印结果为“30”

2、写出下面代码执行输出的结果

function C1(name) {
    if (name) {
        this.name = name;
    }
}
function C2(name) {
    this.name = name;
}
function C3(name) {
    this.name = name || 'join';
}
C1.prototype.name = 'Tom';
C2.prototype.name = 'Tom';
C3.prototype.name = 'Tom';
alert((new C1().name) + (new C2().name) + (new C3().name));

结果:

"Tomundefinedjoin"

分析:

考察原型原型链构造函数,函数实例化,参数不传为undefined

new C1().name => 因为name为undefined,所以当前函数内没有name属性,只能去原型对象去找所以结果为"Tom"

new C2().name => 因为name为undefined,所以当前函数内拥有私有属性name为 undefined,结果为undefined

new C3().name => 因为name为undefined,所以当前函数内拥有私有属性name为 "join",结果为'join'

综上,结果为 alert("Tom" + undefined + 'join') => "Tomundefinedjoin"

3、下面代码运行的结果?

function Fn() {
    let a = 1;
    this.a = a;
}
Fn.prototype.say = function () {
    this.a = 2;
}
Fn.prototype = new Fn;

let f1 = new Fn;
Fn.prototype.b = function () {
    this.a = 3;
};

console.log(f1.a);
console.log(f1.prototype);  // ?
console.log(f1.b);
console.log(f1.hasOwnProperty('b'));
console.log('b' in f1);
console.log(f1.constructor == Fn);

结果:

分析:

f1 => {a: 1 , __ proto __ : {

a =1,

b:function(){ this.a = 3;},

__ proto __ :

​ say: func(){this.a = 2;}

}

console.log(f1.a); => 1

console.log(f1.prototype); => {a:1,b:function(){this.a},__ proto __: {say:func(){...}} }

console.log(f1.b); => function(){ this.a =3 }

console.log(f1.hasOwnProperty('b')); => false

console.log('b' in f1); => true

console.log(f1.constructor == Fn); => true

4、写出下面代码执行输出的结果

function Foo() {
    getName = function () {
        console.log(1);
    };
    return this;
}
Foo.getName = function () {
    console.log(2);
};
Foo.prototype.getName = function () {
    console.log(3);
};
var getName = function () {
    console.log(4);
};
function getName() {
    console.log(5);
}
Foo.getName();
getName();
Foo().getName();
getName();
new Foo.getName();
new Foo().getName();
new new Foo().getName();

结果为:

2 4 1 1 2 3 3 Foo.getName {}

分析:

考察原型链、变量提升

词法解析阶段,var getName 和 函数getName变量提升

1、

2、getName();

3、Foo().getName();

4、getName();

5、new Foo.getName();

6、new Foo().getName();

7、new new Foo().getName();

5、完成如下的需求

let n = 10;
let m = n.plus(10).minus(5);
console.log(m);
//=>15(10+10-5)

分析:

给数字Number这个类添加原型方法

Number.prototype.plus = function(n){return this+n}

Number.prototype.minus = function(n){return this-n}

6、实现如下需求

/*
 * 编写queryURLParams方法实现如下的效果(至少两种方案)
 */
let url="http://www.zhufengpeixun.cn/?lx=1&from=wx#video";
console.log(url.queryURLParams("from")); //=>"wx"
console.log(url.queryURLParams("_HASH")); //=>"video"

分析:

String.prototype. queryURLParams=function(params){
    if(params==='_HASH'){
      return this.slice(this.match(/#/)[1])
    }else{
       return this.slice(this.match(/params/)[1])
    }
}

7、基于ES6中的class重构下面的代码

function Modal(x,y){
    this.x=x;
    this.y=y;
}
Modal.prototype.z=10;
Modal.prototype.getX=function(){
    console.log(this.x);
}
Modal.prototype.getY=function(){
    console.log(this.y);
}
Modal.n=200;
Modal.setNumber=function(n){
    this.n=n;
};
let m = new Modal(10,20);
// 重构
class Parent {
  constructor() {
    this.z = 10;
    this.getX = function () {
      console.log(x);
    };
    this.getY = function () {
      console.log(y);
    };
  }
}

class Modal extends Parent{
  constructor(x, y) {
    super();
    this.x = x;
    this.y = y;
  }
  static n = 200;
  static setNumber = function (n) {
    this.n = n;
  };
}
let m = new Modal(10, 20);
console.log(m);

8、代码输出的结果

let obj = {
    2: 3,
    3: 4,
    length: 2,
    push: Array.prototype.push
}
obj.push(1);
obj.push(2);
console.log(obj);

分析: ?

obj ={
    2: 3,
    3: 4,
    length: 4,
    push: Array.prototype.push
}

9、a等于什么值会让下面条件成立

var a = ?;
if (a == 1 && a == 2 && a == 3) {
 console.log('OK');
}

分析: ?

var a = Object.defineProperty({}, 'a',{
     value: ++a || 1
}).a

10、实现如下需求

let utils = (function(){
    /*
     * toArray:转换为数组的方法
     *   @params
     *      不固定数量,不固定类型
     *   @return
     *      [Array] 返回的处理后的新数组
     * by zhufengpeixun on 2020
     */
    function toArray(){
        //=>实现你的代码(多种办法实现)   
    }

    return {
        toArray
    };
})();
let ary = utils.toArray(10,20,30); //=>[10,20,30]
ary = utils.toArray('A',10,20,30); //=>['A',10,20,30]

分析:


11、对象(数组)的深克隆和浅克隆(头条)

//=>浅克隆:只复制对象或者数组的第一级内容
//=>深克隆:克隆后数组的每一级都和原始数组没有关联
//那么请说出,浅克隆都怎么去实现,如何实现深度克隆
let obj = {
    a: 100,
    b: [10, 20, 30],
    c: {
        x: 10
    },
    d: /^\d+$/
};

let arr = [10, [100, 200], {
    x: 10,
    y: 20
}];

分析:


12、已知基于 instanceof 可以实现检测:实例是否属于某个类,现在需要自己编写这样的一个方法,实现出 instanceof 的效果

//=>example:要检测的实例
//=>classFunc:要检测的类
function instance_of(example, classFunc) {
    //...
}
let res = instance_of([12,23],Array);
console.log(res); //=>true

分析:


# 二、附加题(偏难)

1、实现如下需求

//=>编写toType方法,实现数据类型检测
function toType( obj ) {
   //完成你的代码
}
console.log(toType(1)); //=>"number"
console.log(toType(NaN)); //=>"number"
console.log(toType([])); //=>"array"
console.log(toType(/^\d+$/)); //=>"regexp"
console.log(toType({})); //=>"object"
...

2、 完成如下需求

~function(){
    function change(){
        //=>实现你的代码
    };
    Function.prototype.change=change;
}();
let obj = {name:'zhufeng'};
function func(x,y){
    this.total=x+y;
    return this;
}
let res = func.change(obj,100,200);
//res => {name:'Alibaba',total:300}

分析

3、完成如下需求

~function(){
    //=>bind方法在IE6~8中不兼容,接下来我们自己基于原生JS实现这个方法
    function bind(){

    };
    Function.prototype.bind=bind;
}();
var obj = {name:'zhufeng'};
function func(){
    console.log(this,arguments);
    //=>当点击BODY的时候,执行func方法,输出:obj [100,200,MouseEvent事件对象]
}
document.body.onclick = func.bind(obj,100,200);

结果 :

4、下面代码的输出结果?为什么?

var name = '珠峰培训';
function A(x,y){
    var res=x+y;
    console.log(res,this.name);
}
function B(x,y){
    var res=x-y;
    console.log(res,this.name);
}
B.call(A,40,30);
B.call.call.call(A,20,10);
Function.prototype.call(A,60,50);
Function.prototype.call.call.call(A,80,70);