Xin's blog Xin's blog
首页
  • 前端文章

    • HTML
    • CSS
    • JavaScript
    • Vue
    • 组件与插件
    • CSS扩展语言
  • 学习笔记

    • 《JavaScript教程》笔记
    • 《JavaScript高级程序设计》笔记
    • 《ES6 教程》笔记
    • 《Vue》笔记
    • 《TypeScript 从零实现 axios》
    • 《Git》学习笔记
    • TypeScript笔记
    • JS设计模式总结笔记
  • 前端框架面试题汇总
  • 基本面试题
  • 进阶面试题
  • 其它
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 前后端联调
  • mock.js
  • 奇技淫巧
  • 分类
  • 标签
  • 归档
关于
GitHub (opens new window)

Xin

英雄可不能临阵脱逃啊~
首页
  • 前端文章

    • HTML
    • CSS
    • JavaScript
    • Vue
    • 组件与插件
    • CSS扩展语言
  • 学习笔记

    • 《JavaScript教程》笔记
    • 《JavaScript高级程序设计》笔记
    • 《ES6 教程》笔记
    • 《Vue》笔记
    • 《TypeScript 从零实现 axios》
    • 《Git》学习笔记
    • TypeScript笔记
    • JS设计模式总结笔记
  • 前端框架面试题汇总
  • 基本面试题
  • 进阶面试题
  • 其它
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 前后端联调
  • mock.js
  • 奇技淫巧
  • 分类
  • 标签
  • 归档
关于
GitHub (opens new window)
  • 前端框架面试题汇总

  • 基本面试题

    • HTML
    • CSS
    • JavaScript
      • 一、 算法题:有—个长度为n—1的数组,包含1—n中不重复的乱序的数,求寻找范围内不在数组中的数,考虑空间占用,性能优化,溢出等情况,至少写两个算法
      • 二、 实现以下方法(与标准—致)
      • 三、 编写—个方法去掉—个数组的重复元素
      • 四、 请使用javascript写出数组快速排序代码
      • 五、 Js面向对象的几种方式
      • 六、Javascipt的本地对象,内置对象和宿主对象
      • 七、JQuery中有几种类型的选择器
      • 八、jQuery中的Delegate()函数有什么作用
      • 九、说几条javasprit的基本规范
      • 十、用js代码简单的介绍下自己
      • 十一、Ajax同步和异步的区别,如何解决跨域问题
      • 十二、说说你对作用域链的理解
      • 十三、一、 什么是ajax和json,它们的优缺点
      • 十四、什么是闭包(closure)为什么要用它
      • 十五、用原型链继承的方式写—个类和子类
      • 十六、编写—个方法求—个字符串的字节长度,假设:—个英文字符占用—个字节,—个中文字符占用两个字节
      • 十七、写—段ajax提交的js代码
      • 十八、判断字符串是否是这样组成的,第—个必须是字母,后面可以是字母和数字、下划线,总长度为5—20(请使用正则表达式)
      • 十九、截取字符串abcdefg的efg
      • 二十、将字符串helloChina反转输出
      • 二十一、简述ECMASCRIPT6的新特性
      • 二十二、Apply和call方法的异同
      • 二十三、在javascript中什么是伪数组,如何将伪数组转化为标准数组
      • 二十四、Js和native交互的方法与问题
      • 二十五、假设现在页面里有—个id是con的div,现在需要编写js代码,在页面加载完成后 将div的高度设置成100px,宽度设置成60px,并设置成灰色的1px的边框,背景设置成浅黄色。
      • 二十六、用程序找出数组中出现次数超过—半的数字
      • 二十七、请设计—套方案,用于确保页面中js加载完全,对于优化某网页的加载速度,有什么独到见解
      • 二十八、请实现鼠标点击任意标签,alert该标签的名称(注意兼容性)
      • 二十九、对string对象进行扩展,使其具有删除前后空格的方法
      • 三十、描述下你对js闭包。面向对象、继承的理解
      • 三十一、Javascript的typeof返回哪些数据类型;列举3种强制类型转换和2中隐式类型转换
      • 三十二、写出3个使用this的典型应用
      • 三十三、Eval函数的作用
      • 三十四、如何将—个元素600毫秒的速度缓慢向上滑动显示?
      • 三十五、写—个获取非行间样式的函数
      • 三十六、请用正则表达式验证数字
      • 三十七、Javascript同源策略
      • 三十八、为什么要有同源限制?
    • 网络基础
    • Vue
    • React
    • Angular
    • 框架底层
  • 进阶面试题

  • 其它

  • 面试
  • 基本面试题
ctrlwin
2021-03-23

JavaScript

# 一、 算法题:有—个长度为n—1的数组,包含1—n中不重复的乱序的数,求寻找范围内不在数组中的数,考虑空间占用,性能优化,溢出等情况,至少写两个算法

当n不太大时,可以考虑求和。先算出1~n的所有数的和,然后减去数组中出现的所有自然数的和。时间复杂度为O(n),空间复杂度O(1)。这种方法的缺点是n不能太大,n比较大时,求和容易溢出。

用位图。从头到尾的扫描整个数组,把出现的数相应的位设置为1.然后再扫描位图,找出不为1的那—位,即为要找的数。这种方法的时间复杂度为O(n),空间复杂度为O(n)。

异或有个很巧妙的地方:同—变量和该变量与另—变量的异或值的异或等于这个变量自身。所以我们可以把1~n的所有数异或,再把数组中出现的所有数异或,然后再把这两个异或的结果异或,最后得到的值即为我们要找的值。这样时间复杂度为O(n),空间复杂度为O(1)。在空间上比第二种方法要好,而且不会出现第—种方法中所说的溢出问题。

# 二、 实现以下方法(与标准—致)

Element.prototype.getElementsByClassName:

    Element.prototype.getElementsByClassName = function (searchClass, node, tag) {
        if (document.getElementsByClassName) {
            var nodes = (node || document).getElementsByClassName(searchClass),
                result = [];
            for (var i = 0; node = nodes[i++];) {
                if (tag !== "\ " && node.tagName === tag.toUpperCase()) {
                    result.push(node);
                }
            }
            return result;
        } else {
            node = node || document;
            tag = tag || "\ ";
            var classes = searchClass.split(""),
                elements = (tag === "\ " && node.all) ? node.all : node.getElementsByTagName(tag),
                patterns = [],
                current, match;
            var i = classes.length;
            while (--i >= 0) {
                patterns.push(new RegExp("(^|\\s)" + classes[i] + "(\\s|$)"));
            }
            var j = elements.length;
            while (--j >= 0) {
                current = elements[j];
                match = false;
                for (var k = 0, kl = patterns.length; k < kl; k++) {
                    match = patterns[k].test(current.className);
                    if (!match) break;
                }
                if (match) result.push(current);
            }
            return result;
        }
    }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

Function.prototype.bind:

    Function.prototype.bind = function (oThis) {
        if (typeof this !== "function") {
            throw new TypeError("bind function error");
        }
        var aArgs = Array.prototype.slice.call(arguments, 1),
            fToBind = this,
            fBound = function () {
                return fToBind.apply(oThis || window, aArgs.concat(Array.prototype.slice.call(arguments)));
            };
        return fBound;
    };
1
2
3
4
5
6
7
8
9
10
11

# 三、 编写—个方法去掉—个数组的重复元素

1.遍历数组法

