前端题2

23. 监听输入:

    1. oninput  > onchange:  onchange在离焦事件是触发。不如input灵敏 ( IE9+ )

    2. 中文输入时(即非直接输入),input获取的值不正确,需加判断。( IE9+ )

        compositionstart:当浏览器有非直接的文字输入时, compositionstart事件会以同步模式触发.

        compositionEnd:    当浏览器是直接的文字输入时, compositionend会以同步模式触发.

var cpLock = false;
input.addEventListener('compositionstart', function(){
    cpLock = true;
})
input.addEventListener('compositionend', function(){
    cpLock = false;
})
input.addEventListener('input', function(){
    if(!cpLock)console.log(this.value);
});

    3. 需要兼容IE9一下的,只能使用keyPress,keyDown等事件,判断keyCode

    (参考做法:http://jyren-rachel.iteye.com/blog/1886275)

24. 递归中的性能:

        递归是处遍历外最常用的循环方法。鉴于其性能问题,一般能用while,for等循环的尽量不用递归。 若必须用递归方法,一般把递归中的执行代码放入setTimeout方法中,以避免栈溢出(setTimeout总是在下一次的tick中执行)。

        setInterval的不靠谱:当每次执行的时间小于循环时间时,不会出现异常;而当代码执行时间较长,超出循环时间时,下一次的循环将被延后,这样每次的循环间隔将不统一,且任务会堆积在队列中。

更详细的介绍https://www.cnblogs.com/simonbaker/p/5707270.html

25. es6属性:

    1. let , const

        let : a. 不存在变量提升, 必须先声明 后使用。(会报错 is not defined ;var 中则不报错,返回值为 undefined)

               b. 存在块作用域内,同域内不可重复声明

               c. 暂时性死区:一旦在作用域内声明了次变量,若提前访问会报错,(即使外域也声明了同名变量)

        const : 与 let 特点相同,声明时必须赋值,且不能更改赋值,若是对象保存的是对象的地址。

    2. 结构赋值 : 等号右边的值会赋予左边的变量。        

   

    3. 模板字符串: ‘字符串’,按照字符串处理拼接。

        a. 反引号为特殊字符,使用的话需加 \ 转义。

        b. 花括号内可以进行 js 运算

        c. 空格、缩进都会被保留

         `${1}+${2}`  //  '1+2'

    4.   rest参数  , 扩展运算符

        rest :  (. . .a)  作为参数或者等号左边变量 必须为最后一个参数

        扩展运算符: 相当于rest的逆运算, 展开一个数组或者对象

    5.class 类,super方法:(阮一峰:https://m.imooc.com/article/20618

        注:react中一般写法: super ( props );这样写的原因是 在constructor 中可以使用 this.props,  props是实例化时传入的参数。

        (子类才会有super方法,父类是没有的);在子类的构造函数中,只有调用super之后,才能使用this关键字,否则会报错,这是因为子类没有自己的this对象,而是继承父类的this对象,然后对其进行加工,如果不调用super方法,子类就得不到this对象;

        如果子类没有定义constructor方法,这个方法会默认添加,也就是说,不管有没有显式定义,任何一个子类都有constructor方法。

        通过super调用父类的方法时,super会绑定子类的this。

        super当作函数调用时,代表父类的构造函数;super作为对象时,在普通方法中,指向父类的原型对象,在静态方法中,指向父类

26. http1.0 和 http2.0:

    http2增加了:

  • 多路复用
  • 压缩头信息
  • 请求划分优先级
  • 支持服务器端主动推送 
  • 只支持https

27.  use strict 严格模式:(参考文章:https://blog.csdn.net/weixin_40387601/article/details/80514358)

        js 以更严谨的方式运行。

28. 小程序实现vue类型的数据监听:Object.defineProperty方法

    

    /**
     * 设置监听器
     */
    setWatcher(page) {
        let data = page.data;
        let watch = page.watch;
        Object.keys(watch).forEach(v => {
            let key = v.split('.'); // 将watch中的属性以'.'切分成数组
            let nowData = data; // 将data赋值给nowData
            for (let i = 0; i < key.length - 1; i++) { // 遍历key数组的元素,除了最后一个!
                nowData = nowData[key[i]]; // 将nowData指向它的key属性对象
            }
            let lastKey = key[key.length - 1];
            // 假设key==='my.name',此时nowData===data['my']===data.my,lastKey==='name'
            let watchFun = watch[v].handler || watch[v]; // 兼容带handler和不带handler的两种写法
            let deep = watch[v].deep; // 若未设置deep,则为undefine
            this.observe(nowData, lastKey, watchFun, deep, page); // 监听nowData对象的lastKey
        })
    },
    /**
     * 监听属性 并执行监听函数
     */
    observe(obj, key, watchFun, deep, page) {
        var val = obj[key];
        // 判断deep是true 且 val不能为空 且 typeof val==='object'(数组内数值变化也需要深度监听)
        if (deep && val != null && typeof val === 'object') { 
            Object.keys(val).forEach(childKey=>{ // 遍历val对象下的每一个key
                this.observe(val,childKey,watchFun,deep,page); // 递归调用监听函数
            })
        }
        var that = this;
        Object.defineProperty(obj, key, {
            configurable: true,
            enumerable: true,
            set: function(value) {
                // 用page对象调用,改变函数内this指向,以便this.data访问data内的属性值
                watchFun.call(page,value,val); // value是新值,val是旧值
                val = value;
                if(deep){ // 若是深度监听,重新监听该对象,以便监听其属性。
                    that.observe(obj, key, watchFun, deep, page); 
                }
            },
            get: function() {
                return val;
            }
        })
    }


page中使用:

//index.js
 
Page({
    data: {
        my: {
            name: 'xuyang',
            age: 21,
            hobby: ['girls', 'games']
        },
        nameInfo:{}
    },
    onLoad() {
        getApp().setWatcher(this);
        this.data.my.hobby[0] = 'study';
        this.setData({
            nameInfo:{name:'haha',sex:'boy'}
        })
        console.log(this.data)
    },
    watch: {
        my:{
            handler(newValue) {
                console.log(newValue);
            },
            deep:true
        }
    }
})

        (转载链接:https://blog.csdn.net/xuyangxinlei/article/details/81408200)

29. CSS 3  + HTML 5  (postcss-loader只是给 css 添加前缀,通gulp中的autoprefixer, 谨慎使用新属性)

    1.选择器:

        属性:[att=val] 指定特定名字的元素

              [att*=val] 匹配val*的元素,

              [att^=val] 匹配val开头的元素,比如id为val1、val432432都可以。

              [att$=val] 匹配val结尾的元素,比如id为1213val、fdajlval等等。

        顺序:first-child:选择第一个子元素

              last-child:选择最后一个子元素

              nth-child:选择第n个子元素,这个还可以根据奇偶来制定,

                   nth-last-child:选择倒数第n个子元素

              only-child:单个子元素时,指定样式

        状态: hover , active ,checked , selection, focus , enabled , disabled , read-only

    2. 效果: border-radius , box-shadow  , box-sizing , background属性 , linear-gradient , radial-gradient

    3.动画:

        1.关键帧动画:animation: name  duration timing-function delay count;    @keyframes

        2.2D效果属性: tranform :     translate  、rotate、scale ;    transition   

    4. html5 :

        1.语义化标签: nav ,head ,footer , aside,article,section;

        2. 拖拽: drag  , drop 

        3. vedio 、audio、canvas

        4.input 新类型: time , date , email , url ,  search  ,calendar ,  datetime, week , month , color , tel ,number ,

        5. websocket , localstorage 

28.闭包:定义 , 效果:可以获去操作一个函数中的局部变量。缺点:消耗内存,一直保持父函数的引用。 优点: 对局部变量保护作用,利于函数的 封装。

29. CMD,AMD比较:

    AMD(异步模块定义):requirejs  : 提前下载,提前执行

    CMD(通用模块定义):seajs       :提前下载,延迟执行    

    RequireJS 和 SeaJS 都是很不错的模块加载器,两者区别如下:

    1. 两者定位有差异。RequireJS 想成为浏览器端的模块加载器,同时也想成为 Rhino / Node 等环境的模块加载器。SeaJS 则专注于 Web 浏览器端,同时通过 Node 扩展的方式可以很方便跑在 Node 服务器端

    2. 两者遵循的标准有差异。RequireJS 遵循的是 AMD(异步模块定义)规范,SeaJS 遵循的是 CMD (通用模块定义)规范。规范的不同,导致了两者 API 的不同。SeaJS 更简洁优雅,更贴近 CommonJS Modules/1.1 和 Node Modules 规范。

    3. 两者社区理念有差异。RequireJS 在尝试让第三方类库修改自身来支持 RequireJS,目前只有少数社区采纳。SeaJS 不强推,而采用自主封装的方式来“海纳百川”,目前已有较成熟的封装策略。

    4. 两者代码质量有差异。RequireJS 是没有明显的 bug,SeaJS 是明显没有 bug。

    5. 两者对调试等的支持有差异。SeaJS 通过插件,可以实现 Fiddler 中自动映射的功能,还可以实现自动 combo 等功能,非常方便便捷。RequireJS 无这方面的支持。

    6. 两者的插件机制有差异。RequireJS 采取的是在源码中预留接口的形式,源码中留有为插件而写的代码。SeaJS 采取的插件机制则与 Node 的方式一致:开放自身,让插件开发者可直接访问或修改,从而非常灵活,可以实现各种类型的插件。.

    (来源文章:http://www.cnblogs.com/dojo-lzz/p/4707725.html

30. arguments对象:函数的参数对象

    特点:1. 不是数组,但是有数组的一些属性,length,索引,变成数组的方法:[].slice.call(arguments)或Array.prototype.slice.call(arguments);

                   typeof arguments   // obeject ;            {}.tostring.call(arguments)   // [object Arguments]

              2. 实参中的值和arguments中的值保持一致。

              3. length的值不会自动改变,必须主动设置,但可以访问

              4. 属性callee:arguments.callee指向函数本身,可以用于递归中,优点是即使函数名称改变,也不会报错 ; arguments.callee.caller指向调用此函数的函数,若无为null,

              5. 严格模式下,对arguments操作,只对arguments有效,对参数无效。

function test(a,b,c){
    console.log(c);
    arguments[2]=10;
    console.log(c);
    arguments[3]=10;
    console.log(arguments[3]);
    console.log(arguments.length);
    arguments.length=4;
    console.log(arguments.length);
}

test(1,2,3)
// 结果: 
//        3
//        10           特点2
//        10           特点3   
//         3   
//         4

test(1,2)
// 结果: 
//        undefined    特点2
//        10           特点3   
//        10   
//        2
//        4

31. 队列,宏任务,微任务:参考:https://juejin.im/post/59e85eebf265da430d571f89

32. SEO及优化:

    1. TDK:title , description , keywords

    2. 标题标签,img的alt属性,语义化标签,

    SPA的优化:单页面应用对国内浏览器seo很不友好,国外浏览器不受影响。

                    a. 预渲染    b. ssr 服务端渲染,首屏采用服务端渲染。nuxt.js

                    vue : prerender-plugin  + vue-meta-info

33. sort方法:浏览器的实现方式不同:V8:<=22使用InsertionSort ,>22使用QuickSort排序。ff:归并排序

//自定义sort方法:
Array.prototype.mySort = function (fn) {
    for (var i = this.length; i >0; i--) {
        for (var j =0; j < i; j++) {
            if (fn && typeof fn == 'function') {
                if(fn(this[j] ,this[j+1])>0){
                    [this[j], this[j+1]] = [this[j+1], this[j]];
                }
            } else {
                var a = String(this[j]),b=String(this[j+1]);
                if(charcode(a,b)>0){
                    var temp=this[j];
                    this[j] = this[j+1];
                    this[j+1] = temp;
                    // [this[j+1], this[j]] = [this[j], this[j+1]];
                }
            }
        }
    }
    function charcode(a,b){    
        if(a.charCodeAt(0)<b.charCodeAt(0)){
           return -1
        }else if(a.charCodeAt(0)>b.charCodeAt(0)){
            return 1
         }else{
            if(a.slice(1)===''){
                return -1
            }else if(b.slice(1)===''){
                return 1
            }else{
                return charcode(a.slice(1),b.slice(1))
            } 
        }
    }
    return this;
}

    

34. 构造函数:   

 //js中没有类的概念(es6中也只是中语法糖),所以通过原型链实现继承这种机制。

 //构造函数实际上就是普通函数,返回一个实例对象
  function Test(name,age){
      this.name=name;
      this.age=age;
  }; 

 //每个函数都有prototype属性,一个对象,是所以实例对象共有的属性方法,因为都引用这个对象,new 的过程中会自动添加constructor属性,构造函数本身。
   Test.prototype.constructor = Test;
   Test.prototype.fn=function(){};

 //一个实例的属性分为两部分:自有属性 + 公共属性
   var  test = new Test(1,2);  // name , age ,  fn

 //通过 hasOwnProperty 判断属性是否是自有属性
   test.hasOwnProperty('fn')   // false

 //通过 isPrototypeOf 判断 实例 是否是构造函数的实例
   Test.prototype.isPrototypeOf(test) // true;
   

35原型链:

数据类型:undefined,null,Number,String,Boolean + Object 六大类型。

Number,String,Boolean, Object,Function等都是构造函数,typeof 值:‘function’
生成相应类型的数据可以直接定义,也可以通过构造函数生成(这种方式生成的返回值都是一个 object,function例外,返回的是function),

// 1.prototype:只有函数有此属性,

// 2.__proto__:对象的此属性指向构造函数的prototype, 函数的此属性指向Function的prototype(所以的函数都是Function的实例),
     Obeject.__proto__ === Function.prototype   // true    typeof 为function,此function较特殊,没有prototype属性,
     Object.__proto__.__proto__ ===Object.prototype  // true   拥有object的属性
     

//constructor:指向构造函数本身,在34中,是在prototype中的默认一个属性。因此所以的实例中也会有此方法,

sd

36.运算符优先级及转换

var a = (!(~+[])+{})[--[~+""][+[]]*[~+[]] + ~~!+[]] + ({}+[])[[~!+[]]*~+[]];  
     // sb  (--的优先级大于*;~改变正负值再减一;[]是空=>0;{}是[object Object])

sd

猜你喜欢

转载自my.oschina.net/u/3272730/blog/2052450