一。跨域问题解决方案:
- 协议,域名,端口号三者之一不同即为跨域
- 前端通信方式:Ajax,WebSocket,CORS
- xmlhttp.readyState有5种请求状态,从0-4发生变化
1XX:信息性状态码,接收的请求正在处理
2XX:成功状态码,请求正常处理完毕
3XX:重定向状态码,需要进行附加操作以完成请求
4XX:客户端错误状态码,服务器无法处理请求
5XX:服务器错误状态码,服务器处理请求出错 - xmlhttp.status,响应状态码:
200-OK
403-服务器拒绝请求
404-服务器找不到请求的网页
408-服务器请求发生超时
500-服务器内部出现错误,无法完成请求 - 跨域通信的几种方式:
1.JSONP(只支持GET请求,请求方式为jsonp)
<script type="text/javascript">
$.ajax({
url:'url',
type:'get',
dataType:'jsonp',
success:function(res){}
});
</script>
2.CORS(只需服务器端设置Access-Control-Allow-Origin,若带cookie,则 前后端都要设置)
3.document.domain+iframe(只有在主域相同才能使用该方法)
4.HTML5的window.postMessage方法
5.window.name
二。处理异步请求的方法:
fetch是为了解决ajax的回调地狱而生的链式调用方法,使用fetch方法返回一个Promise对象。
三。js的堆栈和拷贝
- 栈(stack)是一种特殊的线性表,特殊性在于限定插入和删除数据元素的操作只在线性表的一端进行,后进先出(LIFO)
- 基本类型是存放在栈内存的简单数据段,数据大小确定,内存空间大小可以分配,5种基本类型:Undefined,Null,Boolean,Number,String
- 引用类型存放在堆内存中的对象,当我们要访问引用类型(如函数,对象,数组)的值时,首先从栈中获得对象的地址指针,然后从堆内存中取得所需的数据。
- 深拷贝:
1.递归思想
function deepClone(obj1,obj2){
var obj2 = obj2 || {};
for(var key in obj1){
if(typeof obj1[key] === "object"){
obj2[key] = (obj1[key].constructor === Array) ? [] : {};
deepClone(obj1[key],obj2[key]);
}else{
obj2[key] = obj1[key];
}
}
return obj2;
}
let obj1 = [2,3,4];
let obj2 = [];
obj2 = deepClone(obj1,obj2);
obj1[0] = 1;
console.log(obj1,obj2);
(3) [1, 3, 4] (3) [2, 3, 4]
2.jQuery的$.extend(true,目标对象,被合并的对象)
let a = [0,1,2];
let b = $.extend(true,[],a);
a[0]=10;
console.log(a,b);
[10, 1, 2] [0, 1, 2]
3.JSON对象的parse和stringify
function deepClone(obj){
let _obj = JSON.stringify(obj);
let objClone = JSON.parse(_obj);
return objClone;
}
let a = [0,1,[2,3,4]];
let b = deepClone(a);
a[2][0] = 10;
console.log(a,b);
4.对于数组,ES6有两种新方法Array.from(要复制的数组) ,…
let arr1 = [2,3,[6,6,6]];
let arr2 = Array.from(arr1);
arr1[2][0]=10;
console.log(arr1,arr2);
[10,6,6] [10,6,6]
let arr1 = [0,1,[6,6,6]];
let arr2 = [...arr1];
arr1[2][0] = 10;
console.log(arr1,arr2);
[10,6,6] [10,6,6]
证明Array.from和…的第二级属性还是会受影响,不算深拷贝
四。js面向对象之继承
- 原型链继承
1.定义了Father和Son两个函数,原型链继承核心是:Son.prototype = new Father()将父类的一个实例赋值给子类的原型,这样子类就能够使用父类实例所拥有的方法和父类原型中的方法了;也就是利用原型链让一个引用类型继承另一个应用类型的方法和属性。
function Father(name){
this.val = true;
this.name = name;
}
Father.prototype.sayName = function(){
console.log('name is '+this.name);
}
var father = new Father('father');
father.sayName();//name is father
function Son(name){
this.name = name;
}
Son.prototype = new Father();
var son = new Son("son");
son.sayName();//name is son
console.log(son.val); //true
2.问题是子类的所有实例都共享了父类的引用属性;另一个问题是在创建子类的实例的时候,不能向父类的构造函数传递参数。
function Super(){
this.friends = ["peng","gao"];
}
function Sub(){
//...
}
Sub.prototype = new Super();
var sub1 = new Sub();
var sub2 = new Sub();
sub1.friends.push("du");
console.log(sub2.friends); //["peng", "gao", "du"]
- 构造函数继承(call,apply)
构造函数模式解决了原型链继承中出现的两个问题,可以传递参数,也没有了子类共享父类引用属性的问题;但这种模式也有问题,问题就是在父类原型中定义的方法对子类是不可见的
function Father(){
this.val = true;
this.arr = [1,3];
}
function Son(){
Father.call(this);
}
var son = new Son();
console.log(son.val); //true
son.arr.push(10);
console.log(son.arr); //[1, 3, 10]
function teacher(name,age){
this.name = name;
this.age = age;
this.sayhi = function(){
alert('name:'+name+", age:"+age);
}
}
function student(){
var args = arguments;
teacher.call(this,args[0],args[1]);
// teacher.apply(this,arguments);
}
var teacher1 = new teacher('xiaoming',23);
teacher1.sayhi();
var student1 = new student('xiaolan',12);
student1.sayhi();
// alert: name:xiaoming, age:23
// alert: name:xiaolan, age:12
- 组合继承
function teacher(name,age){
this.name = name;
this.age = age;
}
teacher.prototype.sayName = function(){
console.log('name:'+this.name);
}
teacher.prototype.sayAge = function(){
console.log('age:'+this.age);
}
function student(){
var args = arguments;
teacher.call(this,args[0],args[1]);
}
student.prototype = new teacher();
var student1 = new student('xiaolin',23);
student1.sayName();
student1.sayAge();
// name:xiaolin
// age:23
五。javascript相关程序计算题
- 判断一个字符串中出现次数最多的字符,统计次数
var str = 'asdfaaaaaaaaaa';
var json = {};
for(var i = 0;i<str.length;i++){
if(!json[str.charAt(i)]){
json[str.charAt(i)] = 1;
}else{
json[str.charAt(i)]++;
}
}
console.log(json);//{a:11,d:1,f:1,s:1}
console.log(str.charAt(1))//s
//json[s]=1
//json[a]=9
var iMax = 0;
var iIndex = '';
for(var i in json){
if(json[i]>iMax){
iMax = json[i];
iIndex = i;
}
}
console.log('出现次数最多的是:'+iIndex+'出现'+iMax+'次');//出现次数最多的是:a出现11次
- 把url地址的参数分解为json串
function showWindowHref(){
var sHref = 'http://www.runoob.com/jquery/misc-trim.html?channelid=12333&name=xiaoming&age=23';
var args = sHref.split('?');
if(args[0] == sHref){
return "";
}
var arr = args[1].split('&');
var obj = {};
for(var i=0;i<arr.length;i++){
var arg = arr[i].split('=');
obj[arg[0]] = arg[1];
}
return obj;
}
console.log(showWindowHref());//{channelid: "12333", name: "xiaoming", age: "23"}
- 编写一个方法,去掉一个数组的重复元素
1.方法一:
var arr = [2,2,1,5,6,7,7,7,8,8];
var obj = {};
var tmp = [];
for(var i=0,len=arr.length;i<len;i++){
if(!obj[arr[i]]){
obj[arr[i]] = 1;
tmp.push(arr[i]);
}
}
console.log(tmp);//[2, 1, 5, 6, 7, 8]
console.log(obj);//{1: 1, 2: 1, 5: 1, 6: 1, 7: 1, 8: 1}
2.方法二:
var arr = [2,3,4,4,5,2,3,6],
arr2 = [];
for(var i = 0;i< arr.length;i++){
if(arr2.indexOf(arr[i]) < 0){
arr2.push(arr[i]);
}
}
console.log(arr2);//[2, 3, 4, 5, 6]
六。Array相关的属性和方法
- 如何判断是数组
1.arr instanceof Array
2.typeof arr == “object” && arr.constructor == Array - Array对象属性:
1.constructor 返回对创建此对象的数组的引用
2.length 设置或者返回数组元素的数目
3.prototype 向数组添加属性和方法 - Array对象方法:
1.concat() 连接两个或多个数组,并返回结果
2.join() 把数组的所有元素放到一个字符串,元素通过指定的分隔符分割
3.push() 向数组末尾添加一个或者多个元素,并返回新的长度
4.pop() 删除并返回数组的最后一个元素
5.unshift() 向数组开头添加一个或者多个元素,并返回新的长度
6.shift() 删除并返回数组的最后一个元素
7.reverse() 颠倒数组中元素的顺序
8.slice() 从已有数组中返回选定的元素
9.splice() 删除元素,并向数组添加新元素
10.sort() 对数组元素排序
11.toString() 把数组转换为字符串,并返回结果