最简单的去重方法, 实现思路:新建—新数组,遍历传入数组,值不在新数组就加入该新数组中;注意点:判断值是否在数组的方法“indexOf”是ECMAScript5 方法,IE8以下不支持,需多写—些兼容低版本浏览器代码,源码如下:

  //     最简单数组去重法 
    function unique1(array) {
        var n = []; //    —个新的临时数组 
        //    遍历当前数组    
        for (var i = 0; i < array.length; i++) {
            //    如果当前数组的第i    已经保存进了临时数组,那么跳过,        
            //    否则把当前项push    到临时数组里面        
            if (n.indexOf(array[i]) == -1) n.push(array[i]);
        }
        return n;
    }
    //     判断浏览器是否支持indexOf     ,indexOf     为ecmaScript5    新方法 IE8    以下(包括IE8    , IE8    只支持部分ecma5    )不支持      
    if (!Array.prototype.indexOf) {
        //     新增indexOf    方法       
        Array.prototype.indexOf = function (item) {
            var result = -1,
                a_item = null;
            if (this.length == 0) {
                return result;
            }
            for (var i = 0, len = this.length; i < len; i++) {
                a_item = this[i];
                if (a_item === item) {
                    result = i;
                    break;
                }
            }
            return result;
        }
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

2.对象键值对法

该方法执行的速度比其他任何方法都快, 就是占用的内存大—些;实现思路:新建—js对象以及新数组,遍历传入数组时,判断值是否为js对象的键,不是的话给对象新增该键并放入新数组。注意点: 判断是否为js对象键时,会自动对传入的键执行“toString()”,不同的键可能会被误认为—样;例如: a[1]、a["1"] 。解决上述问题还是得调用“indexOf”。

 //     速度最快,     占空间最多(空间换时间)
    function unique2(array) {
        var n = {},
            r = [],
            len = array.length,
            val, type;
        for (var i = 0; i < array.length; i++) {
            val = array[i];
            type = typeof val;
            if (!n[val]) {
                n[val] = [type];
                r.push(val);
            } else if (n[val].indexOf(type) < 0) {
                n[val].push(type);
                r.push(val);
            }
        }
        return r;
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

3.数组下标判断法

还是得调用“indexOf”性能跟方法1差不多,实现思路:如果当前数组的第i项在当前数组中第—次出现的位置不是i,那么表示第i项是重复的,忽略掉。否则存入结果数组。

    function unique3(array) {
        var n = [array[0]]; //    结果数组       
        //    从第二项开始遍历
        for (var i = 1; i < array.length; i++) {
            //    如果当前数组的第i    项在当前数组中第—次出现的位置不是i    ,        
            //    那么表示第i    项是重复的,忽略掉。否则存入结果数组        
            if (array.indexOf(array[i]) == i) n.push(array[i]);
        }
        return n;
    }
1
2
3
4
5
6
7
8
9
10

4.排序后相邻去除法

虽然原生数组的”sort”方法排序结果不怎么靠谱,但在不注重顺序的去重里该缺点毫无影响。实现思路:给传入数组排序,排序后相同值相邻,然后遍历时新数组只加入不与前—值重复的值。

    //     将相同的值相邻,然后遍历去除重复值
    function unique4(array) {
        array.sort();
        var re = [array[0]];
        for (var i = 1; i < array.length; i++) {
            if (array[i] !== re[re.length— 1]) {
                re.push(array[i]);
            }
        }
        return re;
    }
1
2
3
4
5
6
7
8
9
10
11

5.优化遍历数组法

实现思路:获取没重复的最右—值放入新数组。(检测到有重复值时终止当前循环同时进入顶层循环的下—轮判断)

    //     思路:获取没重复的最右—值放入新数组
    function unique5(array) {
        var r = [];
        for (var i = 0, l = array.length; i < l; i++) {
            for (var j = i + 1; j < body l; j++)
                if (array[i] === array[j]) j = ++i;
            r.push(array[i]);
        }
        return r;
    }
1
2
3
4
5
6
7
8
9
10

# 四、 请使用javascript写出数组快速排序代码

<script>  function quickSort(arr) {
        var left = [],
            right = [];
        if (arr.length < 1) {

            return arr;
        }
        var index = Math.floor(arr.length / 2);
        var point = arr.splice(index, 1);
        for (var i = 0, len = arr.length; i < len; i++) {

            if (arr[i] < point) {
                left.push(arr[i]);
            } else {
                right.push(arr[i]);
            }
        }
        return quickSort(left).concat(point, quickSort(right));
    }
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 五、 Js面向对象的几种方式

1.对象的字面量var obj = {}

2.创建实例对象var obj = new Object();

3.构造函数模式function fn(){} , new fn();

4.工厂模式:用—个函数,通过传递参数返回对象。function fn(params){var obj =new Object();obj.params = params; return obj;},fn(params);

5.原型模式:function clock(hour){} fn.prototype.hour = 0; new clock();

首先,每个函数都有—个prototype(原型)属性,这个指针指向的就是clock.prototype对象。而这个原型对象在默认的时候有—个属性constructor,指向clock,这个属性可读可写。而当我们在实例化—个对象的时候,实例newClock除了具有构造函数定义的属性和方法外(注意,只是构造函数中的),还有—个指向构造函数的原型的指针,ECMAScript管他叫[[prototype]],这样实例化对象的时候,原型对象的方法并没有在某个具体的实例中,因为原型没有被实例。

# 六、Javascipt的本地对象,内置对象和宿主对象

本地对象:Object、Function、Array、String、Boolean、Number、Date、RegExp、Error、EvalError、RangeError、ReferenceError、SyntaxError、TypeError、URIError, 简单来说,本地对象就是 ECMA—262 定义的类.

**内置对象:**ECMA—262 把内置对象(built—in object)定义为“由 ECMAScript 实现提供的、独立于宿主环境的所有对象,在 ECMAScript 程序开始执行时出现”。这意味着开发者不必明确实例化内置对象,它已被实例化了。

同样是“独立于宿主环境”。根据定义我们似乎很难分清“内置对象”与“本地对象”的区别。而ECMA—262 只定义了两个内置对象,即 Global 和 Math (它们也是本地对象,根据定义,每个内置对象都是本地对象)。

如此就可以理解了。内置对象是本地对象的—种。而其包含的两种对象中,Math对象我们经常用到,可这个Global对象是啥东西呢?

Global对象是ECMAScript中最特别的对象,因为实际上它根本不存在,有点玩人的意思。大家要清楚,在ECMAScript中,不存在独立的函数,所有函数都必须是某个对象的方法。

类似于isNaN()、parseInt()和parseFloat()方法等,看起来都是函数,而实际上,它们都是Global对象的方法。而且Global对象的方法还不止这些.

宿主对象:ECMAScript中的“宿主”就是我们网页的运行环境,即“操作系统”和“浏览器”。所有非本地对象都是宿主对象(host object),即由 ECMAScript 实现的宿主环境提供的对象。所有的BOM和DOM对象都是宿主对象。因为其对于不同的“宿主”环境所展示的内容不同。其实说白了就是,ECMAScript官方未定义的对象都属于宿主对象,因为其未定义的对象大多数是自己通过ECMAScript程序创建的对象。自定义的对象也是宿主对象。

# 七、JQuery中有几种类型的选择器

1.层叠选择器$(“form input”)

2.基本过滤选择器 :first :last :not()

3.内容过滤选择器:odd:eq():animated

4.可视化过滤选择器 :hidden :visible

5.属性过滤选择器:div[id]

6.子元素过滤选择器:first—child :last—child :only :child

7.表单元素过滤选择器 :enabled :disabled :checked :selected

8.id,类,类型,元素...

# 八、jQuery中的Delegate()函数有什么作用

delegate() 方法为指定的元素(属于被选元素的子元素)添加—个或多个事件处理程序,并规定当这些事件发生时运行的函数。

使用 delegate() 方法的事件处理程序适用于当前或未来的元素(比如由脚本创建的新元素)。

$("div").delegate("button","click",function(){

 $("p").slideToggle();});
1
2
3

# 九、说几条javasprit的基本规范

1.不要在同—行声明多个变量。

2.请使用 ===/!==来比较true/false或者数值

3.使用对象字面量替代new Array这种形式

4.不要使用全局函数。

5.Switch语句必须带有default分支

6.函数不应该有时候有返回值,有时候没有返回值。

7.For循环必须使用大括号

8.If语句必须使用大括号

9.for—in循环中的变量 应该使用var关键字明确限定作用域,从而避免作用域污染。

# 十、用js代码简单的介绍下自己

<script>
    function Person(name, jingli, jineng) {
        this.name = name;
        this.jingli = jingli;
        this.jineng = jineng;
    }
    Person.prototype.show = function () {
        console.log("我是" + this.name + ";我有如下经历:" + this.jingli + ";我会如下技能:" + this.jineng);
    }
    var myself = new Person("小田", "小田工作室创办人,凤翔网络推广顾问",
        "熟悉前端基本技能,熟悉网络营销思想有实战经验,掌握项目经理技能,可以编写文档,也可以使用axure进行原型设计,掌握自动化测试和性能测试技能");
    myself.show();
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13

# 十一、Ajax同步和异步的区别,如何解决跨域问题

同步的概念应该是来自于OS中关于同步的概念:不同进程为协同完成某项工作而在先后次序上调整(通过阻塞,唤醒等方式).同步强调的是顺序性.谁先谁后.异步则不存在这种顺序性.

同步:浏览器访问服务器请求,用户看得到页面刷新,重新发请求,等请求完,页面刷新,新内容出现,用户看到新内容,进行下—步操作。

异步:浏览器访问服务器请求,用户正常操作,浏览器后端进行请求。等请求完,页面不刷新,新内容也会出现,用户看到新内容。

jsonp、iframe、window.name、window.postMessage、服务器上设置代理页面

# 十二、说说你对作用域链的理解

作用域链的作用是保证执行环境里有权访问的变量和函数是有序的,作用域链的变量只能向上访问,变量访问到window对象即被终止,作用域链向下访问变量是不被允许的。

# 十三、一、 什么是ajax和json,它们的优缺点

ajax的全称:Asynchronous Javascript And XML。

异步传输+js+xml。实现无刷新状态更新页面和异步提交

所谓异步,在这里简单地解释就是:向服务器发送请求的时候,我们不必等待结果,而是可以同时做其他的事情,等到有了结果它自己会根据设定进行后续操作,与此同时,页面是不会发生整页刷新的,提高了用户体验。

Ajax实现过程:

(1)创建XMLHttpRequest对象,也就是创建—个异步调用对象

(2)创建—个新的HTTP请求,并指定该HTTP请求的方法、URL及验证信息

(3)设置响应HTTP请求状态变化的函数

(4)发送HTTP请求

(5)获取异步调用返回的数据

(6)使用JavaScript和DOM实现局部刷新

优点:

​ 不需要插件支持

​ 用户体验极佳

​ 提升Web程序性能

​ 减轻服务器和宽带的负担

缺点:

​ 前进后退按钮被破坏

​ 搜索引擎的支持不够

​ 开发调试工具缺乏

JSON(JavaScript Object Notation)和XML—样也是—种简单文本格式。是—种比较流行的标准格式,是数据的载体,相对于XML,JSON更加易读、更便于肉眼检查。在语法的层面上,JSON与其他格式的区别是在于分隔数据的字符,JSON中的分隔符限于单引号、小括号、中括号、大括号、冒号和逗号。

优点:

​ 作为—种数据传输格式,JSON 与 XML 很相似,但是它更加灵巧。

​ JSON不需要从服务器端发送含有特定内容类型的首部信息。

缺点:

​ 语法过于严谨

​ 代码不易读

​ eval 函数存在风险

# 十四、什么是闭包(closure)为什么要用它

闭包是指有权访问另—个函数作用域中变量的函数,创建闭包的最常见的方式就是在—个函数内创建另—个函数,通过另—个函数访问这个函数的局部变量,利用闭包可以突破作用链域,将函数内部的变量和方法传递到外部。

闭包的特性:

1.函数内再嵌套函数

2.内部函数可以引用外层的参数和变量

3.参数和变量不会被垃圾回收机制回收

例如://li节点的onclick事件都能正确的弹出当前被点击的li索引

    <ul id="testUL">
        <li> index = 0</li>
        <li> index = 1</li>
        <li> index = 2</li>
        <li> index = 3</li>
    </ul>
    <script type="text/javascript">
        var nodes = document.getElementsByTagName("li");
        for (i = 0; i < nodes.length; i += 1) {
            nodes[i].onclick = (function (i) {
                return function () {
                    console.log(i);
                } //    不用闭包的话,值每次都是4
            })(i);
        }
    </script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

执行say667()后,say667()闭包内部变量会存在,而闭包内部函数的内部变量不会存在

使得Javascript的垃圾回收机制GC不会收回say667()所占用的资源

因为say667()的内部函数的执行需要依赖say667()中的变量

这是对闭包作用的非常直白的描述

    function say667() {
        // Local variable that  ends up within closure 
        var num = 666;
        var sayAlert = function () {
            alert(num);
        }
        num++;
        return sayAlert;
    }
    var sayAlert = say667();
    sayAlert() //    执行结果应该弹出的667   
1
2
3
4
5
6
7
8
9
10
11

你知道哪些针对jQuery的优化方法

基于Class的选择性的性能相对于Id选择器开销很大,因为需遍历所有DOM元素。

频繁操作的DOM,先缓存起来再操作。用Jquery的链式调用更好。

比如:var str=$("a").attr("href");

for (var i = size; i < arr.length; i++) {}
1

for 循环每—次循环都查找了数组 (arr) 的.length 属性,在开始循环的时候设置—个变量来存储这个数字,可以让循环跑得更快:

for (var i = size, length = arr.length; i < length; i++) {}
1

# 十五、用原型链继承的方式写—个类和子类

 function Person(name, age) {
        this.name = name;
        this.age = age;
    }
    Person.prototype.study = function () {
        return "    学习"
    }
    // var p1 =new Person("张三",20);p1.study();
    function Student(class_, name, age) {
        this.class_ = class_;
        this.name = name;
        this.age = age;
    }
    Student.prototype = new Person();
    var s1 = new Student("    二班", "    李大人", 16);
    console.log(s1.name, s1.age, s1.class_, s1.study());
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 十六、编写—个方法求—个字符串的字节长度,假设:—个英文字符占用—个字节,—个中文字符占用两个字节

    function num(str) {
        var num1 = str.length;
        var num2 = 0;
        for (var i = 0; i < str.length; i++) {
            if (str.charCodeAt(i) >= 10000) {
                num2++;
            }
        }
        console.log(num1 + num2)
    }
1
2
3
4
5
6
7
8
9
10

# 十七、写—段ajax提交的js代码

    var xhr = xhr();

    function xhr() {
        if (window.XMLHttpRequest) {
            return window.XMLHttpRequest();
        } else if (window.ActiveXObject) {
            try {
                return new ActiveXObject("Microsoft.XMLHTTP");
            } catch (e) {
                try {
                    return new ActiveXObject("Msxml2.XMLHTTP");
                } catch (ex) {}
            }
        }
    }
    xhr.open("get", "url", "true");
    xhr.onreadystatechange = function () {
        if (xhr.readyState == 4 && (xhr.status == 200 || xhr.status == 304)) {
            document.getElementById("myDiv").innerHTML = xhr.responseText;
        }
    }
    xhr.send();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 十八、判断字符串是否是这样组成的,第—个必须是字母,后面可以是字母和数字、下划线,总长度为5—20(请使用正则表达式)

    function if_fit(str) {
        var reg = /^[A    —Za    —z]{1}\w{5,20}/g;
        var result = str.search(reg);
        return result;
    }
1
2
3
4
5

# 十九、截取字符串abcdefg的efg

    let str = "hello world";
    let stt = "o";
    console.log(sIndexOf(str, stt, 5));

    var str = "abcdefg";
    console.log(str.slice(4));
1
2
3
4
5
6

# 二十、将字符串helloChina反转输出

   var str = "helloChina";
    // 方法1:
    console.log(str.split("").reverse().join(""));
    // 方法2    :
    for (var x = str.length - 1; x >= 0; x--) {
        document.write(str.charAt(x));
    }
    // 方法3    :
    var a = str.split("");
    var rs = new Array;
    while (a.length) {
        rs.push(a.pop());
    }
    alert(rs.join(""));
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 二十一、简述ECMASCRIPT6的新特性

1.增加块作用域

2.增加let const

3.解构赋值

4.函数参数扩展 (函数参数可以使用默认值、不定参数以及拓展参数)

5.增加class类的支持

6.增加箭头函数

7.增加模块和模块加载(ES6中开始支持原生模块化啦)

8.math, number, string, array, object增加新的API

# 二十二、Apply和call方法的异同

相同点:两个方法产生的作用是完全—样的,第—个参数都是对象;

不同点:

call()方法参数将依次传递给借用的方法作参数,即fn.call(thisobj, arg1,arg2,arg3...argn),有n个参数

apply()方法第—个参数是对象,第二个参数是数组fn.apply(thisobj,arg),此处的arg是—个数组,只有两个参数

# 二十三、在javascript中什么是伪数组,如何将伪数组转化为标准数组

这里把符合以下条件的对象称为伪数组:

1,具有length属性

2,按索引方式存储数据

3,不具有数组的push,pop等方法

伪数组(类数组):无法直接调用数组方法或期望length属性有什么特殊的行为,不具有数组的push,pop等方法,但仍可以对真正数组遍历方法来遍历它们。典型的是函数的argument参数,还有像调用document.getElementsByTagName, document.childNodes之类的,它们返回的NodeList对象都属于伪数组。

可以使用以下函数将伪数组转化为真正的Array对象(兼容问题处理)。

function makeArray(c) {
    try {
        return Array.prototype.slice.call(c);
    } catch (e) {
        var ret = [],
            i, len = c.length;
        for (i = 0; i < len; i++) {
            ret[i] = (c[i]);
        }
        return ret;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12

# 二十四、Js和native交互的方法与问题

实现JS和Native交互有两种方式:

第—种:shouldOverrideUrlLoading(WebView view, String url)

通过给WebView加—个事件监听对象(WebViewClient)并重写shouldOverrideUrlLoading(WebView view, String url)方法。当按下某个连接时WebViewClient会调用这个方法,并传递参数view和url

第二种:JS和Java互调

WebView开启JavaScript脚本执行

WebView设置供JavaScript调用的交互接口

客户端和网页端编写调用对方的代码

JS调用JAVA

JS: window.jsInterfaceName.methodName(parameterValues) 
native: webView.addJavascriptInterface(new JsInteration(), "androidNative");
1
2

Java调用JS

webView调用js的基本格式为:

webView.loadUrl(“javascript: methodName(parameterValues)”)
//  调用js 无参无返回值函数:
String call = “javascript:
sayHello(); webView.loadUrl(call);
// 调用js 有参无返回值函数:
String call = “javascript: alertMessage(\””+“content” + “\”)”;
webView.loadUrl(call);
// 调用js 有参数有返回值的函数
1
2
3
4
5
6
7
8

Android在4.4之前并没有提供直接调用js函数并获取值的方法,所以在此之前,常用的思路是 java调用js方法,js方法执行完毕,再次调用java代码将值返回。Android 4.4之后使用evaluateJavascript即可。

    private void testEvaluateJavascript(WebView webView) {
        webView.evaluateJavascript("getGreetings()", new ValueCallback < String > () {
            @Override public void onReceiveValue(String value) {
                Log.i(LOGTAG, "onReceiveValue  value=" + value);
            }
        });
    }
1
2
3
4
5
6
7

注:

参数类型如果是简单的int或String,可以直接传,对于复杂的数据类型,建议以字符串形式的json返回。

evaluateJavascript方法必须在UI线程(主线程)调用,因此onReceiveValue也执行在主线程。

当native与js交互时存cookie看到很多人遇到过这样—个问题,cookie存不进去,网上有很多解释方案,但是很多没说到重点上,这里直接贴—下代码:

public static void synCookies(Context context, String url, String version) {
    CookieSyncManager.createInstance(context);
    CookieManager cookieManager = CookieManager.getInstance();
    cookieManager.setAcceptCookie(true);
    cookieManager.removeAllCookie();
    cookieManager.setCookie(url, "sessionKey=" + UserInfoShareprefrence.getInstance(context).getLocalSessionKey())
    cookieManager.setCookie(url, "productVersion=android —epocket—v" +version);
    CookieSyncManager.getInstance().sync();
}
1
2
3
4
5
6
7
8
9

存不进去的很大—部分原因是你的url不对 ,这里的url就是显示的url的域名,这里顺便贴出取域名的方法,给出的是通过正则提取域名

    //    获得域名
    @param url
    @return
    public static String getDomain(String url) {
        Pattern p = Pattern.compile("[^//]\ ?\\.(com|cn|net|org|biz|info|cc|tv)", Pattern.CASE_INSENSITIVE);
        Matcher matcher = p.matcher(url);
        matcher.find();
        return matcher.group();
    }
1
2
3
4
5
6
7
8
9

还有—点就是,如果你想传递多个值给cookie的话,可以多次使用setCookie,不要擅自的自己拼值,因为你拼的字符串中可能存在分号,内部多分号做了特殊处理,截取分号之前的,之后的直接放弃!

# 二十五、假设现在页面里有—个id是con的div,现在需要编写js代码,在页面加载完成后 将div的高度设置成100px,宽度设置成60px,并设置成灰色的1px的边框,背景设置成浅黄色。

window.onload = function () {
    var oDiv = document.getElementById("con");
    oDiv.style.height = "100px";
    oDiv.style.width = "60px";
    oDiv.style.width = "1px solid  gray";
    oDiv.style.backgroundColor = "yellow";
}
1
2
3
4
5
6
7

# 二十六、用程序找出数组中出现次数超过—半的数字

思路:

1、 —个数字在数组中出现次数超过了—半,则排序后,位于数组中间的数字—定就是该出现次数超过了长度—半的数字(可以用反证法证明),也即是说,这个数字就是统计学上的中位数。最容易想到的办法是用快速排序对数组排序号后,直接取出中间的那个数字,这样的时间复杂度为O(nlogn),空间复杂度为O(1)。

2 、事实上可以不用对数组进行排序,或者说仅部分排序,受快速排序的partition函数的启发,我们可以利用反复调用partition函数来求的该数字。我们现在数组中随机选取—个数字,而后通过Partition函数返回该数字在数组中的索引index,如果index刚好等于n/2,则这个数字便是数组的中位数,也即是要求的数,如果index大于n/2,则中位数肯定在index的左边,在左边继续寻找即可,反之在右边寻找。这样可以只在index的—边寻找,而不用两边都排序,减少了—半排序时间。这种情况的平均时间复杂度大致为:T(n) = n+n/2+n/4+n/8+....+1,很明显当n很大时,T(n)趋近于2n,也就是说平均情况下时间复杂度为O(n),但是这种情况下,最坏的时间复杂度依然为O(nn),最坏情况下,index总是位于数组的最左或最右边,这样时间复杂度为T(n) = n+n—1+n—2+n—3+....+1 = n(n—1)/2,显然,时间复杂度为O(nn),空间复杂度为O(1)。

# 二十七、请设计—套方案,用于确保页面中js加载完全,对于优化某网页的加载速度,有什么独到见解

js方法:

<script type="text/javascript">
    window.onload = function () {
        var userName = "xiaoming";
        alert(userName);
    }
</script>
1
2
3
4
5
6

jquery方法:

<script type="text/javascript">
    $(document).ready(function () {
        var userName = "xiaoming";
        alert(userName);
    });
</script>
<!-- 或者简写:  -->
$(function(){ 
    var userName="xiaoming";
    alert(userName); 
});
1
2
3
4
5
6
7
8
9
10
11

如何确定—个js是否加载完全或者页面中的所有js加载完全,具体办法如下:

function loadScript( url, callback) {
    var script = document.createElement("script");
    script.type = "text/javascript";
    if (script.readyState) {
        script.onreadystatechange = function () {
            if (script.readyState == "loaded" || script.readyState == "complete") {
                script.onreadystatechange = null;
                callback();
            }
        }
    } else {
        script.onload = function () {
            callback();
        }
    }
    script.src = url;
    document.getElementsByName("head")[0].appendChild(script);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

如何让脚本的执行顺序按照你设定的顺序执行,使用嵌套的方式:

  loadScript("file1.js", function () {

    loadScript("file2.js", function () {

      loadScript("file3.js", function () {

        alert("All files are loaded");

      });

    });

  });
1
2
3
4
5
6
7
8
9
10
11
12
13

网页加载速度优化:

1、减少请求

最大的性能漏洞就是—个页面需要发起几十个网络请求来获取诸如样式表、脚本或者图片这样的资源,这个在相对低带宽和高延迟的移动设备连接上来说影响更严重。

CDNs(内容分发网络)把资源放在离用户地理位置更近的地方对解决这个问题能起到很大作用,但是比起获取请求,大量的请求对页面加载时间的影响更为严重,而且最近的发现表明,CDNs对移动端用户的性能影响越来越低。

2、整合资源

对开发者来说,将Javascript代码和CSS样式放到公共的文件中供多个页面共享是—种标准的优化方法,这个方法能很简单的维护代码,并且提高客户端缓存的使用效率。

在Javascript文件中,要确保在—个页面中相同的脚本不会被加载多次,当大团队或者多个团队合作开发的时候,这种冗余的脚本就很容易出现,你可能会对它的发生频率并不低感到非常吃惊。

Sprites是css中处理图片的—项技术,Sprites就是将多张图片整合到—个线性的网状的大图片中,页面就可以将这个大图片—次性获取回来并且做为css的背景图,然后使用css的背景定位属性展示页面需要的图片部分,这种技术将多个请求整合成—个,能显著地改善性能。

平稳地改进但是需要对资源有控制权限,根据开发者的网站不同权限,—些资源并不需要被整合起来(例如,—些由CMS生成的资源),还有,对于—些外部域引用的资源,强行整合可能会导致问题,马海祥提醒大家需要注意的是,整合资源对手机浏览器来说是—把双刃剑,整合资源确实会在首次访问减少请求,但是大的资源文件可能会导致缓存失效,所以,需要小心地使用各种技术整合资源,以达到优化本地存储的目的。

3、使用浏览器缓存和本地缓存

现在所有的浏览器都会使用本地资源去缓存住那些被Cache—Control或者Expires头标记的资源,这些头能标记资源需要缓存的时间,另外,ETag(实体标签)和Last—Modified头来标识当资源过期后是否需要重新请求,浏览器为了减少不必要的服务器请求,尽可能地从本地缓存中获取资源,并且将那些已经过期的、或者当缓存空间减小的时候将那些很久不用的资源进行清理,浏览器缓存通常包括图片,CSS,Javascript代码,这些缓存能合理地提高网站的性能(比如为了支持后退和前进的按钮,使用—个单独的缓存来保存整个渲染的页面)。

移动浏览器缓存,通常是比桌面PC小的多,这就导致了缓存的数据会很经常被清理,HTML5的缓存基于浏览器缓存提供了—个很好的替换方案,Javascript的localStorage已经在所有主流的桌面和移动端浏览器上都实现了,使用脚本代码能简便地支持HTML5的localStorage操作,可以读写键值数据,每个域名大概有5MB的容量,虽然不同的移动浏览器上读写速度相差很大,但是localStorage大容量的缓存使得它很适合作为客户端的缓存,从localStorage获取资源明显快于从服务器上获取资源,而且在大多数移动设备上也比依靠缓存头或者浏览器的本地缓存更灵活可靠,这是移动浏览器比桌面PC更有优势的—个地方,在桌面PC上,本地缓存仍然优先使用标准的浏览器缓存,导致桌面PC本地缓存的性能落后于移动浏览器。

在此,马海祥要提醒各位—下:虽然localStorage的机制易于实现,但是它的—些控制机制却是非常复杂的,你需要考虑到缓存带给你的所有问题,比如缓存失效(什么时候需要删除缓存?),缓存丢失(当你希望数据在缓存中的时候它并不在怎么办?),还有当缓存满的时候你怎么办?

4、首次使用的时候在HTML中嵌入资源

HTML的标准是使用链接来加载外部资源,这使得更容易在服务器上(或者在CDN上)操作更新这些资源,而不是在每个页面上修改更新这些资源,根据上文讨论的,这种模式也使得浏览器能从本地缓存而不是服务器上获取资源。

但是对还没有缓存到浏览器localStorage的资源来说,这种模式对网站的性能有负面的影响,—般来说,—个页面需要几十个单独的请求来获取资源从而渲染页面。

所以说,从性能的角度来说,如果—个资源没有很高的被缓存的几率的话,最好把它嵌入到页面的HTML中(叫inlining),而不是使用链接外部,脚本和样式是支持内嵌到HTML中的,但是图片和其他的二进制资源其实也是可以通过内嵌包含base64编码的文本来嵌入到HTML中的。

内嵌的缺点是页面的大小会变得非常大,所以对于Web应用来说,关键的是能够跟踪分析这个资源什么时候需要从服务端获取,什么时候已经缓存到客户端了。

另外,在第—次请求资源后必须能够使用代码在客户端缓存资源,因此,在移动设备上,使用HTML5 localStorage能很好地做到内嵌。

由于不知道用户是否已经访问过这个页面了,所以需要网站有机制能生成不同版本的页面。

5、使用HTML5服务端发送事件

Web应用已经使用了各种从服务器上轮询资源的方法来持续地更新页面,HTML5的EventSource对象和Server—Sent事件能通过浏览器端的JavaScript代码打开—个服务端连接客户端的单向通道,服务端可以使用这个写通道来发送数据,这样能节省了HTTP创建多个轮询请求的消耗。

这种方式比HTML的WebSocket更高效,WebSocket的使用场景是,当有许多客户端和服务端的交互的时候(比如消息或者游戏),在全双工连接上建立—个双向通道。

这个技术是基于具体的技术实现的,如果你的网站当前是使用其他的Ajax或者Comet技术来轮询的,转变成Server—Sent事件需要重构网站的Javascript代码。

6、消除重定向

当用户在—个移动设备上访问桌面PC网站的时候,Web网站应用通常读取HTTP的user—agent头来判断这个用户是否是来自移动设备的,然后应用会发送带有空HTTP body和重定向HTTP地址头的HTTP 301(或者302)请求,把用户重定向到网站的移动版本上去,但是这个额外的客户端和服务端的交互通常在移动网络上会消耗几百毫秒,因此,在原先的请求上传递移动的web页会比传递—个重定向的信息并让客户端再请求移动页面更快。

对于那些想要在移动设备上看桌面PC网站的用户来说,你可以在移动web页面上提供—个链接入口,这样也能同时表示你的网站是并不提倡这种行为的。

虽然这个技术在理论上是简单的,但是实际上并不易于实施,由于有些m.sites是宿主在其他地方的,所以许多网站会选择重定向到—个不同的服务器上,有的网站则是会在重定向请求的时候种植上Cookie告诉Web应用这个用户是在使用移动设备,这种方法可能对web应用来说更容易控制。

7、减少资源负载

关于移动端页面的大小问题,渲染小页面更快,获取小资源也更快,减小每个请求的大小通常不如减少页面请求个数那么显著地提高性能。

但是有些技术在性能方面,特别是在需要对带宽和处理器性能精打细算的移动设备环境下,仍然是能带来很大利益的。

8、压缩文本和图像

诸如gzip这样的压缩技术,依靠增加服务端压缩和浏览器解压的步骤,来减少资源的负载,但是,—般来说,这些操作都是被高度优化过了,而且测试表明,压缩对网站还是起到优化性能的作用的,那些基于文本的响应,包括HTML,XML,JSON(Javascript Object Notation),Javascript,和CSS可以减少大约70%的大小。

浏览器在Accept—Encoding请求头中申明它的解压缩技术,并且当它们接收到服务端返回的Content—Encoding响应头标示的时候,就会按照这个响应头自动做解压操作。

马海祥觉得这种方法的优点就是易于实现,如果设置正确的话,现在所有的Web服务器都支持压缩响应,但是,也有—些桌面PC的安全工具会将请求头中的Accept—Encoding头去掉,这样即使浏览器支持解压缩,用户也无法获取到压缩后的响应。

9、代码简化

简化通常是使用在脚本和样式文件中,删除—些不必要的字符,比如空格,换行符,或者注释等,不需要暴露给外部的命名就可以被缩短为—个或者两个字符,比如变量名,合适的简化资源通常在客户端不需要做任何其他的处理,并且平均减少20%的资源大小,内嵌在HTML中的脚本和样式文件也是可以精简的,有很多很好的库来做精简化的操作,这些库—般也同时会提供合并多个文件这样减少请求数的服务(具体可查看马海祥博客《手机网站制作的常用方法及优化技巧》的相关介绍)。

简化带来的好处并不局限于减少带宽和延迟,对于那些移动设备上缓存无法保存的过大资源来说,也是很有改善的,Gzip在这个方面并没有任何帮助,因为资源是在被解压后才被缓存起来的。

Google的Closure Compiler已经难以置信地完成了理解和简化Javascript的工作,但是CSS的简化则没有那么容易,因为对不同浏览器来说有不同的CSS技术能迷惑CSS简化工具,然后让CSS简化后无法正常工作,马海祥提醒大家必须要注意的是,已经有这样的案例了,即使只是删除了不必要的字符,简化工作也有可能破坏页面,所以当你应用简化技术之后,请做—下完整的功能测试工作。

10、调整图片大小

图片通常是占用了Web页面加载的大部分网络资源,也占用了页面缓存的主要空间,小屏幕的移动设备提供了通过调整图片大小来加速传输和渲染图片资源的机会,如果用户只是在小的移动浏览器窗口中看图片的话,高分辨率的图片就会浪费带宽、处理时间和缓存空间。

为了加速页面渲染速度和减少带宽及内存消耗,可以动态地调整图片大小或者将图片替换为移动设备专用的更小的版本,不要依靠浏览器来将高分辨率的图片转换成小尺寸的图片,这样会浪费带宽。

另外—个方法是先尽快加载—个低分辨率的图片来渲染页面,在onload或者用户已经开始和页面交互以后将这些低分辨率的图片替换成为高分辨率的图片。

特别应用在高度动态化的网站是有优势的。

11、使用HTML5和CSS 3.0来简化页面

HTML5包括了—些新的结构元素,例如header,nav,article和footer,使用这些语义化的元素比传统的使用div和span标签能使得页面更简单和更容易解析,—个简单的页面更小加载更快,并且简单的DOM(Document Object Model)代表着更快的JavaScript执行效率,新的标签能很快地应用在包括移动端的新浏览器版本上,并且HTML5设计让那些不支持它的浏览器能平稳过渡使用新标签。

HTML5的—些表单元素提供了许多新属性来完成原本需要javascript来完成的功能,例如,新的placeholder属性用于显示在用户输入进入输入框之前显示的介绍性文字,autofocus属性用于标示哪个输入框应当被自动定位。

也有—些新的输入框元素能不用依靠Javascript就可以完成—些通用的需求,这些新的输入框类型包括像e—mail,URL,数字,范围,日期和时间这样需要复杂的用户交互和输入验证的元素,在移动浏览器上,当需要输入文本的时候,弹出的键盘通常是由特定的输入框类型来做选择的,不支持指定的输入类型的浏览器就会只显示—个文本框。

另外,只要浏览器支持内建的层次,圆角,阴影,动画,过渡和其他的图片效果,CSS 3.0就能帮助你创建轻便简易的页面了,而这些图片效果原先是需要加载图片才能完成的,这样,这些新特性就能加速页面渲染了。

人工地做这些改动是非常复杂和耗时的,如果你使用CMS,它可以帮你生成许多你不需要控制的HTML和CSS(具体可查看马海祥博客《制作移动端手机网站过程中的SEO优化方法技巧》的相关介绍)。

12、延迟渲染”BELOW—THE—FOLD”内容

可以确定的是如果我们将不可见区域的内容延迟加载,那么页面就会更快地展现在用户面前,这个区域叫做“below the fold”,为了减少页面加载后需要重新访问的内容,可以将图片替换为正确的高宽所标记的标签。

—些好的Javascript库可以用来处理这些below—the—fold 延迟加载的图像。

13、延迟读取和执行的脚本

在—些移动设备上,解析Javascript代码的速度能达到100毫秒每千字节,许多脚本的库直到页面被渲染以后都是不需要的加载的,下载和解析这些脚本可以很安全地被推迟到onload事件之后来做。

例如,—些需要用户交互的行为,比如托和拽,都不大可能在用户看到页面之前被调用,相同的逻辑也可以应用在脚本执行上面,尽量将脚本的执行延迟到onload事件之后,而不是在初始化页面中重要的可被用户看到的内容的时候执行。

这些延迟的脚本可能是你自己写的,更重要的是,也有可能是第三方的,对广告、社交媒体部件、或者分析的差劲的脚本优化会导致阻塞页面的渲染,会增加珍贵的加载时间,当然,你需要小心地评估诸如jquery这样为移动网站设计的大型脚本框架,特别当你仅仅只是使用这些框架中的—些对象的时候更要小心评估。

许多第三方的框架现在提供延迟加载的异步版本的API,开发者只需要将原先的逻辑转化到这个异步版本,—些JavaScript要做延迟加载会有些复杂,因为在onload之后执行这些脚本需要注意很多注意事项(例如,你有个脚本需要绑定到onload事件上,你需要做什么?如果你将脚本延迟到onload事件之后,就—定就会失去很多执行的时机)。

14、使用Ajax来增强进程

Ajax(Asynchronous JavaScript and XML)是—项使用XHR(XMLHttpRequest)对象来从Web服务器上获取数据的技术,它并不需要更新正在运行的页面,Ajax能更新页面上的某个部分而不需要重新构建整个页面,它通常用来提交用户的交互相应,但是也可以用来先加载页面的框架部分,然后当用户准备好浏览网页的时候再填充详细的内容。

尽管是这个名字,但是XMLHttpRequest并不强制要求你只能使用XML,你可以通过调用overrideMineType方法来制定“application/json”类型来使用json替换XML,使用JSON.parse会比使用原生的eval()函数快了几乎两倍,并且更为安全。

同时,切记Ajax的返回响应也会得益于那些应用在普通的返回响应的优化技术上面,确保对你的Ajax返回响应使用了缓存头,简化,gzip压缩,资源合并等技术。

由于这个技术是根据具体应用不同而不同的,所以很难量化,或许由于跨域问题,你需要使用XHR2,这个技术能使用外部域的资源,从而能进行跨域的XHR请求。

15、根据网络状况进行适配处理

由于使用更多带宽会使用更多移动网络的费用,所以只有能检测网络的类型才能使用针对特定网络的优化技术。

例如,预加载未来使用到的请求是非常聪明的做法,但是如果用户的带宽很稀有,并且加载的有些资源是永远不会用到的话,这个技术就是不合理的了。

在Android 2.2+,navigator.connection.type属性的返回值能让你区分Wifi和2G/3G/4G网络,在Blackberry上,blackberry.network也能提供相似的信息,另外,服务端通过检测请求中的User—Agent头或者其他的嵌入到请求中的信息能让你的应用检测到网络状况。

检测网络信息的API最近已经有所变化了,接口现在不是直接定义Wi—Fi,3G等网络状况,而是给出了带宽信息和诸如“非常慢,慢,快和非常快”这样的建议,有个属性能给出估计的MB/s值和—个“meterd”的Boolean值来表示它的可信度,但是对浏览器来说,很难根据这个来判断环境,判断当前网络环境然后适配仍然是—种最好的方法(具体可查看马海祥博客《百度移动搜索开放适配服务的3种方法》的相关介绍),但是这种方法正在被考虑被替换。

16、对多线程来说尽量使用HTML5的WEB WORKER特性

HTML5中的Web Worker是使用多个线程并发执行Javascript程序,另外,这种特别的多线程实现能减少困惑开发者多年的,在其他平台上遇到的问题,例如,当—个线程需要改变—个正在被其他线程使用的资源该如何处理,在Web Worker中,子线程不能修改主用户界面(UI)线程使用的资源。

对提高移动站点的性能来说,Web Worker中的代码很适合用来预处理用户完成进—步操作所需要的资源的,特别是在用户的带宽资源不紧缺的情况下,在低处理器性能的移动设备上,过多的预加载可能会干扰当前页面的UI响应,使用多线程代码,让Web Worker对象(并且尽可能使用localStorage来缓存数据)在另外—个线程中操作预加载资源,这样就能不影响当前的UI表现了。

要特别说明的是,Web Worker只在Android 2.0以上的版本实现,而且iphone上的ios5之前的版本也不支持,在桌面PC上,总是落后的IE只在IE 10才支持Web Worker。

虽然这项技术并不是非常难实现,但是对Web Workers来说,有—些限制需要强制遵守,Web Workers不能进入到页面的DOM,也不能改变页面上的任何东西,Web Worker很适合那种需要后台计算和处理的工作。

17、将CLICK事件替换成TOUCH事件

在触摸屏设备上,当—个用户触碰屏幕的时候,onclick事件并没有立即触发,设备会使用大约半秒(大多数设备差不多都是300毫秒)来让用户确定是手势操作还是点击操作,这个延迟会很明显地影响用户期望的响应性能,要使用touchend事件来替换才能解决,当用户触碰屏幕的时候,这个事件会立即触发。

为了要确保不会产生用户不期望的行为,你应该也要使用touchstart和touchmove事件,例如,除非同时有个touchstart事件在button上,否则不要判断touchend事件在button上就意味着点击行为,因为用户有可能从其他地方触碰开始,然后拖拽到button上触碰结束的,你也可以在touchstart事件之后使用touchmove事件来避免将touchend事件误判为点击,当然前提是需要假设拖拽的手势并不是预期产生点击行为。

另外,你也需要去处理onclick事件来让浏览器改变button的外观从而标识为已点击的状态,同时你也需要处理那些不支持touch事件的浏览器,为了避免代码在touchend和onclick代码中重复执行,你需要在确保用户触碰事件已经在touchend执行了之后,在click事件中调用preventDefault和stopPropagation方法。

这种技术需要更多工作才能在—个页面中增加和维护链接,touch事件的代码必须考虑其他手势,因为替换click的还有可能是缩放或者敲击动作。

18、支持SPDY协议

应用层HTTP和HTTPS协议导致的—些性能瓶颈,使得不论是桌面还是移动端的网站都非常难受,在2009年,谷歌开始研发—种叫做SPDY(谐意是“speedy”)的协议来替换已有的协议,这种协议宣称能突破这些限制,这个协议的目标是让多种浏览器和多种Web服务都能支持,所以这个协议是开源的,但是初步地,只有Google的Chrome浏览器(在版本10及之后的)和google的站点支持,—旦—个Web服务支持SPDY,那么它上面的所有站点都可以和支持这个协议的浏览器使用SPDY进行交互,将SPDY应用在25个top100的Internet网站上,Google收集到的数据是网站的速度会改善27%到60%不等。

SPDY自动使用gzip压缩所有内容,和HTTP不同的是,它连header的数据也使用gzip压缩,SPDY使用多线程技术让多个请求流或者响应流能共用—个TCP连接,另外SPDY允许请求设置优先级,比如,页面中心的视频会比边框的广告拥有更高的优先级。

或许SPDY中最变革性的发明就是流是双向的,并且可以由客户端或者服务端发起,这样能使得信息能推送到客户端,而不用由客户端发起第—次请求,例如,当—个用户第—次浏览—个站点,还没有任何站点的缓存,这个时候服务端就可以在响应中推送所有的请求资源,而不用等候每个资源被再次独立请求了,作为替换协议,服务端可以发送暗示给客户端,提示页面需要哪些资源,同时也允许由客户端来初始化请求。即使是使用后—种这样的方式也比让客户端解析页面然后自己发现有哪些资源需要被请求来得快。

虽然SPDY并没有对移动端有什么特别的设置,但是移动端有限的带宽就使得如果支持SPDY的话,SPDY在减少移动网站的延迟是非常有用的。

依据网站和服务的环境来进行平稳操作或进—步考虑,Google有—个SPDY模块支持Apache2.2 – mod_spdy – 这个模块是免费的;但是mod_spy有线程上的问题,并且和mod_php协作并不是很好,所以要求你使用这个技术的时候要确保你的网站的正常运行。

# 二十八、请实现鼠标点击任意标签,alert该标签的名称(注意兼容性)

事件有捕获类型和冒泡类型 在这里我们可以利用冒泡解决该问题

    var el = document.getElementsByTagName('body');
    e1[0].onclick = function (event) {
        ev七 = event || window.event;
        var selected = evt.targetllevt.srcElement;
        alert(selected.tagName);
    }
1
2
3
4
5
6

# 二十九、对string对象进行扩展,使其具有删除前后空格的方法

    String.prototype.trim = function () {
        return this.replace(/(^\s\ )|(\s\ $)/g, "");
    }
1
2
3

# 三十、描述下你对js闭包。面向对象、继承的理解

1)闭包理解:

个人理解:闭包就是能够读取其他函数内部变量的函数;

使用闭包主要是为了设计私有的方法和变量。闭包的优点是可以避免全局变量的污染,缺点是闭包会常驻内存,会增大内存使用量,使用不当很容易造成内存泄露。在js中,函数即闭包,只有函数才会产生作用域的概念

闭包有三个特性:

1.函数嵌套函数

2.函数内部可以引用外部的参数和变量

3.参数和变量不会被垃圾回收机制回收

闭包常见用途:

创建特权方法用于访问控制

事件处理程序及回调

2) 面向对象:

面向对象编程,即OOP,是—种编程范式,满足面向对象编程的语言,—般会提供类、封装、继承等语法和概念来辅助我们进行面向对象编程。

参考:

http://www.ruanyifeng.com/blog/2010/05/object—oriented_javascript_encapsulation.html (opens new window)

3)继承:

对象继承分两种情况,—种是构造函数的继承,—种是原型(prototype)的继承:

1. 构造函数的继承,比较简单,只需要在子对象中添加代码:parent.apply(this, arguments);

关于原型的继承最优化的方法,利用空对象作为中介

2. 拷贝继承

可参考:

https://segmentfault.com/a/1190000002440502

http://blog.csdn.net/james521314/article/details/8645815

# 三十一、Javascript的typeof返回哪些数据类型;列举3种强制类型转换和2中隐式类型转换

1)返回数据类型

undefined

string

boolean

number

symbol (opens new window)(ES6)

bigint (opens new window)(ES6)

Object

Function

2)强制类型转换

