• home > webfront > ECMAS > emphasis >

    JS易错笔试题(二):克隆|继承|语法及前端页面处理问题

    Author:[email protected] Date:

    前端JS基础笔试题集:js易错笔试题收集。JavaScript应用案与概念相关问题汇总讲解。

    ES5/ES6 的继承有什么区别?

    先看ES5的继承(原型链继承)

    function a () {
        this.name = 'a'
    }
    a.prototype.getName = function getName () {
        return this.name
    }
    function b () { }
    b.prototype = new a()
    console.log(b.prototype.__proto__ === a.prototype)

    ES6继承

    class A {
      constructor(a) {
        this.name = a;
      }
      getName() {
        return this.name;
      }
    }
    
    class B extends A{
      constructor() {
        super();
      }
    }

    对比代码可以知道,子类的继承都是成功的,但是问题出在,子类的 __proto__ 指向不一样。

    • ES5 的子类和父类一样,都是先创建好,再实现继承的,所以它们的指向都是 [Function]

    • ES6 则得到不一样的结果,它指向父类,那么我们应该能推算出来,它的子类是通过 super 来改造的


    根据 es6--阮一峰  ECMAScript6入门 的class继承篇  里面的说法,是这样子的:

    子类必须在constructor方法中调用super方法,否则新建实例时会报错。这是因为子类自己的this对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法,然后再对其进行加工,加上子类自己的实例属性和方法。如果不调用super方法,子类就得不到this对象

    ES5 的继承,实质是先创造子类的实例对象this,然后再将父类的方法添加到this上面(Parent.apply(this))ES6 的继承机制完全不同,实质是先将父类实例对象的属性和方法,加到this上面(所以必须先调用super方法),然后再用子类的构造函数修改this

    1. class 声明会提升,但不会初始化赋值。Foo 进入暂时性死区,类似于 let、const 声明变量。

    2. class 声明内部会启用严格模式。

    3. class 的所有方法(包括静态方法和实例方法)都是不可枚举的。

    4. class 的所有方法(包括静态方法和实例方法)都没有原型对象 prototype,所以也没有[[construct]],不能使用 new 来调用。

    5. 必须使用 new 调用 class。

    6. class 内部无法重写类名

    JS克隆

    实现一个函数clone,可以对JavaScript中的5种主要的数据类型(包括Number、String、Object、Array、Boolean)进行值复制

    • 考察点1:对于基本数据类型和引用数据类型在内存中存放的是值还是指针这一区别是否清楚

    • 考察点2:是否知道如何判断一个变量是什么类型的

    • 考察点3:递归算法的设计

    // 方法一:
    function clone (obj) {
        var o = obj.constructor === Array ? [] : {};
        for (var e in this) {
            o[e] = typeof this[e] === "object" ? this[e].clone() : this[e];
        }
        return o;
    };
    //方法二:
    
    /**
     * 克隆一个对象
     * @param Obj
     * @returns
     */
    
    function clone(Obj) {
        var buf;
        if (Obj instanceof Array) {
            buf = [];
            //创建一个空的数组
            var i = Obj.length;
            while (i--) {
                buf[i] = clone(Obj[i]);
            }
            return buf;
        } else if (Obj instanceof Object) {
            buf = {};
            //创建一个空对象
            for (var k in Obj) {
                //为这个对象添加新的属性
                buf[k] = clone(Obj[k]);
            }
            return buf;
        } else {
            //普通变量直接赋值
            return Obj;
        }
    }


    如何消除一个数组里面重复的元素?

    var arr=[1,2,3,3,4,4,5,5,6,1,9,3,25,4];
    function deRepeat(){
        var newArr=[];
        var obj={};
        var index=0;
        var l=arr.length;
        for(var i=0;i<l;i++){
            if(obj[arr[i]]==undefined)
            {
                obj[arr[i]]=1;
                newArr[index++]=arr[i];
            }
            else if(obj[arr[i]]==1)
                continue;
        }
        return newArr;
    
    }
    var newArr2=deRepeat(arr);
    alert(newArr2);
    //输出1,2,3,4,5,6,9,25

    es6去重

    function unique(arr) {    
        return Array.from(new Set(arr))
    }

    数组扁平化并去重

    已知如下数组:

    var arr = [ [1, 2, 2], [3, 4, 5, 5], [6, 7, 8, 9, [11, 12, [12, 13, [14] ] ] ], 10];

    编写一个程序将数组扁平化去并除其中重复部分数据,最终得到一个升序且不重复的数组

    Array.from(new Set(arr.toString().split(',').map(Number)))


    请评价以下代码并给出改进意见。

    if(window.addEventListener){
        var addListener = function(el,type,listener,useCapture){
            el.addEventListener(type,listener,useCapture);
        };
    }
    else if(document.all){
        addListener = function(el,type,listener){
            el.attachEvent("on"+type,function(){
                listener.apply(el);
            });
        }
    }

    评价:

    •  不应该在if和else语句中声明addListener函数,应该先声明;

    •  不需要使用window.addEventListener或document.all来进行检测浏览器,应该使用能力检测;

    •  由于attachEvent在IE中有this指向问题,所以调用它时需要处理一下

    function addEvent (elem, type, handler) {
      if (elem.addEventListener) {
        elem.addEventListener(type, handler, false)
      } else if (elem.attachEvent) {
        elem['temp' + type + handler] = handler
        elem[type + handler] = function () {
          elem['temp' + type + handler].apply(elem)
        }
        elem.attachEvent('on' + type, elem[type + handler])
      } else {
        elem['on' + type] = handler
      }
    }


    原生JS的window.onload与Jquery的$(document).ready(function(){})有什么不同?如何用原生JS实现Jq的ready方法?

    window.onload()方法是必须等到页面内包括图片的所有元素加载完毕后才能执行。

    $(document).ready()是DOM结构绘制完毕后就执行,不必等到加载完毕。

    /*
     * 传递函数给whenReady()
     * 当文档解析完毕且为操作准备就绪时,函数作为document的方法调用
     */
    var whenReady = (function() {
        //这个函数返回whenReady()函数
        var funcs = [];
        //当获得事件时,要运行的函数
        var ready = false;
        //当触发事件处理程序时,切换为true
        //当文档就绪时,调用事件处理程序
        function handler(e) {
            if(ready) return;
                //确保事件处理程序只完整运行一次
            //如果发生onreadystatechange事件,但其状态不是complete的话,那么文档尚未准备好
            if(e.type === 'onreadystatechange' && document.readyState !== 'complete') {
                return;
            }
            //运行所有注册函数
            //注意每次都要计算funcs.length
            //以防这些函数的调用可能会导致注册更多的函数
            for(var i=0; i<funcs.length; i++) {
                funcs[i].call(document);
            }
            //事件处理函数完整执行,切换ready状态, 并移除所有函数
            ready = true;
            funcs = null;
        }
        //为接收到的任何事件注册处理程序
        if(document.addEventListener) {document.addEventListener('DOMContentLoaded', handler, false);
            document.addEventListener('readystatechange', handler, false);
            //IE9+
            window.addEventListener('load', handler, false);
        }else if(document.attachEvent) {
            document.attachEvent('onreadystatechange', handler);
            window.attachEvent('onload', handler);
        }
        //返回whenReady()函数
        return function whenReady(fn) {
            if(ready) { fn.call(document); }
            else { funcs.push(fn); }
        }
    })();

    如果上述代码十分难懂,下面这个简化版:

    function ready(fn) {
        if (document.addEventListener) {
            //标准浏览器
            document.addEventListener('DOMContentLoaded', function () {
                //注销事件, 避免反复触发
                document.removeEventListener('DOMContentLoaded', arguments.callee, false);
                //执行函数
                fn();
            }, false);
        } else if (document.attachEvent) {
            //IE
            document.attachEvent('onreadystatechange', function () {
                if (document.readyState == 'complete') {
                    document.detachEvent('onreadystatechange', arguments.callee);
                    //函数执行
                    fn();
                }
            });
        }
    }



    转载本站文章《JS易错笔试题(二):克隆|继承|语法及前端页面处理问题》,
    请注明出处:https://www.zhoulujun.cn/html/webfront/ECMAScript/js6/2016_0417_7771.html