JavaScript基础(一)

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程序创建的对象。自定义的对象也是宿主对象。

 说几条javasprit的基本规范

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

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

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

4.不要使用全局函数。

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

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

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

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

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

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

 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();
View Code

  什么是闭包(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>

 
View Code

执行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
View Code

随着浏览器的升级,大部分浏览器对于闭包引起的循环引用问题都能够顺利解决。但IE9之前使用非本地JavaScript对象实现DOM对象,对于Javascript对象跟DOM对象使用不同的垃圾收集器。所以闭包在IE的这些版本中发生循环引用时便会导致内存泄露。

参考:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Closures

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

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

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

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

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

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

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

  用原型链继承的方式写一个类和子类

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());
View Code

 编写一个方法求一个字符串的字节长度,假设:一个英文字符占用一个字节,一个中文字符占用两个字节

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)
}

 简单概括浏览器事件模型,如何获得资源dom节点

在各种浏览器中存在三种事件模型:原始事件模型( original event model),DOM2事件模型,IE事件模型.其中原始的事件模型被所有浏览器所支持,而DOM2中所定义的事件模型目前被除了IE以外的所有主流浏览器支持。

浏览器事件模型分为三个阶段

  1、捕获阶段

  2、目标阶段

  3、冒泡阶段

Dom节点获取方法:

1.通过id属性获取 document.getElementById()

2.通过name属性获取 document.getElementsByName()

3.通过标签名获取 document.getElementsByTagName()

4.通过class属性获取 document.getElementsByClassName()

5.原生js中的querySelector 和 querySelectorAll方法也同样可以获取到相应的dom节点,相似于jquery,但比jq更快

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

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

  截取字符串abcdefg的efg

var str="abcdefg";

console.log(str.slice(4));

 将字符串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(""));

简述ECMASCRIPT6的新特性

1.增加块作用域

2.增加let const

3.解构赋值

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

5.增加class类的支持

6.增加箭头函数

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

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

  在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;
    }
}

  此外还有,ES6中数组的新方法 from()

function test(){
    var arg = Array.from(arguments);
    arg.push(5);
    console.log(arg);//1,2,3,4,5

}
test(1,2,3,4);

es6中,展开操作符对于实现了 Iterator 接口的对象转为真正的数组

任何 Iterator 接口的对象,都可以用扩展运算符转为真正的数组。

let nodeList = document.querySelectorAll('div');
let array = [...nodeList];

上面代码中,querySelectorAll方法返回的是一个nodeList对象。它不是数组,而是一个类似数组的对象。这时,扩展运算符可以将其转为真正的数组,原因就在于NodeList对象实现了 Iterator 。

对于那些没有部署 Iterator 接口的类似数组的对象,扩展运算符就无法将其转为真正的数组。

let arrayLike = {
  '0': 'a',
  '1': 'b',
  '2': 'c',
  length: 3
};

// TypeError: Cannot spread non-iterable object.
let arr = [...arrayLike];

上面代码中,arrayLike是一个类似数组的对象,但是没有部署 Iterator 接口,扩展运算符就会报错。这时,可以改为使用Array.from方法将arrayLike转为真正的数组。

jquery中的,jQuery.toArray()方法

alert($('li').toArray());

jquery中,jQuery.makeArray(obj)

将类数组对象转换为数组对象。

类数组对象有 length 属性,其成员索引为 0 至 length - 1。实际中此函数在 jQuery 中将自动使用而无需特意转换。

var arr = jQuery.makeArray(document.getElementsByTagName("div"));

如何实现浏览器内多个标签页之间的通信?

通过WebSocket或SharedWorker把客户端和服务器端建立socket连接,从而实现通信;也可以调用localstorge、cookies等本地存储方法。

假设现在页面里有一个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";
}

 

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

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

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

1)闭包理解:

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

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

闭包有三个特性:

1.函数嵌套函数

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

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

闭包常见用途:

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

事件处理程序及回调

2) 面向对象:

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

 参考:

http://www.ruanyifeng.com/blog/2010/05/object一oriented_javascript_encapsulation.html

3)继承:

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

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

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

2.        拷贝继承

可参考:

https://segmentfault.com/a/1190000002440502

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

javascript 进制转换(2进制、8进制、10进制、16进制之间的转换)? 

//十进制转其他  
var x=110;  
alert(x);  
alert(x.toString(8));  
alert(x.toString(32));  
alert(x.toString(16));  
//其他转十进制  
var x='110';  
alert(parseInt(x,2));  
alert(parseInt(x,8));  
alert(parseInt(x,16));  
//其他转其他  
//先用parseInt转成十进制再用toString转到目标进制  
alert(String.fromCharCode(parseInt(141,8)))  
alert(parseInt('ff',16).toString(2));   

 setInterval 与 setTimeout ?

JavaScript是单线程的语言,但使用setTimout(延时器) 和 setInterval(定时器)可以模拟多线程

setInterval(function(){
  console.log(111)
},1000)
setTimeout(function(){
  console.log(222)
},1000)

在JavaScript代码执行期间,遇到setTimeout 和 setInterval 会将其依次放置到执行栈中,当其他代码执行完后才开始执行执行栈中的“任务”,因此当碰到

... ...
setTimeout(function(){}, 0)
... ...

相当于将其中的任务放置到JavaScript代码最后执行,但有一点要注意的是间隔的时间最小为10ms,但一般情况下这不是最小值,因为计算机的执行频率一般为60/s,所以最小值为1000/60 = 16.66666...。此外还有使用setInterval时其中的“任务”也是一个费时的过程则表现出的现象并不是我们想要的,如:假设我们想要一个任务每隔10s运行一次,而这个任务每次运行可能需要9秒,这样表现出来的可能就是每一秒就运行了这个任务;更有甚者,假设我们想要一个任务每隔10s运行一次,而这个任务每次运行的过程可能要11秒或者20s...,,这时候setInterval就会在执行栈进行累积,随后连续触发,为此我们可以使用setTimeout来实现我们想要的结果:

!function(){
    console.log("这是一个需要9秒的任务")
    setTimeout(arguments.callee,10000)
}()

 面试题:

for(var i=0;i<3;i++){
    setTimeout(function(){
        console.log(i--) // 3 2 1
    },0)
} 

 

posted @ 2017-11-21 21:53  fanlinqiang  阅读(306)  评论(0编辑  收藏  举报