Front-end js classic interview questions

/**
 * 用js实现一个类P 包含成员变量a,成员变量b成员函数sum sum输出a与b的和,a,b默认值都为0.实现一个类M,M继承自P,在P的基础上增加成员变量c成员变量函数sum变成a,b,c的和
 */
function P(a,b){
    this.a = a || 0;
    this.b = b || 0;
}
P.prototype.sum = function(){
    return this.a + this.b;
};

function M(a,b,c){
    P.call(this,a,b);
    this.c = c || 0;
}

M.prototype = new P();
M.prototype.constructor = M;

M.prototype.sum = function(){
    return this.a + this.b + this.c;
};

var p = new P(1,2);
var m = new M(1,2,3);
console.log("p.sum()=",p.sum());
console.log("m.sum()=",m.sum());

/**
 * 写出三个不同的this使用场景
 */

// 0. 构造器函数内的this:
//如果函数创建的目的是使用new来调用,并产生一个对象,那么此函数被称为 构造器函数。
// var Niu = function (string) {
//
//     this.name = string;
// };
// 上述的Niu即为一个构造器函数,其内部的this会自动绑定到new所创建的新对象上面。
//
// 1. 对象成员方法内的this:
// 对象的成员方法中的this是对象本身,此时跟其它语言是一致的,但是也有差异,javascript中this到对象的绑定发生在函数调用的时候。
//
// var myObj = {
//
//     value: 0,
//
//     increment: function (inc) {
//
//         this.value += typeof inc === 'number' ? inc : 1;
//
//     }
//
// };
//
// myObj.increment();    //1
//
// myObj.increment(2);   //3

// 2. 普通函数 与 闭包内的this:
//
//     2.1 以普通方式定义的函数中的this:会被自动绑定到全局对象。
// var value = 232;
//
// function toStr()
//
// {
//
//     console.log("%d", this.value);  //232
//
// }
//
//
// 2.2 对象方法中闭包函数的this:
//
//     由2.1可知,在以普通方式定义的函数中的this会被自动绑定到全局对象上,大家应该可以看出闭包函数定义也与普通方式无异,因此他也会被绑定到全局对象上。
//
// value = 10;<br>var closureThis = {
//     value: 0,
//     acc: function ()
//     {
//         var helper = function ()
//         {
//             this.value += 2;
//             console.log("this.value : %d", this.value);
//         }
//         helper();
//     }
// };
//
// closureThis.acc();   //12
// closureThis.acc();   //14
//
// var closureThat = {
//     value: 0,
//     acc: function ()
//     {
//         that = this;
//         var helper = function ()
//         {
//             that.value += 2;
//             console.log("that.value : %d", that.value);
//         }
//         helper();
//     }
// };
//
// closureThat.acc(); // 2
// closureThat.acc(); // 4
// 从上述输出值可以看出,上述描述的正确性。
//
// 3. Apply函数的参数this:
//
// appy方法允许我们选择一个this值作为第一个参数传递,第二个参数是一个数组,表明可以传递多个参数。


