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();
什么是闭包(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>
执行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
随着浏览器的升级,大部分浏览器对于闭包引起的循环引用问题都能够顺利解决。但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());
编写一个方法求一个字符串的字节长度,假设:一个英文字符占用一个字节,一个中文字符占用两个字节
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) }