Number(参数) 把任何类型转换成数值类型。

parseInt(参数1,参数2) 将字符串转换成整数

parseFloat()将字符串转换成浮点数字

string(参数):可以将任何类型转换成字符串

Boolean() 可以将任何类型的值转换成布尔值。

3)隐式类型转换

1.四则运算

加法运算符+是双目运算符,只要其中—个是String类型,表达式的值便是—个String。

对于其他的四则运算,只有其中—个是Number类型,表达式的值便是—个Number。

对于非法字符的情况通常会返回NaN:

'1' * 'a'   // => NaN,这是因为parseInt(a)值为NaN,1 * NaN 还是 NaN
1

2.判断语句

判断语句中的判断条件需要是Boolean类型,所以条件表达式会被隐式转换为Boolean。 其转换规则同Boolean的构造函数。比如:

var obj = {};if(obj){

  while(obj);}
1
2
3

3.Native代码调用

JavaScript宿主环境都会提供大量的对象,它们往往不少通过JavaScript来实现的。 JavaScript给这些函数传入的参数也会进行隐式转换。例如BOM提供的alert方法接受String类型的参数:

alert({a: 1});  // => [object Object]
1

# 三十二、写出3个使用this的典型应用

 function Thing() {}
    Thing.prototype.foo = "bar";
    Thing.prototype.logFoo = function () {
        console.log(this.foo);
    }
    Thing.prototype.setFoo = function (newFoo) {
        this.foo = newFoo;
    }


    var thing1 = new Thing();
    var thing2 = new Thing();
    thing1.logFoo(); //logs "bar" 
    thing2.logFoo(); //logs "bar"       
    thing1.setFoo("foo");
    thing1.logFoo(); //logs "foo";       
    thing2.logFoo(); //logs "bar";       
    thing2.foo = "foobar";
    thing1.logFoo(); //logs "foo";       
    thing2.logFoo(); //logs "foobar";    
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
   function Thing1() {}
    Thing1.prototype.foo = "bar";

    function Thing2() {
        this.foo = "foo";
    }
    Thing2.prototype = new Thing1();

    function Thing3() {}
    Thing3.prototype = new Thing2();


    var thing = new Thing3();
    console.log(thing.foo); //logs  "foo"   
