概述
1,jquery中的ajax(数据请求)
第一步:
》1:引入jquery.js 或者jquery.min.js,普通引入
<script src='jquery.js'></script>
》2: 如果是项目脚手架引入jquery(比如react),需要:
npm i jquery -S
在哪个地方使用jQuery就在什么地方引入jQuery
import $ from 'jquery'
第二步:固定格式套用请求如下(延伸概念什么是同步异步)
<script> $.ajax({ type: "post", dataType: "json", async:false,//默认设置为true,所有请求均为异步。如果需要发送同步请求,请将此选项设置为false url: '/Resources/GetList.ashx', data: {username:'zhangsan',password:'123456'}, success: function (data) { if (data.code == 0 ) { $("#anhtml").html(data.str); } } }); </script>
延伸作业:axios的请求(get,post有什么不同,qs的作用,如何封装调用,如何拦截等)
2,函数式继承
①:call 和apply概念区别
每个函数都包含两个非继承而来的方法:call()方法和apply()方法。
相同点:这两个方法的作用是一样的。都是在特定的作用域中调用函数,等于设置函数体内this对象的值,以扩充函数赖以运行的作用域。一般来说,this总是指向调用某个方法的对象,但是使用call()和apply()方法时,就会改变this的指向。(总结,扩展作用域,改变this指向)
不同点:
apply()方法 接收两个参数,一个是函数运行的作用域(this),另一个是参数数组。
** 语法:**apply([thisObj [,argArray] ]);
,调用一个对象的一个方法,2另一个对象替换当前对象。
** 说明:**如果argArray不是一个有效数组或不是arguments对象,那么将导致一个 TypeError,如果没有提供argArray和thisObj任何一个参数,那么Global对象将用作thisObj。
call()方法 第一个参数和apply()方法的一样,但是传递给函数的参数必须列举出来。
** 语法:**call(thisObj, arg1, arg2, arg3, arg4);
,应用某一对象的一个方法,用另一个对象替换当前对象。
** 说明:** call方法可以用来代替另一个对象调用一个方法,call方法可以将一个函数的对象上下文从初始的上 下文改变为thisObj指定的新对象,如果没有提供thisObj参数,那么Global对象被用于thisObj。
1》call()方法使用示例:
//例1 <script> window.color = 'red'; document.color = 'yellow'; var s1 = {color: 'blue' }; function changeColor(){ console.log(this.color); } changeColor.call(); //red (默认传递参数) changeColor.call(window); //red changeColor.call(document); //yellow changeColor.call(this); //red changeColor.call(s1); //blue </script> //例2 var Pet = { words : '...', speak : function (say) { console.log(say + ''+ this.words) } } Pet.speak('Speak'); // 结果:Speak... var Dog = { words:'Wang' } //将this的指向改变成了Dog Pet.speak.call(Dog, 'Speak'); //结果: SpeakWang
2》apply示例:
//例1 <script> window.number = 'one'; document.number = 'two'; var s1 = {number: 'three' }; function changeColor(){ console.log(this.number); } changeColor.apply(); //one (默认传参) changeColor.apply(window); //one changeColor.apply(document); //two changeColor.apply(this); //one changeColor.apply(s1); //three </script> //例2 function Pet(words){ this.words = words; this.speak = function () { console.log( this.words) } } function Dog(words){ //Pet.call(this, words); //结果: Wang Pet.apply(this, arguments); //结果: Wang } var dog = new Dog('Wang'); dog.speak();
3》不同点示例:
function add(c,d){ return this.a + this.b + c + d; } var s = {a:1, b:2}; console.log(add.call(s,3,4)); // 1+2+3+4 = 10 console.log(add.apply(s,[5,6])); // 1+2+5+6 = 14
②:ES5 构造函数继承
function Parent() { this.name = 'parent'; this.colors = ['black', 'yellow', 'red'] } function Child() { Parent.call(this); this.type = 'child'; } Parent.prototype.age = 12; Parent.prototype.say = function(){ console.log('hello'); } var q1 = new Child(); console.log(q1.name); // parent console.log(q1.colors);// [ 'black', 'yellow', 'red' ] console.log(q1); //Child {name: "parent", colors: Array(3), type: "child"} console.log(q1.age); // undefined console.log(q1.say()); // 报错 TypeError: q1.say is not a function
综上总结:Child无法继承Parent的原型对象,并没有真正的实现继承(部分继承)
③:ES5 原型链继承
function Parent() { this.name = 'parent'; this.colors = ['black', 'yellow', 'red'] } function Child() { this.type = 'child'; } Parent.prototype.age = 12; Parent.prototype.say = function(){ console.log('hello'); } Child.prototype = new Parent(); var q1 = new Child(); console.log(q1); console.log(q1.age); // 12 console.log(q1.say()); // hello undefined(因为方法没返回)) var q2 = new Child();//具有相同的原型,所以不分彼此 q1.colors.push('pink'); console.log(q1.colors) // [ 'black', 'yellow', 'red', 'pink' ] console.log(q2.colors) // [ 'black', 'yellow', 'red', 'pink' ]
综上:被new出来的实例不能隔离(因为具有相同的原型,所以没有独立性,一个被改其他的跟着被改动)
④:组合继承(构造函数和原型链继承)
function Parent() { this.name = 'parent'; this.colors = ['black', 'yellow', 'red'] } function Child() { Parent.call(this); this.type = 'child'; } Parent.prototype.age = 12; Parent.prototype.say = function(){ console.log('hello'); } //Child.prototype = new Parent();//也可以用这种方式实现,但是父类的构造函数被执行了两次, //第一次是Child.prototype = new Parent(), //第二次是在实例化的时候,这是没有必要的。(优化如下) Child.prototype = Object.create(Parent.prototype); Child.prototype.constructor = Child; var q1 = new Child(); var q2 = new Child(); q1.colors.push('pink'); console.log(q1.colors) // [ 'black', 'yellow', 'red','pink'] console.log(q2.colors) // [ 'black', 'yellow', 'red', ]
综上:Object.create是一种创建对象的方式,它会创建一个中间对象(或者叫寄生组合继承)
⑤:ES6 class继承
// es6的继承 class Parent { constructor(name='dfd') { this.name = name; } say() { console.log('parent has say method. ' + this.name); } } class Child extends Parent { constructor(name) { super(name); } fly() { console.log('chid can fly...'); } } var p = new Child('tom'); p.say();//parent has say method. tom p.fly();//chid can fly...
3,this指向问题
参考链接:this - JavaScript | MDN
1》全局环境:
无论是否在严格模式下,在全局执行环境中(在任何函数体外部)this
都指向全局对象。
// 在浏览器中, window 对象同时也是全局对象: console.log(this === window); // true a = 37; console.log(window.a); // 37 this.b = "MDN"; console.log(window.b) // "MDN" console.log(b) // "MDN"
2》函数(运行内)环境
在函数内部,this
的值取决于函数被调用的方式。
情况<1>:普通函数
因为下面的代码不在严格模式下,且 this
的值不是由该调用设置的,所以 this
的值默认指向全局对象
function f1(){ return this; } //在浏览器中: f1() === window; //在浏览器中,全局对象是window //在Node中: f1() === global;
情况<2>:严格模式
严格模式下,this将保持他进入执行环境时的值,所以下面的
this将会默认为
undefined`。
function f2(){ "use strict"; // 这里是严格模式 return this; } f2() === undefined; // true
所以,在严格模式下,如果 this
没有被执行环境(execution context)定义,那它将保持为 undefined
。
注释:
<!--在第二个例子中,`this`的确应该是[undefined](https://developer.mozilla.org/zh-CN/docs/Glossary/undefined),因为`f2`是被直接调用的,而不是作为对象的属性或方法调用的(如 `window.f2()`)。有一些浏览器最初在支持[严格模式](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Strict_mode)时没有正确实现这个功能,于是它们错误地返回了`window`对象。-->
情况<3>:继承改变this指向(call,apply)
如果要想把 this
的值从一个环境传到另一个,就要用 call
或者apply
方法。
// 将一个对象作为call和apply的第一个参数,this会被绑定到这个对象。 var obj = {a: 'Custom'}; // 这个属性是在global对象定义的。 var a = 'Global'; function whatsThis(arg) { return this.a; // this的值取决于函数的调用方式 } whatsThis(); // 'Global' whatsThis.call(obj); // 'Custom' whatsThis.apply(obj); // 'Custom'
当一个函数在其主体中使用 this
关键字时,可以通过使用函数继承自Function.prototype
的 call
或 apply
方法将 this
值绑定到调用中的特定对象。
3》bind方法
ECMAScript 5 引入了 Function.prototype.bind
。调用f.bind(someObject)
会创建一个与f
具有相同函数体和作用域的函数,但是在这个新函数中,this
将永久地被绑定到了bind
的第一个参数,无论这个函数是如何被调用的。
function f(){ return this.a; } var g = f.bind({a:"azerty"}); console.log(g()); // azerty var h = g.bind({a:'yoo'}); // bind只生效一次! console.log(h()); // azerty var o = {a:37, f:f, g:g, h:h}; console.log(o.f(), o.g(), o.h()); // 37, azerty, azerty
4》箭头函数
在箭头函数中,箭头函数的this
被设置为封闭的词法环境的,this
与封闭词法环境的this
保持一致,换句话说,箭头函数中的this取决于该函数被创建时的环境。在全局代码中,它将被设置为全局对象,
var objProject = this; var foo = (() => this); console.log(foo()); // window console.log(objProject); // window console.log(foo() === objProject ); // true // 作为对象的一个方法调用 var obj = {foo: foo}; console.log(obj.foo() === objProject ); // true // 尝试使用call来设定this console.log(foo.call(obj) === objProject ); // true // 尝试使用bind来设定this foo = foo.bind(obj); console.log(foo() === objProject ); // true
5》作为对象的方法
当函数作为对象里的方法被调用时,它们的 this
是调用该函数的对象。
下面的例子中,当 o.f()
被调用时,函数内的this
将绑定到o
对象。
var o = { prop: 37, f: function() { return this.prop; } }; console.log(o.f()); // logs 37
请注意,这样的行为,根本不受函数定义方式或位置的影响。在前面的例子中,我们在定义对象o
的同时,将函数内联定义为成员 f
。但是,我们也可以先定义函数,然后再将其附属到o.f
。这样做会导致相同的行为:
var o = {prop: 37}; function independent() { return this.prop; } o.f = independent; console.log(o.f()); // logs 37
综上:这表明函数是从o
的f
成员调用的才是重点
同样,this
的绑定只受最靠近的成员引用的影响。在下面的这个例子中,我们把一个方法g
当作对象o.b
的函数调用。在这次执行期间,函数中的this
将指向o.b
。事实证明,这与他是对象 o
的成员没有多大关系,最靠近的引用才是最重要的。
o.b = {g: independent, prop: 42}; console.log(o.b.g()); // 42
6》作为构造函数
当一个函数用作构造函数时(使用new关键字),它的this
被绑定到正在构造的新对象。
虽然构造器返回的默认值是this所指的那个对象,但它仍可以手动返回其他的对象(如果返回值不是一个对象,则返回this对象)
/* * 构造函数这样工作: * * function MyConstructor(){ * // 函数实体写在这里 * // 根据需要在this上创建属性,然后赋值给它们,比如: * this.fum = "nom"; * // 等等... * * // 如果函数具有返回对象的return语句, * // 则该对象将是 new 表达式的结果。 * // 否则,表达式的结果是当前绑定到 this 的对象。 * //(即通常看到的常见情况)。 * } */ function C(){ this.a = 37; } var o = new C(); console.log(o.a); // logs 37 function C2(){ this.a = 37; return {a:38}; } o = new C2(); console.log(o.a); // logs 38
7》作为DOM事件处理函数
当函数被用作事件处理函数时,它的this
指向触发事件的元素(一些浏览器在使用非addEventListener
的函数动态添加监听函数时不遵守这个约定)。
// 被调用时,将关联的元素变成蓝色 function bluify(e){ console.log(this === e.currentTarget); // 总是 true // 当 currentTarget 和 target 是同一个对象时为 true console.log(this === e.target); this.style.backgroundColor = '#A5D9F3'; } // 获取文档中的所有元素的列表 var elements = document.getElementsByTagName('*'); // 将bluify作为元素的点击监听函数,当元素被点击时,就会变成蓝色 for(var i=0 ; i<elements.length ; i++){ elements[i].addEventListener('click', bluify, false); }
关于this问题的一道面试题:
var baz = 0; let foo = { bar:function() { console.log(this,this.baz); return this.baz; }, baz:1 }; let foo2 = { baz:2 }; let a = foo.bar(); //作为对象的方法调用,this指向调用函数的对象,即foo let b = foo.bar.call(foo2); //使用call方法将this绑定到第一个参数对象向,此时,this指向foo2 let fn = foo.bar; let c = fn(); //let fn创建的对象,此时,fn = function(){...},此时函数执行时,默认指向全局window对象 let d; (function test(){ d = arguments[0]() })(foo.bar); // arguments.callee包括了一个函数的引用去创建一个arguments对象,它能让一个匿名函数很方便的指向本身,即此时this指向arguments类数组对象 console.log(a,b,c,d);
4,setTimeout ,执行函数
JavaScript 是单线程执行的,也就是无法同时执行多段代码,当某一段代码正在执行的时候,所有后续的任务都必须等待,形成一个队列,一旦当前任务执行完毕,再从队列中取出下一个任务。这也常被称为 “阻塞式执行”。所以一次鼠标点击,或是计时器到达时间点,或是 Ajax 请求完成触发了回调函数,这些事件处理程序或回调函数都不会立即运行,而是立即排队,一旦线程有空闲就执行。假如当前 JavaScript 进程正在执行一段很耗时的代码,此时发生了一次鼠标点击,那么事件处理程序就被阻塞,用户也无法立即看到反馈,事件处理程序会被放入任务队列,直到前面的代码结束以后才会开始执行。如果代码中设定了一个 `setTimeout`,那么浏览器便会在合适的时间,将代码插入任务队列,如果这个时间设为 0,就代表立即插入队列,但不是立即执行,仍然要等待前面代码执行完毕。所以 `setTimeout` 并不能保证执行的时间,是否及时执行取决于 JavaScript 线程是拥挤还是空闲。 例如: <script> console.log("1"); setTimeout( function() { console.log("Hello World"); }, 0) //延时0秒 console.log("2"); </script>
5,自执行函数(形成作用域)
(function fun(){})();//称为自执行函数或立即执行函数
// 方式一 (function fun4(){ console.log("fun4"); }()); // "fun4"
分析:因为在JavaScript语言中,()
里面不能包含语句(只能是表达式),所以解析器在解析到function
关键字的时候,会把它们当作function表达式,而不是正常的函数声明。 除了上面直接整个包含住,也可以只包含住函数体(方式二),如下:
// 方式二 (function fun5(){ console.log("fun5"); })();// "fun5"
注:写法上建议采用方式一
“歪瓜裂枣”的自执行函数
除了上面()
小括弧可以把function
关键字作为函数声明的含义转换成函数表达式外,JavaScript的&&
与操作、||
或操作、,
逗号等操作符也有这个效果。
true && function () { console.log("true &&") } (); // "true &&" false || function () { console.log("true ||") } (); // "true ||" 0, function () { console.log("0,") } (); // "0," // 此处要注意: &&, || 的短路效应。即: false && (表达式1) 是不会触发表达式1; // 同理,true || (表达式2) 不会触发表达式2
如果不在意返回值,也不在意代码的可读性,我们甚至还可以使用一元操作符(!
~
-
+
),函数同样也会立即执行。
!function () { console.log("!"); } (); //"!" ~function () { console.log("~"); } (); //"~" -function () { console.log("-"); } (); //"-" +function () { console.log("+"); } (); //"+"
甚至还可以使用new
关键字:
// 注意:采用new方式,可以不要再解释花括弧 `}` 后面加小括弧 `()` new function () { console.log("new"); } //"new" // 如果需要传递参数 new function (a) { console.log(a); } ("newwwwwwww"); //"newwwwwwww"
嗯,最好玩的是赋值符号=
同样也有此效用(例子中的i
变量方式):
//此处 要注意区分 i 和 j 不同之处。前者是函数自执行后返回值给 i ;后者是声明一个函数,函数名为 j 。 var i = function () { console.log("output i:"); return 10; } (); // "output i:" var j = function () { console.log("output j:"); return 99;} console.log(i); // 10 console.log(j); // ƒ () { console.log("output j:"); return 99;}
上面提及到,要注意区分 var i
和 var j
不同之处(前者是函数自执行后返回值给i
;后者是声明一个函数,函数名为j
)。如果是看代码,我们需要查看代码结尾是否有没有()
才能区分。一般为了方便开发人员阅读,我们会采用下面这种方式:
var i2 = (function () { console.log("output i2:"); return 10; } ()); // "output i2:" var i3 = (function () { console.log("output i3:"); return 10; }) (); // "output i3:" // 以上两种都可以,但依旧建议采用第一种 i2 的方式。(个人依旧喜欢第二种i3方式)
自执行函数应用
for( var i=0;i<3;i++){ setTimeout(function(){ console.log(i); } ,300); } // 输出结果 3,3,3
如果想输出1,2,3,可以用自执行函数如下:
for(var i=1;i<=3;i++){ (function(index){ setTimeout(function(){ console.log(index) },0) }(i)) }
分析:尽管循环执行结束,i
值已经变成了3。但因遇到了自执行函数,当时的i
值已经被 lockedIndex
锁住了。也可以理解为 自执行函数属于for循环一部分,每次遍历i
,自执行函数也会立即执行。所以尽管有延时器,但依旧会保留住立即执行时的i
值
for( var i=0;i<3;i++){ setTimeout((function(lockedInIndex){ console.log(lockedInIndex); })(i) ,300); }
6,堆栈的概念=》地址指针
js里实现队列与堆栈 - Joans - 博客园
这里先说两个概念:**1、堆(heap)2、栈(stack)
**堆 是堆内存的简称,栈 是栈内存的简称
说到堆栈,我们讲的就是内存的使用和分配了,没有寄存器的事,也没有硬盘的事。 各种语言在处理堆栈的原理上都大同小异。堆是动态分配内存,内存大小不一,也不会自动释放。栈是自动分配相对固定大小的内存空间,并由系统自动释放。
javascript的基本类型就5种:Undefined、Null、Boolean、Number和String,它们都是直接按值存储在栈中的,每种类型的数据占用的内存空间的大小是确定的,并由系统自动分配和自动释放。这样带来的好处就是,内存可以及时得到回收,相对于堆来说,更加容易管理内存空间。
javascript中其他类型的数据被称为引用类型的数据 : 如对象(Object)、数组(Array)、函数(Function) …,它们是通过拷贝和new出来的,这样的数据存储于堆中。其实,说存储于堆中,也不太准确,因为,引用类型的数据的地址指针是存储于栈中的,当我们想要访问引用类型的值的时候,需要先从栈中获得对象的地址指针,然后,在通过地址指针找到堆中的所需要的数据。
说来也是形象,栈,线性结构,后进先出,便于管理。堆,一个混沌,杂乱无章,方便存储和开辟内存空间
例如:
var arr1 = [1,2,5,8]; var arr2 = arr1 ; var str1 = arr1[2]; console.log(arr2);//1,2,5,8 console.log(str1);//5 arr2[4] = 99; str1 = 6; console.log(arr1);//1,2,5,8,99 console.log(arr1[2]);//5
上方例子得知,当我改变arr2中的数据时,arr1中数据也发生了变化,当改变str1的数据值时,arr1却没有发生改变。为什么?这就是传值与传址的区别。
<!--因为arr1是数组,属于引用类型,所以它赋予给arr2的时候传的是栈中的地址(相当于新建了一个不同名“指针”),而不是堆内存中的对象的值。str1得到的是一个基本类型的赋值,因此,str1仅仅是从arr1堆内存中获取了一个数值,并直接保存在栈中。arr1、arr2都指向同一块堆内存,arr2修改的堆内存的时候,也就会影响到arr1,str1是直接在栈中修改,并且不能影响到arr1堆内存中的数据。-->
堆(heap)、栈(stack)
浅拷贝和深拷贝
上边说到的赋值方式就是浅拷贝,那么什么叫作深拷贝呢?就是要将arr1的每个基本类型的数据都遍历一遍,依次的赋值给arr2的对应字段。避免产生因为地址引用带来的问题(或者 [...arr2])
var arr1 = [1,2,5,8]; var arr2 = []; for(var i=0;i<arr1.length;i++){ arr2[i]=arr1[i]; }; console.log(arr2)//1,2,5,8 arr2[4]=99; console.log(arr2)//1,2,5,8,99 console.log(arr1)//1,2,5,8 //javascript面向对象的语言本身在处理对象和非对象上就进行了划分,从数据结构的角度来讲,对象就是栈的指针和堆中的数值。
7,dom二级事件
一. 0级DOM分为两种
-
行内事件:在标签中写事件
-
元素.on事件名=函数
1.行内 <input type="button" id="btn" value="按钮" οnclick="alert('上海尚学堂,你值得拥有!')">
2.元素.on事件名=函数 document.getElementById("btn").onclick = function () { alert('上海尚学堂,你值得拥有!'); }
为什么没有1级DOM? DOM级别1于1998年10月1日成为W3C推荐标准。1级DOM标准中并没有定义事件相关的内容,所以没有所谓的1级DOM事件模型。在2级DOM中除了定义了一些DOM相关的操作之外还定义了一个事件模型 ,这个标准下的事件模型就是我们所说的2级DOM事件模型
三, 2级Dom事件
概念:Dom二级事件可以解决事件冒泡以及一个对象只能绑定一个事件的问题(主要)
只有一个:监听方法,有两个方法用来添加和移除事件处理程序:addEventListener()和removeEventListener()。 它们都有三个参数:第一个参数是事件名(如click); 第二个参数是事件处理程序函数; 第三个参数如果是true则表示在捕获阶段调用,为false表示在冒泡阶段调用。 addEventListener():可以为元素添加多个事件处理程序,触发时会按照添加顺序依次调用。 removeEventListener():不能移除匿名添加的函数。 例: document.getElementById("btn").addEventListener("click", function(){alert('上海尚学堂,你值得拥有!')}, false);
<input id='input' type="text" οnclick="alert('haha')" /> <script> document.getElementById('input').onclick = function() { alert('fff') }; document.getElementById('input').addEventListener('click', function() { alert('mmm') }, true) document.getElementById('input').addEventListener('click', function() { alert('ooooo') }, true) document.getElementById('input').addEventListener('click', function() { alert('pppp') }, false) // 兼容低版本IE的写法 document.getElementById('input').attachEvent("onclick", function() { alert('pppp') }); </script> // mmm ooooo fff pppp //只有2级DOM包含3个事件:事件捕获阶段、处于目标阶段和事件冒泡阶段 //dom2不会覆盖,会依次执行,dom1和dom2是可以共存的
但是在IE6-8浏览器中,不支持addEventListener,如果想实现DOM2事件绑定只能用attachEvent/detachEvent
它只有两个参数,不能像addEventListener那样控制在哪个阶段发生,默认只能在冒泡阶段发生,同时行为需要添加on(和DOM0特别的类似)
box.attachEvent('onclick',fn1)
8,SEO优化
搜索引擎优化 (SEO) 是提高一个网站在搜索引擎中的排名(能见度)的过程。如果网站能够在搜索引擎中有良好的排名,有助于网站获得更多的流量。
SEO主要研究搜索引擎是工作的原理,是什么人搜索,输入什么搜索关键字)。优化一个网站,可能涉及内容的编辑,增加关键字的相关性。推广一个网站,可以增加网站的外链数量。
搜索引擎优化需要修改一个网站的HTML源代码和网站内容。搜索引擎优化策略应在网站建设之前就纳入网站的发展,尤其是网站的菜单和导航结构。
笼统的说,所有使用作弊手段或可疑手段的,都可以称为黑帽SEO。比如说垃圾链接,隐藏网页,桥页,关键词堆砌等等。
黑帽seo就是作弊的意思,黑帽seo手法不符合主流搜索引擎发行方针规定。黑帽SEO获利主要的特点就是短平快,为了短期内的利益而采用的作弊方法。同时随时因为搜索引擎算法的改变而面临惩罚。
不论是白帽seo还是黑帽seo没有一个精准的定义。笼统来说所有使用作弊手段或一些可疑手段的都可称为黑帽SEO。例如隐藏网页,关键词堆砌,垃圾链接,桥页等等。
优化:
搜索引擎优化 一、内部优化 (1)META标签优化:例如:TITLE,KEYWORDS,DESCRIPTION等的优化; (2)内部链接的优化,包括相关性链接(Tag标签),锚文本链接,各导航链接,及图片链接; (3)网站内容更新:每天保持站内的更新(主要是文章的更新等)。 (4)在网站上合理设置Robot.txt文件; 二、外部优化 (1)外部链接类别:友情链接、博客、论坛、B2B、新闻、分类信息、贴吧、知道、百科、站群、相关信息网等尽量保持链接的多样性; (2)外链运营:每天添加一定数量的外部链接,使关键词排名稳定提升; (3)外链选择:与一些和你网站相关性比较高,整体质量比较好的网站交换友情链接,巩固稳定关键词排名。
(2) 网页代码优化
1.<title>标题:只强调重点即可,尽量把重要的关键词放在前面,关键词不要重复出现,尽量做到每个页面的<title>标题中不要设置相同的内容。 2.<meta keywords>标签:关键词,列举出几个页面的重要关键字即可,切记过分堆砌。 3.<meta description>标签:网页描述,需要高度概括网页内容,切记不能太长,过分堆砌关键词,每个页面也要有所不同。 4.<body>中的标签:尽量让代码语义化,在适当的位置使用适当的标签,用正确的标签做正确的事。让阅读源码者和“蜘蛛”都一目了然。比如:h1-h6是用于标题类的,<nav>标签是用来设置页面主导航的等。 5.<a>标签:页内链接,要加“title” 属性加以说明,让访客和 “蜘蛛” 知道。而外部链接,链接到其他网站的,则需要加上el="nofollow"属性, 告诉 “蜘蛛” 不要爬,因为一旦“蜘蛛”爬了外部链接之后,就不会再回来了。 6.正文标题要用<h1>标签:“蜘蛛” 认为它最重要,若不喜欢<h1>的默认样式可以通过CSS设置。尽量做到正文标题用<h1>标签,副标题用<h2>标签, 而其它地方不应该随便乱用 h 标题标签。 7.<br>标签:只用于文本内容的换行,比如: <p> 第一行文字内容<br/> 第二行文字内容<br/> 第三行文字内容 </p> 8.表格应该使用<caption>表格标题标签 9.<img>应使用 “alt” 属性加以说明 10.<strong>、<em>标签 : 需要强调时使用。<strong>标签在搜索引擎中能够得到高度的重视,它能突出关键词,表现重要的内容,<em>标签强调效果仅次于<strong>标签。 <b>、<i>标签: 只是用于显示效果时使用,在SEO中不会起任何效果。 11、文本缩进不要使用特殊符号 应当使用CSS进行设置。版权符号不要使用特殊符号 © 可以直接使用输入法,拼“banquan”,选择序号5就能打出版权符号©。 12、巧妙利用CSS布局,将重要内容的HTML代码放在最前面,最前面的内容被认为是最重要的,优先让“蜘蛛”读取,进行内容关键词抓取。 13.重要内容不要用JS输出,因为“蜘蛛”不认识 14.尽量少使用iframe框架,因为“蜘蛛”一般不会读取其中的内容 15.谨慎使用display:none :对于不想显示的文字内容,应当设置z-index或设置到浏览器显示器之外。因为搜索引擎会过滤掉display:none其中的内容。 16. 不断精简代码 17.js代码如果是操作DOM操作,应尽量放在body结束标签之前,html代码之后。
注:vue 不建议做seo,如果要做可以考虑->Vue的通用框架Nuxt.js
基于Vue的通用框架Nuxt.js - 肖秋雄 - 博客园
9,工厂模式
个人理解:抽离出有规律的对象,然后传不同的参数去调用一个对象返回不同的结果
从ES6重新认识JavaScript设计模式(二): 工厂模式 - 简书
所有的设计模式:
JS设计模式 - 初心不负 - 博客园
10,ES6 数组语法,数组去重等(es6,原生)
Array.from概念:从一个类似数组或可迭代对象创建一个新的,浅拷贝的数组实例
实际上:将一个类数组对象或者可遍历对象转换成一个真正的数组。
那么什么是类数组对象呢?所谓类数组对象,最基本的要求就是具有length属性的对象
情况1:(要有length属性)
var obj = { 0:20, 1:'华清', 'length': 2 } array = Array.from(obj)// [20, "华清"] var obj = { 0:20, 1:'华清', } array = Array.from(obj)//[] 说明需要有length属性 console.log(array)
情况2:将Set结构的数据转换为真正的数组:
let arr = [12,45,97,9797,564,134,45642] let set = new Set(arr) console.log(set) console.log(Array.from(set)) // [ 12, 45, 97, 9797, 564, 134, 45642 ]
情况3:
let str = 'hello world!'; console.log(Array.from(str)) // ["h", "e", "l", "l", "o", " ", "w", "o", "r", "l", "d", "!"]
Es6 新特性:Set
特性
似于数组,但它的一大特性就是所有元素都是唯一的,没有重复。
我们可以利用这一唯一特性进行数组的去重工作。
let set6 = new Set([1, 2, 2, 3, 4, 3, 5]) console.log('distinct 1:', set6)//distinct 1: Set(5) {1, 2, 3, 4, 5}
1.向Set中添加元素。
let set1 = new Set() set1.add(1) set1.add(2) set1.add(3) console.log('added:', set1)
2.从Set中删除元素。
let set1 = new Set() set1.add(1) set1.add(2) set1.add(3) set1.delete(1) console.log('deleted:', set1)
3.判断某元素是否存在。
let set1 = new Set() set1.add(1) set1.add(2) set1.add(3) set1.delete(1) console.log('has(1):', set1.has(1)) console.log('has(2):', set1.has(2))
JavaScript 高性能数组去重 - Wise.Wrong - 博客园(效率比较)
方法一:(for循环双层循环,占用内存高,效率最低)(15w数据大概20152ms)
let arr = [1, 2, 3, 4, 2, 1]; for (let i=0, len=arr.length; i<len; i++) { for (let j=i+1; j<len; j++) { if (arr[i] == arr[j]) { arr.splice(j, 1); // splice 会改变数组长度,所以要将数组长度 len 和下标 j 减一 len--; j--; } } } console.log(arr) // [1, 2, 3,4]
方法二:(filter+indexOf)(15w数据大概8427ms)
let arr = [1, 2, 3, 4, 2, 1]; var aaa = arr.filter((item, index)=> { return arr.indexOf(item) === index }) console.log(aaa) // [1, 2, 3,4]
方法三:(Array.from + Set)(15w数据大概57ms)(150w数据大概需要678ms)
let arr = [1, 2, 3, 2, 1]; function unique(arr){ return Array.from(new Set(arr)); } console.log(unique(arr)) // [1, 2, 3]
方法四:(拓展运算+set)
let arr = [1, 2, 3, 2, 1]; function unique(arr){ return [...new Set(arr)]; } console.log(unique(arr)) // [1, 2, 3]
方法五:(用sort先排序,然后对比相近的数据是否相等)
这种方法只做了一次排序和一次循环,所以效率会比较高(15w数据大概120ms)
let arr = [1, 2, 3, 4, 2, 1]; arr = arr.sort() let result = [arr[0]] for (let i=1, len=arr.length; i<len; i++) { arr[i] !== arr[i-1] && result.push(arr[i]) } console.log(result) // [1, 2, 3,4]
方法六:(创建一个空对象,然后用 for 循环遍历利用对象的属性不会重复这一特性,校验数组元素是否重复)
效率超级高:(15w数据大概16ms)(150w数据大概93ms)简直666666666
let arr = [1, 2, 3, 4,2, 2, 1]; let result = [] let obj = {} for (let i of arr) { if (!obj[i]) { result.push(i) obj[i] = 1 } } console.log(result) // [1, 2, 3,4]
11,原型,继承
一、对象等级划分
我们认为在javascript任何值或变量都是对象,但是我还需要将javascript中的对象分为一下几个等级。
首先Object是顶级公民,这个应该毋庸置疑,因为所有的对象都是间接或直接的通过它衍生的。Function是一等公民,下面会做解释。几个像String,Array,Date,Number,Boolean,Math等内建对象是二等公民。剩下的则都是低级公民。
1.构造函数
构造函数 ,是一种特殊的方法。主要用来在创建对象时初始化对象。每个构造函数都有prototype(原型)属性
原型(prototype)
概念:每一个构造函数都有一个prototype
属性,指向另一个对象。这个对象的所有属性和方法,都会被构造函数的实例继承。
function Person() { } // 虽然写在注释里,但是你要注意: // prototype是函数才会有的属性 Person.prototype.name = 'Kevin'; var person1 = new Person(); var person2 = new Person(); console.log(person1.name) // Kevin console.log(person2.name) // Kevin
proto
每一个JavaScript对象(除了 null )都具有的一个属性,叫proto,这个属性会指向该对象的原型proto是一个指针
function Person() { } var person = new Person(); console.log(person.__proto__ === Person.prototype); // true
constructor
每个原型都有一个 constructor 属性指向关联的构造函数 实例原型指向构造函数
function Person() { } console.log(Person === Person.prototype.constructor); // true
原型链
概念:在javascript中,每个对象都有一个指向它的原型(prototype)对象的内部链接。每个原型对象又有自己的原型,直到某个对象的原型为null为止,组成这条链的最后一环
个人理解:根据proto一直向上查找,直到找到null为止
构造/new调用函数的时候做了什么**:
-
创建一个全新的对象。
-
这个新对象的原型(
Object.getPrototypeOf(target)
)指向构造函数的prototype
对象。 -
该函数的this会绑定在新创建的对象上。
-
如果函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个新对象。
-
我们称这个新对象为构造函数的实例。
12,vue中key的作用
diff算法,使用key来给每个节点做一个唯一标识,Diff算法就可以正确的识别此节点,找到正确的位置区插入新的节点。
所以一句话,key的作用主要是为了高效的更新虚拟DOM。
另外vue中在使用相同标签名元素的过渡切换时,也会使用到key属性,其目的也是为了让vue可以区分它们,
否则vue只会替换其内部属性而不会触发过渡效果。
13,如何进行组件复用
已经存在的ui类库,elementui 等等···就是灵活的组件
[一个好的组件库,衡量标准主要包括灵活性、复用性、全面性。灵活性指一个组件的字段、icon、配色都应该可以灵活改写,以应对多样化的需求。复用性指对于通用组件,应当是可以在不同项目间复用的。全面性则指一套组件库应当覆盖尽可能多的常用元素。 组件化的初衷并非提高一致性、利于团队合作这些高大上的目的,而是人类进步的第一生产力——「懒」。消灭重复劳动是提高效率的主要途径,勤劳如小蜜蜂的设计师也不例外,那么组件化就是无论交互还是UI设计中我们不得不思考的问题。]
[2、复用性:组件库的意义
上面说到组件化是源于「懒」,并不是说组件化的作用仅限于简化重复操作。除了提高设计师个人的设计效率这一显而易见的好处之外,在交互设计阶段对常见的元素控件进行组件化,还有很多更深层次的意义: 一致性「从娃娃抓起」:从交互稿阶段开始,就让整个项目的产出物具有高度的一致性,使用同一组件库画的每个顶栏、每个列表、每个弹框都是遵循同一规则的。 与视觉设计无缝衔接:Sketch为交互设计和视觉设计阶段的无缝衔接提供了最好的平台,交互组件库可以直接交付视觉设计师进行视觉设计,形成真正的UI组件库(UI Kit)。 有助于形成设计规范:当UI组件库形成后,「设计规范的积淀」——这个贯穿交互和UI设计管理工作中的老大难问题,就已经解决了一大半了,经过评审确认的UI组件库可以直接作为视觉设计规范的一部分。 利于团队合作:无论是交互设计组件库还是UI组件库,经过整理和完善,在项目或者团队中推行开来,对项目内,或者不同项目间设计成果的一致性、合作效率都大有裨益,也有助于让整个品牌形成有效的辨识度。 ]
[既然组件化有这么多的好处,哪些元素可以进行组件化呢?其实很简单,凡是你觉得已经重复画了很多次的元素,不同场景下都会用到的元素,都可以考虑将其单独拿出来进行组件化。]
《《《《《命名》》》》》》
组件的命名应该跟业务无关。应该依据组件的功能为组件命名。
例如,一个展示公司部门的列表,把每一项作为一个组件,并命名为 bumen。这时,有一个需求要展示团队人员列表,样式跟刚刚的部门列表一样。显然,bumen这个名字就不适合了。(list)
因此,可复用组件在命名上应避免跟业务扯上关系,以组件的角色、功能对其命名。Item、ListItem、Cell。可以参考 Bootstrap、ElementUI 等一些 UI 框架的命名。
《《《《业务数据无关》》》》
可复用组件只负责 UI 上的展示和一些交互以及动画,如何获取数据跟它无关,因此不要在组件内部去获取数据,以及任何与服务端打交道的操作。可复用组件只实现 UI 相关的功能。
《《《《《组件职责》》》》》
约束好组件的职责,能让组件更好地解耦,知道什么功能是组件实现的,什么功能不需要实现。
组件可以分为通用组件(可复用组件)和业务组件(一次性组件)。
可复用组件实现通用的功能(不会因组件使用的位置、场景而变化):
-
UI 的展示
-
与用户的交互(事件)
-
动画效果
业务组件实现偏业务化的功能:
-
获取数据
-
和 vuex 相关的操作
-
引用可复用组件
可复用组件应尽量减少对外部条件的依赖,所有与 vuex 相关的操作都不应在可复用组件中出现。
组件应当避免对其父组件的依赖,不要通过 this.$parent 来操作父组件的示例。父组件也不要通过 this.$children 来引用子组件的示例,而是通过子组件的接口与之交互。
《《《数据扁平化》》》》
定义组件接口时,尽量不要将整个对象作为一个 prop 传进来。
<!-- 反例 --> <card :item="{ title: item.name, description: item.desc, poster: item.img }></card>
每个 prop 应该是一个简单类型的数据。这样做有下列几点好处:
-
组件接口清晰
-
props 校验方便
-
当服务端返回的对象中的 key 名称与组件接口不一样时,不需要重新构造一个对象
<card :title="item.name" :description="item.desc" :poster="item.img"> </card>
扁平化的 props 能让我们更直观地理解组件的接口。
14,vue的一些问题:
1.setInterval路由跳转继续运行并没有及时进行销毁
比如一些弹幕,走马灯文字,这类需要定时调用的,路由跳转之后,因为组件已经销毁了,但是setInterval还没有销毁,还在继续后台调用,控制台会不断报错,如果运算量大的话,无法及时清除,会导致严重的页面卡顿。
解决方案:在组件生命周期beforeDestroy停止setInterval
beforeDestory() { clearInterval(this.timer); MessageBox.close() }
2,vue.js中有两个核心功能:响应式数据绑定,组件系统
3,vue的原理(引申到数据的双向绑定)
1. 通过建立虚拟dom树`document.createDocumentFragment()`,方法创建虚拟dom树。 2. 一旦被监测的数据改变,会通过[Object.defineProperty](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty)定义的数据拦截,截取到数据的变化。 3. 截取到的数据变化,从而通过订阅——发布者模式,触发Watcher(观察者),从而改变虚拟dom的中的具体数据。 4. 最后,通过更新虚拟dom的元素值,从而改变最后渲染dom树的值,完成双向绑定
15.cookie sessionStorage localstorage 的区别?
2,vue数据的双向绑定,以及其原理(v-model)
vue,在ie9下不兼容(axios不能跨域,配置了babel-polyfill不好使,只能后端解决)
3,webpack打包项目
4,vuex的掌握情况
五大属性:
state => 基本数据 getters => 从基本数据派生的数据 mutations => 提交更改数据的方法,同步! actions => 像一个装饰器,包裹mutations,使之可以异步。 modules => 模块化Vuex
模块化:
1, dataScrSetupFlag: true, //总数据总览总设置开关(设置一些开关等,到达一些样式变化的效果)
2,项目的产品的一些配置信息
3,userName: '', // 重置密码之后的 用户名密码 跳转登陆的时候填入
4,api接口路径:百度一下,你就知道
16,项目中的难点,亮点
在vue项目中关于定时器的使用(难点)
假如,我们在A组建中声明了一个定时器进行倒计时此时 我们在定时器中一直打印时间戳,此时我们通过路由跳转到下一个组件页面,按照正常理论来说,A组件在跳转后整个组件就会被销毁,到达B组件时A组件已经没有了。
但是在我们有定时器的情况下 此时跳转过后 定时器依然会存在。所以我们要在页面销毁时候将当前页面的定时器clear掉。(比如,统计页面,定时刷新数据)
2:比如数组去重,使用了效率更高的写法()
3,有些后端为了性能优化,多数情况,避免前端频繁的请求后端接口,一次返回数据,让前端去调用排序,搜索等
17,react可能会问到(vue也会用到diff算法)
Diff算法 的运行机制?
概念: diff算法是一种优化手段,将前后两个模块进行差异对比,修补(更新)差异的过程叫做patch(打补丁)
通俗的讲,当前层级的dom 先进行对比,如果发现异同 就更新当前dom 和 它的子节点
<!--为什么vue,react这些框架中都会有diff算法呢? 我们都知道渲染真实dom的开销是很大的,这个跟性能优化中的重绘重排意义类似, 回到正题来, 有时候我们修改了页面中的某个数据,如果直接渲染到真实DOM中会引起整棵数的重绘重排, 那么我们能不能只让我们修改的数据映射到真实DOM, 做一个最少化重绘重排呢-->
注:Key值唯一 提高虚拟dom的对比效率
问:Key值的作用 为什么最好不要用index???
Index 索引可以随着队列的操作发生变化 不利于虚拟dom之间的对比
[
[id:004,小李] 0
[id:001,小明] 1
[id:002,小红] 2
[id:003,小花] 3
]
总结
-
尽量不要跨层级的修改dom
-
在开发组件时,保持稳定的 DOM 结构会有助于性能的提升
-
设置key可以让diff更高效
18,组件数据传递时候延迟怎么办
<echarts-com v-if="datamenu.length>0" ids="nike" widths='700px' />
加上判断就行,这个时候,数据如果没有就不显示当前组件,有数据在显示
19,面试问题1
Get和post的区别 ,Tcp三次握手,函数节流防抖,ajax和axios区别
最后
以上就是友好纸飞机为你收集整理的前端问题总结16,项目中的难点,亮点17,react可能会问到(vue也会用到diff算法)的全部内容,希望文章能够帮你解决前端问题总结16,项目中的难点,亮点17,react可能会问到(vue也会用到diff算法)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复