//【场景1】全局环境中的this指向全局对象
// this.a = 10;
// alert(a);//10
// b = 20;
// alert(this.b);//20
// var c = 30;
// alert(this.c);//30
// 【场景2】对象内部函数的this指向调用函数的当前对象
// var a = 10;
// var bar = {
//     a: 20,
//     test: function(){
//         alert(this.a);
//     }
// }
// bar.test();//20
// 【场景3】全局环境函数的this指向全局对象
// var a = 10;
// function foo(){
//     alert(this.a);
// }
// foo();//10
// 【场景4】匿名函数中的this指向全局对象
// var a = 10;
// var foo = {
//     a: 20,
//     fn: (function(){
//         alert(this.a);
//     })()
// }
// foo.fn//10
// 【场景5】setInterval和setTimeout定时器中的this指向全局对象
// var a = 10;
// var oTimer1 = setInterval(function(){
//     var a = 20;
//     alert(this.a);//10
//     clearInterval(oTimer1);
// },100);
// 【场景6】eval中的this指向调用上下文中的this
// (function(){
//     eval("alert(this)");//[object Window]
// })();
// function Foo(){
//     this.bar = function(){
//         eval("alert(this)");//[object Object]
//     }
// }
// var foo = new Foo();
// foo.bar();
// 【场景7】构造函数中的this指向构造出的新对象
// function Person(name,age){
//     this.name = name;
//     this.age = age;
//     this.sayName = function(){
//         alert(this.name);
//     }
// }
// var p1 = new Person('lily','20');
// p1.sayName();//'lily'
// 【场景8】new Function中的this指向全局对象
// (function(){
//     var f = new Function("alert(this)");
//     f();//[object Window]
// })();
// function Foo(){
//     this.bar = function(){
//         var f = new Function("alert(this)");
//         f();//[object Window]
//     }
// }
// var foo = new Foo();
// foo.bar();
// 【场景9】apply和call中的this指向参数中的对象
// var a = 10;
// var foo = {
//     a: 20,
//     fn: function(){
//         alert(this.a);
//     }
// };
// var bar ={
//     a: 30
// }
// foo.fn.apply();//10(若参数为空,默认指向全局对象)
// foo.fn.apply(foo);//20
// foo.fn.apply(bar);//30
// 【复合场景1】
// var someone = {
//     name: "Bob",
//     showName: function(){
//         alert(this.name);
//     }
// };
// var other = {
//     name: "Tom",
//     showName: someone.showName
// }
// other.showName();  //Tom
//
// //以上函数相当于
//
// var other = {
//     name: "Tom",
//     showName: function(){
//         alert(this.name);
//     }
// }
// other.showName();  //Tom
// 【复合场景2】
// var name = 2;
// var a = {
//     name: 3,
//     fn: (function(){
//         alert(this.name);
//     })(),
//     fn1:function(){
//         alert(this.name);
//     }
// }
// a.fn;//2[匿名函数中的this指向全局对象]
// a.fn1();//3[对象内部函数的this指向调用函数的当前对象]
//
// 【复合场景3】
// var name = "Bob";
// var nameObj ={
//     name : "Tom",
//     showName : function(){
//         alert(this.name);
//     },
//     waitShowName : function(){
//         var that = this;
//         setTimeout(function(){
//             that.showName();
//         }, 1000);
//     }
// };
// nameObj.waitShowName();//"Tom"[that=this改变this的指向,使this从指向全局变量变化到指向nameObj]
//
// var name = "Bob";
// var nameObj ={
//     name : "Tom",
//     showName : function(){
//         alert(this.name);
//     },
//     waitShowName : function(){
//         var that = this;//that指向nameObj
//         setTimeout(function(){
//             (function(){
//                 alert(this.name);
//             })();
//         }, 1000);
//     }
// };
// nameObj.waitShowName();// 'Bob'[形成匿名函数,this指向全局变量]


/**
 * 写出下面这段代码的执行结果
 */
for(var i = 0 ; i < 3 ; i ++){
    setTimeout(function(){
        console.log(i);
    },0);
}

/**
 * 执行结果:
 * 3
 * 3
 * 3
 * 原因:js是单程的,会先执行for然后有空闲的时候再执行setTimeout,虽然setTimeout的时间延时为0,还是会缓存等待for循环执行结束之后等有空闲的时候再执行
 */

/**
 * 说出以下函数的作用,并填写空格内容
 */

//define
(function(window){
    function fn(str){
        this.str = str;
    }
    fn.prototype.format = function(){
        var arg = ____;
        return this.str.replace(____,function(a,b){
            return arg[b] || "";
        });
    };
    window.fn = fn;
})(window);

//use
(function(){
    var t = new fn('<p><a href = "{0}">{1}</a><span>{2}</span></p>');
    console.log(t.format('http://www.baidu.com','BaiDuSecurites','Welcome'));
})();

/**
 * 将字符串中的特定字符用函数的参数来替换
 */

//define 这里是一个私有作用域,为了让外面的函数可以访问到fn函数,传入了window对象,并且最终将定义的函数赋值到了window中的fn上了,所以外面可以访问到
(function(window){
    function fn(str){
        this.str=str;
    }
    fn.prototype.format=function(){
        var arg=arguments;
        return this.str.replace(/\{(\d+)\}/ig,function(a,b){
            // console.log(a);
            // console.log(arg);
            // console.log(b);
            console.log(arg[b]);
            return arg[b]||'';
        });
    }
    window.fn=fn;
})(window);