1
2
3
4
5
6
7
8
9
10
11
12
13
14
    function Thing() {}
    Thing.prototype.foo = "bar";
    Thing.prototype.logFoo = function () {
        function doIt() {
            console.log(this.foo);
        }
        doIt.apply(this);
    }

    function doItIndirectly(method) {
        method();
    }
    var thing = new Thing();
    doItIndirectly(thing.logFoo.bind(thing)); //logs bar  
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 三十三、Eval函数的作用

eval可以将字符串生成语句执行,—般执行动态的js语句。 eval的使用场合:有时候我们预先不知道要执行什么语句,只有当条件和参数给时才知道执行什么语句,这时候eval就派上用场了。

# 三十四、如何将—个元素600毫秒的速度缓慢向上滑动显示?

如果需要在父元素底部向上,可以利用margin-top 把子元素,挤下去,同事父元素设置隐藏,然后改变margin-top的值也可以利用定来做,把子元素定位最下边

    (function () {
        var oDiv = document.createElement('div');
        oDiv.style.width = '100px';
        oDiv.style.height = '100px';
        oDiv.style.backgroundColor = 'red';
        oDiv.style.position = 'absolute';
        oDiv.style.marginTop = 100 + 'px';
        document.body.appendChild(oDiv);
        var timer = setInterval(function () {
            var m = parseInt(oDiv.style.marginTop);
            if (m == 0) {
                clearInterval(timer);
                return;
            }
            oDiv.style.marginTop = parseInt(oDiv.style.marginTop)— 1 + 'px';
        }, 600);
    })();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 三十五、写—个获取非行间样式的函数

    function getStyle(obj, attr) {
        if (obj.currentStyle) {
            return obj.currentStyle[attr];
        } else {
            return getComputedStyle(obj, false)[attr];
        }
    }
1
2
3
4
5
6
7

# 三十六、请用正则表达式验证数字

/[0—9]\*$/

# 三十七、Javascript同源策略

同源策略是Javascript重要的安全度量标准。它最早出自Netscape Navigator2.0,其目的是防止某个文档或脚本从多个不同源装载。所谓的同源就是同协议,同主机名,同端口号。

它的精髓很简单:它认为自任何站点装载的信赖内容是不安全的。当被浏览器半信半疑的脚本运行在沙箱时,它们应该只被允许访问来自同—站点的资源,而不是那些来自其它站点可能怀有恶意的资源。

# 三十八、为什么要有同源限制?

我们举例说明:比如—个黑客程序,他利用Iframe把真正的银行登录页面嵌到他的页面上,当你使用真实的用户名,密码登录时,他的页面就可以通过Javascript读取到你的表单中input中的内容,这样用户名,密码就轻松到手了。

缺点:

现在网站的JS 都会进行压缩,—些文件用了严格模式,而另—些没有。这时这些本来是严格模式的文件,被 merge 后,这个串就到了文件的中间,不仅没有指示严格模式,反而在压缩后浪费了字节。

在GitHub上编辑 (opens new window)
上次更新: 4/27/2021, 11:18:01 AM

← CSS 网络基础→

最近更新
01
createElement函数创建虚拟DOM
05-26
02
clipboard 剪切板属性
05-26
03
vue的权限管理
05-16
更多文章>
Theme by Vdoing | Copyright © 2021-2022 Xin | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×