//use
(function(){
    var t=new fn('<p><a href="{0}">{1}</a><span>{2}</span></p>');
    console.log(t.format('http://www.alibaba.com','Alibaba','Welcome'));
})();

/**
 * 用js实现一个Promise,要求支持resolve,reject,done,fail,then,always.
 */

// state: 当前执行状态,有pending、resolved、rejected3种取值
//
// done: 向doneList中添加一个成功回调函数
//
// fail: 向failList中添加一个失败回调函数
//
// then: 分别向doneList和failList中添加回调函数
//
// always: 添加一个无论成功还是失败都会调用的回调函数
//
// resolve: 将状态更改为resolved,并触发绑定的所有成功的回调函数
//
// reject: 将状态更改为rejected,并触发绑定的所有失败的回调函数
//
// when: 参数是多个异步或者延迟函数,返回值是一个Promise兑现,当所有函数都执行成功的时候执行该对象的resolve方法,反之执行该对象的reject方法
// 下面是我的具体实现过程:

var Promise = function() {
    this.doneList = [];
    this.failList = [];
    this.state = 'pending';
};

Promise.prototype = {
    constructor: 'Promise',
    resolve: function() {
        this.state = 'resolved';
        var list = this.doneList;
        for(var i = 0, len = list.length; i < len; i++) {
            list[0].call(this);
            list.shift();
        }
    },
    reject: function() {
        this.state = 'rejected';
        var list = this.failList;
        for(var i = 0, len = list.length; i < len; i++){
            list[0].call(this);
            list.shift();
        }
    },
    done: function(func) {
        if(typeof func === 'function') {
            this.doneList.push(func);
        }
        return this;
    },
    fail: function(func) {
        if(typeof func === 'function') {
            this.failList.push(func);
        }
        return this;
    },
    then: function(doneFn, failFn) {
        this.done(doneFn).fail(failFn);
        return this;
    },
    always: function(fn) {
        this.done(fn).fail(fn);
        return this;
    }
};

function when() {
    var p = new Promise();
    var success = true;
    var len = arguments.length;
    for(var i = 0; i < len; i++) {
        if(!(arguments[i] instanceof Promise)) {
            return false;
        }
        else {
            arguments[i].always(function() {
                if(this.state != 'resolved'){
                    success = false;
                }
                len--;
                if(len == 0) {
                    success ? p.resolve() : p.reject();
                }
            });
        }
    }
    return p;
}
// Improve
// 目前只是实现了Promise的基础功能,但仍然还有无法处理的情况,例如要实现3个或3个以上的异步请求的串行,目前我的Promise没有办法支持new Promise(A).then(B).then(C)这样的形式,jQuery在1.7的版本中为Deferred(Promise)对象实现了pipe函数,可以通过这个函数实现上述功能,代码为$.Deferred(A).pipe(B).then(C),我尝试去读了jQuery这部分的代码,但是没能读懂,希望有大神能够给一些实现思路




/**
 * 两个顺序排列的数组A和B,求B数组是否为A数组的子集。(数组内可能有重复数字)
 */

var A = [1,2,2,2,2,3,5,5,5,6,8,9,9,9];
var B = [1,2,3];
/**
 * A,B,分别是两个顺序排列的数组,判断B是否为A的子集
 * @param _A
 * @param _B
 * @returns {boolean}
 */

function isASon(_A,_B){
    var flag = false;
    if(_A instanceof Array && _B instanceof Array){
        var i = 0,j = 0 ;
        while(i < _B.length){
            flag = false;
            for( ; j < _A.length ; j ++){
                if(_B[i] === _A[j] ){
                    flag = true;
                    break;
                }
            }
            if(flag){
                i ++;
            }else{
                return false;
            }
        }
        if(flag){
            return true ;
        }else{
            return false;
        }
    }
}

    isASon(A,B);


I hope my experience of entering the pit is helpful to you, may the Holy Light be with you

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324348484&siteId=291194637