js和jQUERY第十周思维导图
2019-10-28 18:36:21 1 举报
AI智能生成
js和jQUERY
作者其他创作
大纲/内容
继承
1.原型继承
* 就是子对象自动拥有父对象的属性和方法, 继承可以提高代码的复用性。<br>* JS里的继承主要依靠是的原型链。让原型对象(每一个构造函数都有一个原型对象)的值,等于另一个类型的实例,即实现了继承;另外一个类型的原型再指向第三个类型的实例,以此类推,也就形成了一个原型链<br>
function Animal(newName,newAge){<br> this.name = newName;<br> this.age = newAge;<br> }<br> Animal.prototype.eat = function(str){<br> console.log(this.name + "吃" + str);<br> }<br> function Person(newId){<br> this.id = newId;<br> }<br> Person.prototype = new Animal("老王",18);<br> let p1 = new Person("007");<br> console.log(p1.name,p1.age,p1.id);<br> p1.name = "小明";<br> p1.eat("米饭");<br> let p2 = new Person("008");<br> console.log(p2.name,p2.age,p2.id);<br> p1.name = "大明";<br> p1.eat("水果");<br><br>* 使用instanceof操作符检测对象类型<br> console.log(p1 instanceof Person);<br> console.log(p2 instanceof Person);<br>
2.原型链继承
让子对象的原型指向父对象的实例,父对象的原型指向爷爷对象的实例,依次类推,就形成了原型链
function Animal(newAge){<br> this.age = newAge;<br> }<br> Animal.prototype.eat = function(){<br> console.log("Animal.eat");<br> }<br> function Person(newId){<br> this.id = newId;<br> }<br> Person.prototype = new Animal(18);<br> Person.prototype.study = function(){<br> console.log("Person.study");<br> }<br> function Pupli(newTall){<br> this.tall = newTall;<br> }<br> Pupli.prototype = new Person("007");<br> Pupli.prototype.play = function(){<br> console.log("Pupli.play");<br> }<br> <br> let pu = new Pupli(140);<br> console.log(pu.age,pu.id,pu.tall);<br> pu.eat();<br> pu.study();<br> pu.play();<br>
3.原型继承中的注意事项:
1. 先定义原型继承关系,再添加子类的自定义方法或属性(原型的属性,即共享的属性和方法要在原型继承关系确立后,再定义)。<br> 2. 利用原型链继承,给子类添加原型方法时,不可以重写prototype<br>
function Animal(newAge){<br> this.age = newAge;<br> }<br> function Person(newId){<br> this.id = newId;<br> }<br> Person.prototype.eat = function(){<br> console.log("Person eat");<br> }<br> Person.prototype = new Animal(15);<br> <br> let p = new Person("007");<br> console.log(p.id);<br> p.eat();<br>
缺点:<br> 1. 被继承的类型(父类)里包括引用类型的属性的时候,它会被所有实例共享其值<br> 2. 创建子类型的实例时,没法传参给被继承类型。<br>
4.深拷贝浅拷贝
在传入父类传入的参数有引用元素时,则需要考虑深拷贝和浅拷贝的问题。<br>浅拷贝:传参时值只传递了引用空间的地址<br>深拷贝:开辟空间,且赋值<br>
function Birthday(y,m,d){<br> this.y = y;<br> this.m = m;<br> this.d = d;<br> }<br> function Animal(newBir){<br> this.bir = newBir;<br> }<br> function Person(){<br> <br> }<br> Person.prototype = new Animal(new Birthday(1,2,3));<br> Person.prototype.clone = function(){<br> let p = new Person();<br> p.bir = new Birthday(this.bir.y,this.bir.m,this.bir.d);<br> return p;<br> }<br> <br> let p1 = new Person();<br> console.log(p1.bir.y,p1.bir.m,p1.bir.d);<br> let p2 = p1.clone();<br> console.log(p2.bir.y,p2.bir.m,p2.bir.d);<br> p1.bir.y = 666;<br> p1.bir.m = 666;<br> p1.bir.d = 666;<br> console.log(p1.bir.y,p1.bir.m,p1.bir.d);<br> console.log(p2.bir.y,p2.bir.m,p2.bir.d);<br>
5.call和apply的继承
这两个方法,已经讲过,是调用函数的,当然也能调用构造函数 <br> function Person(newId,newName){<br> this.id = newId;<br> this.name = newName;<br> }<br> function Student(newId,newName,newScore){<br> //借用构造方法<br> Person.call(this,newId,newName);<br> this.score = newScore;<br> }<br> <br> let student = new Student("007","老王",99);<br> console.log(student.id,student.name,student.score);<br>
但是这样的继承的方式也有弊端:<br> 1.无法继承父类原型上的属性和方法<br> 2.单独使用这种借用的模式,所有要继承的属性和方法都要在父类型的构造函数里定义,<br> 特别是实例共享的属性和方法也写在构造函数里,那么这样会浪费内存。所以,很少很少单独使用<br>
组合继承:<br> 结合前两种方式:原型链式继承和Call()/Apply()方式继承,我们就能解决前面提出的那些问题。<br> 利用原型链继承共有的属性和方法,利用Call/Apply来初始化自己的但是和父类型同名的属性或
function Person(newId,newName){<br> this.id = newId;<br> this.name = newName;<br> }<br> Person.prototype.eat = function(){<br> console.log("Person eat");<br> }<br> function Student(newId,newName,newScore){<br> Person.call(this,newId,newName);<br> this.score = newScore;<br> }<br> <br> Student.prototype = new Person();<br> let student = new Student("007","老王",99);<br> console.log(student.id,student.name,student.score);<br> student.eat();<br>
6.ES6的继承
class Person{<br> constructor(newId,newName) {<br> this.id = newId;<br> this.name = newName;<br> }<br> showValue(){<br> console.log(this.id,this.name);<br> }<br> }<br> class Student extends Person{<br> constructor(newId,newName,newScore){<br> super(newId,newName);<br> this.score = newScore;<br> }<br> eat(){<br> console.log("student eat");<br> }<br> showValue(){<br> super.showValue();<br> console.log(s.score);<br> }<br> }<br> <br> let s = new Student(1,"老王",99);<br> s.showValue();<br> s.eat();<br>
闭包与函数对象
函数对象
函数的三种定义方式
函数声明 声明的方式有函数的提升<br>function test(ord){<br> alert(“亲”+ord+“!”);<br>}<br>
函数表达式(匿名函数)<br>var test = function(ord){<br> alert(“亲”+ord+“!”);<br>}<br>
let test = new Function(参数1,参数2...,"函数体");<br><br>示例:<br>// test();<br>// function test(){ // 有变量提升<br>// console.log("heihei");<br>// }<br>// test(); <br>// let test = function(){<br>// console.log("heihei");<br>// } <br>// let test = new Function("param","console.log(param)");<br>// test(666);<br>
函数是功能完整的类
* ECMAScript 中函数实际上是功能完整的对象。即函数就是一个对象
格式:<br> var functionName = new Function(arg1,..., argN, function_body)<br> 每个 arg 都是一个参数,最后一个参数是函数主体(要执行的代码)。这些参数必须是字符串。<br>
示例一(无参):<br> var sayHello = new Function("alert(\"hello 哥们1111!\");"); <br>
示例二(有参):<br> var sayHi = new Function("sN", "sM", "alert(sN + sM);");<br> 等价于以前的:<br> function sayHi(sN, sM) {<br> alert(sN + sM);<br> }<br>
既然定义一个函数就是创建一个函数对象。<br> * 那么只要执行函数定义的代码,就会创建新的函数对象<br>
回忆闭包中,一旦父函数被调用一次,闭包就会新创建一个函数。<br> function f1(){<br> var n = 250;<br> function f2(){<br> n++; <br> alert(n);<br> }<br> return f2;<br> }<br> var f21 = f1();//f21就是f2<br> f21();//调用f2;<br> f21();//调用f2;<br> var f22= f1();//f22就是f2<br> f22();//调用f2;<br> f22();//调用f2;<br> 虽然f21和f22的代码一样,但是,它们是两个不同的对象,即,每个的n值不一样。<br>
所以函数等价于类?<br><br> * 函数名作为参数和返回值:<br> * 函数名能作为返回值,那么匿名函数也就可以作为返回值。<br><br> 当我们知道函数是对象,函数名是对象名(变量名)时,函数名作为另外一个函数的参数和返回值就不难理解了。还记得当时讲数组的sort函数是,参数就是另外一个函数名。<br>
this的回顾:
1.事件绑定的方法<br>2.构造函数<br>3.类中出现的方法<br>4.普通函数<br>
arguments
* arguments对象保存函数的所有参数,虽然可以像数组一样的访问每个参数,但是,并不是标准的数组(没法使用push等函数);
arguments对象不但保存着所有的参数,而且还有一个名叫callee的属性。Callee属性是个指针,指向了arguments对象所在的函数。Callee属性有个好处,看如下阶
示例:<br> function fun(a){<br> console.log(a);<br> for(let i=0;iarguments.length; i++){<br> console.log(arguments[i]);}<br> }<br> fun(11,23,34,53,63);<br><br>
乘递归的示例,即可明白<br>function fun(n){<br> let c = 0;<br> if(n==1){<br> return c = 1;<br> }else{<br> c = arguments.callee(n-1)*n;<br> }<br> <br> return c;<br> }<br> <br> console.log(fun(10));<br>如果函数名进行修改,函数体不用修改。<br>
匿名函数
* 匿名函数(anonymous)的概念:
没有名字的函数就是匿名函数。当某个函数,function 关键字后面没有标识符的时候,那么它就是一个匿名函数(lamda,拉姆达函数)。
如:<br> function(){<br> alert(“亲,我来自无名函数”);<br>}<br>以前曾经写过 以下的代码:<br> window.onload = function(){<br> ……<br> }<br>这就是把匿名函数赋给了事件属性。<br>
匿名函数的四种写法
* 写法一: 定义一个函数,把函数名赋给 onload属性<br>function test(){<br> alert("亲1");<br>}<br>
* 写法二 : 定义一个匿名函数,直接赋给 onload属性<br>window.onload = function(){<br> alert("亲2");<br>}<br>
* 写法三 :定义一个匿名函数赋给一个变量;然后把变量赋给onload事件属性; 比写法二多了个中间变量而已<br>var test = function(){<br> alert("亲3");<br>}<br>
* 写法四: 定义一个匿名函数赋给一个变量,用变量(当作函数名)来调用函数;<br>var test = function(){<br> alert("亲4");<br>}<br>test();<br>
常见用法
匿名函数的常见用法:<br> * 函数表达式(var test = function(){})<br> * 事件处理函数 (window.onload = funciont(){})<br> * 自运行(立即执行)<br> * 闭包里的返回值 (闭包中会讲)<br><br>其实,当把匿名函数赋给一个变量时,就知道还可以用在何处(如:作为另外一个函数的参数),但不能进行运算<br>
自运行:
* 什么是自运行(函数)<br>* 自运行(函数)示例:<br><br> 能够自己运行的一个函数。即,不用别人调用就能运行的函数。这是学习闭包的基础。<br> (function(){alert(“亲4”);})()<br><br>推导一下:<br>
1、已知:<br>var test = function(){<br> alert("亲4");<br>}<br>test();<br>
2、把test()中的test等量代换就是 <br> (function(){alert(“亲4”);})() <br> 不要急着问它的好处,不要急着觉<br> 得它有点多此一举,因为,还没有<br> 学习闭包,所以,不能体现它的好处<br>
* 自运行(函数)的其它写法
* 写法一:最外面加括号<br>(function(){<br> console.log("123");<br> }());<br> //这是jslint推荐的写法,好处是,能提醒阅读代码的人,这段代码是一个整体。<br>
* 写法二:最后的括号前面加括号;<br>// (function(){<br>// console.log("heihei");<br>// })();<br>
* 写法三: function前面加运算符,常见的是!与void 。<br>// !function fun(){<br>// console.log("111");<br>// }();<br>// void function fun(){<br>// console.log("111");<br>// }();<br><br>
闭包
官方解释
闭包是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。(函数就是一个表达式)<br> JavaScript中所有的function都是一个闭包。不过一般来说,嵌套的function所产生的闭包更为强大,也是大部分时候我们所谓的“闭包”。<br>* 什么是闭包:闭包是指在函数外部访问函数作用域中变量(局部变量)的函数;或者说闭包就是能够读取其他函数内部变量的函数;或者说闭包是指有权访问另一个函数作用域中的变量的函数;<br> 由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成“定义在一个函数内部的函数”。<br>
通俗解释:
闭包是指有权访问另外一个函数作用域中的变量的函数.可以理解为(能够读取其他函数内部变量的函数)
运用
记数器:
//全局变量 全局变量降低函数的独立性<br>// var count = 0;<br>// function add(){<br>// return count++;<br>// }<br>// console.log(add());<br>// console.log(add());<br>// console.log(add());<br> <br>
//局部变量 函数执行外 局部变量销毁<br>// function add(){<br>// var count = 0;<br>// return count++;<br>// }<br>// console.log(add());<br>// console.log(add());<br>// console.log(add());<br><br><br>
过程
//plus定义在add的内部,可以访问add局部变量count<br> //f为一个全局变量,通过赋值后,成为add的返回值,也就是plus方法<br> //访问到了add中的局部变量count<br> //所以count虽然是局部变量,但不允许被销毁,plus就是闭包<br>
// function add(){<br>// var count = 0;<br>// function plus(){<br>// return count++;<br>// }<br>// return plus;<br>// }<br>// <br>// var f = add();<br>// <br>// console.log(f());<br>// console.log(f());<br>// console.log(f());<br>
//变身<br>// function add(){<br>// var count = 0;<br>// return function(){<br>// return count++;<br>// }<br>// }<br>// <br>// var f = add();<br>// <br>// console.log(f());<br>// console.log(f());<br>// console.log(f());<br>
//继续变身<br>// var f = (function (){<br>// var count = 0;<br>// return function(){<br>// return count++;<br>// }<br>// }());<br>// <br>// console.log(f());<br>// console.log(f());<br>// console.log(f());<br>
闭包的作用:
正常函数执行完毕后,里面声明的变量被垃圾回收处理掉,但是闭包可以让作用域里的 变量,在函数执行完之后依旧保持没有被垃圾回收处理掉<br>* 可以读取函数内部的变量<br>* 让这些变量的值始终保持在内存中。<br>* 增加块级作用域<br>
//java,C,C++都有块作用域,即一对花括号里定义的变量,只在该花括号里起作用。<br>//JS中,就算在花括号里定义的变量(会做声明的提前),属于整个函数内部<br>//JS中,没有块作用域,但是在闭包的写法里,可以体现出来。<br>function outerFunc(){<br> var outVar = 10;<br> var innerF = function (){<br> var innerVar = 20;//该变量虽然隶属于outerFunc内部,但是它的作用域范围只在innerF对应的函数体内,属于块级作用域<br> }<br> alert(innerVar);<br> return innerF;<br>}<br>
使用闭包的注意事项:
* 由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。
* 闭包会在父函数外部改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。
* 示例:局部变量的累加<br> 看程序分析:<br><script type="text/javascript"><br>function outerF(){<br> var t=0;<br> function innerF(){<br> t++; <br> console.log(t);<br> }<br> return innerF;<br>}<br>var f = outerF();<br></script><br><br><br> <input type="button" value="累加一次" onclick="f()">
示例:事件绑定
function outerF(){<br> var t=0;<br> function innerF(){<br> t++; <br> console.log(t);<br> }<br> return innerF;<br>}<br>var f = outerF();<br>
* 用闭包的方式实现mult(5)(6)(7),表示三个数的乘法(5*6*7)<br> function fun(m){<br> return function(n){<br> return function(k){<br> return m*n*k;<br> };<br> }<br> }<br> console.log(fun(5)(6)(7));<br>
<script><br> let list = document.getElementsByTagName("li");<br> <br> for(var i=0; i<list.length; i++){<br> //list[i].index = i;<br> (function fun(i){//自运行<br> list[i].onclick = function(){<br> //alert(this.index+1);<br> alert(i);<br> }<br> }(i));<br> }<br></script>
带参匿名函数
* 带参匿名函数<br>//带参匿名函数<br>var test = function(str1,str2){<br> return str1+str2;<br>}<br>window.onload=function(){<br> alert(test(12,23));<br> alert(test("hello"," 亲"));<br>}<br>
5.函数的属性和方法
prototype属性:<br> 对于引用类型来说,prototype保存着所有实例方法的真正所在,即所有的实例方法都是在prototype中保存着,平时,我们在使用实例方法时,<br> 虽然用对象直接调用,但是真正的保存是在prototype中。在继承中prototype的作用更加明显<br> 我们创建的每个函数都有一个属性是prototype(原型),这是属性是个指针,指向一个对象,该对象的用途是包含所有实例共享的属性和方法。<br> 所有通过同一个构造函数创建的实例对象,都会共享同一个prototype。<br>
示例:<br> function Student(newId,newName,newAge){<br> this.id = newId;<br> this.name = newName;<br> this.age = newAge;<br> <br> //该行为是属于某个对象还是属于整个类组?<br>// this.sleep = function(){<br>// console.log("晚上睡不着,上课睡最香");<br>// }<br> }<br> <br> Student.prototype.sleep = function(){<br> console.log("晚上睡不着,上课睡最香");<br> }<br> <br> let s1 = new Student(1,"大黄",18);<br> let s2 = new Student(2,"小黄",19);<br> <br> s1.sleep();<br> s2.sleep();<br>
区分原型的属性和实例的属性:<br> 实例:用new调用构造函数创建出来的对象叫做实例。<br> 原型属性:写在prototype后面的叫做原型属性 。<br> 实例属性:创建出来的对象,重新给原型属性赋值后,就成为了实例属性。<br>注意原型图:<br> 函数(类)的属性:prototype<br> 实例的属性:_proto_<br><br>
6.apply()和call()
每个函数dui都有两个非继承而来的方法apply()和call(),这两个方法的用途都是用来调用函数(在特定的作用域中),实际上等于设置函数体内的this对象的值。调用函数,实际上就是调用该函数对象的call内部方法。
两者的区别:<br> apply()方法有两个参数,分别是运行函数的作用域,另一个是参数数组(可以是Array也可以是arguments)。<br> call()方法的第一个参数和apply()的第一个参数一样,其它参数就是调用函数的参数(相当于把,apply第二个参数的每个元素单列出来)<br>
//引申出接口的概念<br> //参数1为实力对象,后续参数为eat的参数<br> eat.call(m,"香蕉","牛奶");<br> eat.call(s,"老鼠","人");<br> eat.apply(m,["香蕉","牛奶"]);<br> eat.apply(s,["老鼠","人"]);<br>
apply()和call() 真正的用途:<br><br> 把函数和对象之间进行解耦<br> 即对象和函数之间可以没有关联<br>
插件编写及JQ入门
1.插件
插件是一个独立的功能,与函数相比,他是更加完整的功能。<br>假设将一个汽车比作项目:<br> 函数好比汽车的螺丝,螺帽。<br> 而插件就好比发动机,变速箱。<br>
原生js放大镜插件:
原生js弹出层插件:
class PopPlugin {<br> constructor(newBox) {<br> this.box = newBox;<br> this.btnDiv = null;<br> }<br> setBoxPosition() {<br> this.box.style.display = "block";<br> //要想获取offsetWidth display必须设置为block<br> this.box.style.left = window.innerWidth / 2 - this.box.offsetWidth / 2 + "px";<br> this.box.style.top = window.innerHeight / 2 - this.box.offsetHeight / 2 + "px";<br> this.creatBtn();<br> }<br> creatBtn() {<br> if (this.btnDiv == null) {<br> this.btnDiv = document.createElement("button");<br> }<br> //记得加定位<br> this.btnDiv.style.position = "absolute";<br> this.btnDiv.style.width = 50 + "px";<br> this.btnDiv.style.height = 25 + "px";<br> this.btnDiv.innerHTML = "关闭";<br> this.box.appendChild(this.btnDiv);<br> //必须先有元素才有offsetWidth 这些东西<br> this.btnDiv.style.left = this.box.offsetWidth - this.btnDiv.offsetWidth + "px";<br> this.closeBox();<br> }<br> closeBox(){<br> let that = this;<br> this.btnDiv.onclick = function(){<br> that.box.style.display = "none";<br> }<br> }<br> }<br>
原生jsajax插件:
class myAjax{<br> constructor(newObj) {<br> this.obj = newObj;<br> }<br> ajax() {<br> //1.创建对象 通过兼容模式<br> let xhr;<br> if (window.ActiveXObject) {<br> //ie<br> xhr = new ActiveXObject("Microsoft.XMLHttp");<br> } else {<br> //非ie<br> xhr = new XMLHttpRequest();<br> }<br><br> this.obj.type = this.obj.type.toLowerCase();<br><br> if (this.obj.type == "get") {<br> let urlParam = this.obj.url;<br> urlParam += "?" + this.obj.data;<br> xhr.open(this.obj.type,urlParam, this.obj.isAsyn);<br> xhr.send();<br> } else if (this.obj.type == "post") {<br> xhr.open(this.obj.type, this.obj.url, this.obj.isAsyn);<br> //这句话必须抄 post的请求头<br> xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");<br> xhr.send(this.obj.data);<br> }<br><br><br> let that = this;<br> xhr.onreadystatechange = function() {<br> if (xhr.readyState == 4 && xhr.status == 200) {<br> that.obj.callBack(xhr.responseText);<br> }<br> }<br> }<br> }<br>
原生js选择器插件:
class Select {<br> //静态<br> static $(str) {<br> if (str.charAt(0) == "#") {<br> return document.getElementById(str.substring(1, str.length));<br> } else if (str.charAt(0) == ".") {<br> return document.getElementsByClassName(str.substring(1, str.length))[0];<br> } else {<br> return document.getElementsByTagName(str)[0];<br> }<br> }<br> }<br>
2.jQuery入门
jQuery的特点
jQuery 是一个快速的简洁的javascript框架,可以简化查询DOM对象、处理事件、制作动画、处理Ajax交互过程。<br>1>提供了强大的功能函数<br>2>解决浏览器兼容性问题<br>3>纠正错误的脚本知识<br>4>体积小,使用灵巧(只需引入一个js文件)<br>5>易扩展、插件丰富<br>
jQuery的作用:
* 程序员的角度:简化JavaScript和Ajax编程,能够使程序员从设计和书写繁杂的JS应用中解脱出来,将关注点转向功能需求而非实现细节上,从而提高项目的开发速度。<br>* 用户体验的角度:改善了页面视觉效果,增强了与页面的交互性,体验更绚丽的网页物资。<br><br>方便地选择页面元素(模仿CSS选择器更精确、灵活)<br>动态更改页面样式/页面内容(操作DOM,动态添加、移除样式)<br>控制响应事件(动态添加响应事件)<br>提供基本网页特效(提供已封装的网页特效方法)<br>快速实现通信(ajax)。<br>
如何引入JQuery包:
* jQuery库文件不需要安装,只需使用<script>标签引入到HTML文件中,拿到jQuery的库文件后,就跟自己写的JS文件同样的引入方式,即可,以下是几种引入方式<br> * a.引入本地的Jquery<br> * b.引入cdn在线提供的库文件(稳定可靠高速)<br><script src="http://libs.baidu.com/jquery/2.0.0/jquery.js"></script><br> 写第一个JQuery案例 <script type="“text/javascript”" src="“”"></script><br> <script type="“text/javascript”"><br> $(function(){<br> alert(“jQuery 你好!”);<br> });<br> </script>
写法
* 在JQuery库中,$是JQuery的别名,$()等效于就jQuery()。即以上代码等价于:jQuery(function(){alert(“jQuery 你好!”);});<br><br>$()相当于页面初始化函数,当页面加载完毕,会执行$(),即jQuery()。<br><br><br>* $(function(){ })<br>当页面加载完毕,会执行$(),即jQuery()。<br>$(function(){ }) 是$(document).ready(function(){});的简写。<br>
<br>* $(document).ready(function(){})和window.onload 的区别<br>
* ready表示文档已加载完成(不包含图片等非文字媒体文件)<br>* onload是指页面包含图片在内的所有元素都加载完成<br>* $(document).ready(function(){})要比window.onload先执行<br>
* jQuery包装集
在jQuery的世界中将所有的对象,无论是一个还是一组,都封装成一个jQuery包装集,即集合。也就是说,$()的返回结果都是集合,不是单个对象。<br> 比如获取包含一个元素的jQuery包装集。<br> //testDiv是页面某元素的id<br> var jQueryObject = $(“#testDiv");<br> 虽然,通过id获得的是一个元素对象,但是依然以集合的方式返回,只不过,集合中只有一个元素而已。<br><br><br>* jQuery包装集与DOM 对象的互转<br> * jQuery包装集转DOM对象<br> * DOM对象转jQuery包装集<br><br>jQuery包装集是一个集合,所以我们可以通过索引器访问其中的某一个元素<br>//testDiv是页面某元素的id<br>var domObject = $(“#testDiv”)[0];<br>//testDiv是页面某元素的id<br>var div = document.getElementById("testDiv");<br>var domToJQueryObject = $(div);<br>
jQuery选择器
定义
* jQuery提供了异常强大的选择器用来帮助我们获取页面上的对象,并且将对象以jQuery包装集的形式返回(就像DOM中获得页面的节点一样)<br>“$”符号在jQuery中代表对jQuery对象的引用,返回jQuery对象<br>如:<br>//根据id获取jQuery包装集<br>var jQueryObject = $(“#testDiv”);<br>
1.基础选择器
//1.ID选择器(只代表唯一一个元素)<br> //两种写法<br> //a.js写法<br> //$("#box1").css("backgroundColor","red");<br> //b.css写法<br> //$("#box1").css({backgroundColor:"yellow"});<br> <br> //2.类选择器<br> //$(".box").css({backgroundColor:"red"});<br> <br> //3.标签选择器<br> //$("p").css({backgroundColor:"red"});<br> <br> //4.群组选择器<br> //$("strong,p,span").css({backgroundColor:"red"});<br> <br> //5.通配符选择器(这是选择全部元素)<br> $("*").css({backgroundColor:"red"});<br>
2.层次选择器
//1.后代选择器<br> //$("body div").css({backgroundColor:"red"});<br> //2.子选择器<br> //$("body>div").css({backgroundColor:"skyBlue"});<br> //3.相邻选择器<br> //$("#box1+div").css({backgroundColor:"skyBlue"});<br> //4.兄弟选择器<br> //$("#box1~div").css({background:"yellow"});<br>
3.属性选择器
//div带有class属性的选择器<br> //$("div[class]").css("backgroundColor","red");<br> //div带有id属性的选择器<br> //$("div[id]").css("backgroundColor","green");<br> //指定id为box1<br> //$("div[id='box1']").css("backgroundColor","yellow");<br> //还可以同时存在多个属性<br> //$("div[class][id]").css("backgroundColor","skyblue");<br>
4.伪类选择器
//选中偶数行 下标从0开始<br> //$("div:even").css("backgroundColor","skyblue");<br> //选中奇数行<br> //$("div:odd").css("backgroundColor","skyblue");<br> //选中第一个元素<br> //$("div:first").css("backgroundColor","skyblue");<br> //选中最后一个元素<br> //$("div:last").css("backgroundColor","skyblue");<br> //eq(n)选中第N个div元素 <br> //$("div:eq(1)").css("backgroundColor","skyblue");<br> // 也可以这样写<br> //$("div").eq(1).css("backgroundColor","skyblue");<br> //div里除了#box2元素,其他都被影响<br> //$("div:not('#box2')").css("backgroundColor","skyblue");<br> // 也可以这样写<br> //$("div").not('#box3').css("backgroundColor","skyblue");<br> //gt(n) 匹配出大于n<br> // $("div:gt(1)").css("backgroundColor","skyblue");<br> //lt(n) 匹配出小于n<br> //$("div:lt(3)").css("backgroundColor","skyblue");<br>
5.内容选择器
//contains<br> //字符串中存在hello world的元素<br> //$("div:contains('hello world')").css({background:"red"});<br> //empty<br> //找内容为空的选择器,空格什么东西都不能有<br> //$("div:empty").html("666");<br> //has(选择器)<br> //根据子元素进行筛选<br> $("div:has('#s')").css("background","red");<br>
6.可见性选择器
//改变不可见元素的样式<br> $("tr:hidden").css("background","green");<br> //改变可见元素的样式<br> $("tr:visible").css("background","red");<br>
3.jQuery遍历
什么是遍历?<br>jQuery 遍历,意为“移动”,用于根据其相对于其他元素的关系来“查找”(或选取)HTML 元素。以某项选择开始,并沿着这个选择移动,直到抵达您期望的元素为止。<br>下图展示了一个家族树。通过 jQuery 遍历,您能够从被选(当前的)元素开始,轻松地在家族树中向上移动(祖先),向下移动(子孙),水平移动(同胞)。这种移动被称为对 DOM 进行遍历。<br>图示解释:<br>
//next下一个元素<br> //$("#box2").next().css({background:"red"});<br> //nextAll下面所有元素<br> //$("#box2").nextAll().css({background:"red"});<br> //prev上一个元素<br> //$("#box2").prev().css({background:"red"});<br> //prev上面所有元素<br> //$("#box2").prev().css({background:"red"}); <br> //该方法必须传参<br> //Dom元素的遍历<br> //find("参数") 寻找body下的所有div 后代遍历的方法<br> //$("body").find("div").css({background:"yellow"}); <br> //children body的div会被影响<br> //$("body").children("div").css({background:"yellow"});<br> //children 不传参时默认传递通配符<br> //$("body").children().css({background:"yellow"});<br>
4.jQuery的文本与事件
1.文本的值与元素内容的读写<br> val():文本的值<br> html():元素的内容<br>
//使用val()方法来读写文本内容来<br> //val() == value<br> //读<br> console.log($("input").val());<br> //写<br> $("input").val(888);<br> <br> //使用html()方法来读写元素的内容来<br> //html() == innerHTML<br> console.log($("p").html());<br>
2.jQuery的事件全都去除on
//注意:$(this)的写法<br> $(this).css({background:"red"});<br> });<br> <br> $("div").mouseover(function(){<br> //注意:$(this)的写法<br> $(this).css({background:"yellow"});<br> });<br> <br> $("div").mouseout(function(){<br> //注意:$(this)的写法<br> $(this).css({background:"blue"});<br>
jQuery的事件可以传自定义参数:
$(function(){<br> $("div").click({name:"老王",pwd:123456},function(evt){<br> let e = evt || event;<br> console.log(e.data);<br> });<br> });<br>
5.jQuery动画
1.简单动画
a.方法:hide,show,toggle <script><br> $(function(){<br> //简单动画hide,show,toggle<br> $("button").eq(0).click(function(){<br> //第二个参数为在动画完成时执行的函数,每个元素执行一次。<br> $("div").hide(1000,function(){<br> console.log("heihei");<br> });<br> });<br> $("button").eq(1).click(function(){<br> $("div").show(1000);<br> });<br>// $("button").eq(2).click(function(){<br>// $("div").toggle(1000);<br>// });<br> //做一些奇奇怪怪的事情<br> $("button").eq(2).click(function(){<br> $("div").toggle(1000,function(){<br> $("div").toggle(1000,arguments.callee);<br> });<br> });<br> });<br></script>
$(function(){<br> //简单动画hide,show,toggle<br> $("button").eq(0).click(function(){<br> //第二个参数为在动画完成时执行的函数,每个元素执行一次。<br> $("div").hide(1000,function(){<br> console.log("heihei");<br> });<br> });<br> $("button").eq(1).click(function(){<br> $("div").show(1000);<br> });<br>// $("button").eq(2).click(function(){<br>// $("div").toggle(1000);<br>// });<br> //做一些奇奇怪怪的事情<br> $("button").eq(2).click(function(){<br> $("div").toggle(1000,function(){<br> $("div").toggle(1000,arguments.callee);<br> });<br> });<br> });<br>
b.方法:slideUp,slideDown,slideToggle
//滑动<br> $(function() {<br> $("button").eq(0).click(function() {<br> //第二个参数为在动画完成时执行的函数,每个元素执行一次。<br> $("div").slideUp(1000, function() {<br> console.log("heihei");<br> });<br> });<br> $("button").eq(1).click(function() {<br> $("div").slideDown(1000);<br> });<br> // $("button").eq(2).click(function(){<br> // $("div").toggle(1000);<br> // });<br> //做一些奇奇怪怪的事情<br> $("button").eq(2).click(function() {<br> $("div").slideToggle(1000, function() {<br> $("div").slideToggle(1000, arguments.callee);<br> });<br> });<br> });<br>
c.淡入淡出:常用 fadeIn fadeOut fadeToggle
$(function() {<br> $("button").eq(0).click(function() {<br> //第二个参数为在动画完成时执行的函数,每个元素执行一次。<br> $("div").fadeIn(1000, function() {<br> console.log("heihei");<br> });<br> });<br> $("button").eq(1).click(function() {<br> $("div").fadeOut(1000);<br> });<br> // $("button").eq(2).click(function(){<br> // $("div").toggle(1000);<br> // });<br> //做一些奇奇怪怪的事情<br> $("button").eq(2).click(function() {<br> $("div").fadeToggle(1000, function() {<br> $("div").fadeToggle(1000, arguments.callee);<br> });<br> });<br> });<br>
2.自定义动画animate:
$("button").eq(0).click(function(){<br>// $("#box").animate({<br>// width:"500px",<br>// height:50,<br>// opacity:0.3,<br>// left:"200px"<br>// },1000).animate({//列队动画<br>// width:"100px",<br>// height:500,<br>// opacity:1,<br>// left:"20px"<br>// });<br><br><br> $("#box").animate({<br> left:0<br> },1000).animate({//列队动画<br> left:500<br> },1000).animate({<br> top:500<br> },1000).animate({<br> left:0<br> },1000).animate({<br> top:30<br> });<br> });<br> <br> $("button").eq(1).click(function(){<br> //无参数stop():立刻结束当前动画<br> //参数1:清空动画队列<br> //参数2:立刻执行完当前动画<br> $("#box").stop(true,true);<br> });<br> });<br>
6.手风琴
1.简单版本
<br> <br> <style type="text/css"><br> *{<br> margin: 0;<br> padding: 0;<br> }<br> ul{<br> width: 500px;<br> height: 100px;<br> background: red;<br> position: relative;<br> margin: 0 auto;<br> }<br> ul li{<br> list-style: none;<br> width: 40px;<br> height: 100px;<br> background: yellow;<br> float:left;<br> border: 1px solid black;<br> }<br> </style><br> <br> <br> <ul><br> <li style="overflow: hidden; width: 40px;"></li><br> <li style="overflow: hidden; width: 40px;"></li><br> <li style="overflow: hidden; width: 40px;"></li><br> <li style="overflow: hidden; width: 240px;"></li><br> </ul><br> <br><br><script src="js/jQuery.js" type="text/javascript" charset="utf-8"></script><br><script><br> $(function(){<br> $("li").mouseover(function(){<br> $(this).stop().animate({<br> width:240<br> }).siblings("li").stop().animate({<br> width:40<br> });<br> });<br> });<br></script>
2.完美版
<br> <br> <style type="text/css"><br> *{<br> margin: 0;<br> padding: 0;<br> }<br> ul{<br> width: 400px;<br> height: 100px;<br> background: red;<br> position: relative;<br> margin: 0 auto;<br> }<br> ul li{<br> list-style: none;<br> width: 40px;<br> height: 100px;<br> background: yellow;<br> float:left;<br> border: 1px solid black;<br> overflow: hidden;<br> }<br> <br> ul li img{<br> width: 240px;<br> height: 100px;<br> background-size: 240px 100px;<br> }<br> </style><br> <br> <br> <ul><br> <li style="overflow: hidden; width: 40px;"><br> <img src="images/1.jpg"><br> </li><br> <li style="overflow: hidden; width: 40px;"><br> <img src="images/2.jpg"><br> </li><br> <li style="overflow: hidden; width: 40px;"><br> <img src="images/3.jpg"><br> </li><br> <li style="overflow: hidden; width: 240px;"><br> <img src="images/4.jpg"><br> </li><br> </ul><br> <br><br><script src="js/jQuery.js" type="text/javascript" charset="utf-8"></script><br><script><br> $(function(){<br> $("li").mouseover(function(){<br> $(this).stop().animate({<br> width:240<br> }).siblings("li").stop().animate({<br> width:40<br> });<br> });<br> });<br></script>
localStorage、sessionStorage与设计模式
1.localStorage和sessionStorage功能
早期的web中使用cookies在客户端保存诸如用户名等简单的信息,但是,在使用cookies存储永久数据存在以下问题。<br>1.cookies的大小限制在4kB,不适合大量的数据存储。<br>2.浏览器还限制站点可以在用户计算机上存储的cookies的数量。<br>3 cookies是随HTTP事务一起被发送的,因此会浪费一部分带宽。<br>HTML5很好的提供了本地存储的功能,以键值对存储的解决方案,支持容量至少为4M,HTML5的web提供了两种客户端存储方式。<br>localStorage:是一种没有时间限制的数据存储方式,可以将数据永久保存在客户端。<br>sessionStorage:指的是针对一个session的数据存储,即将数据保存在session对象中,当关闭浏览器后,这些数据就被删除。因此sessionStorage不是一种持久化的本地存储,仅仅是会话级别的存储。<br>
子主题
存:三种方法<br> let ls = localStorage;<br> ls.setItem("id",666);<br> ls.name = "老王";<br> ls["pwd"] = 123456;<br> let ss = sessionStorage;<br> ss.setItem("id",666);<br> ss.name = "老王";<br> ss["pwd"] = 123456;<br>
取:<br> console.log(ls.getItem("id"));<br> console.log(ls.name);<br> console.log(ls["pwd"]);<br>
改:与存的方式相同,key不在则创建,key在则修改value。<br>遍历: <br> let ls = localStorage;<br> <br> for(let i=0;i
2.设计模式是什么
* 定义:模式是在一个上下文中,对一个问题的解决方案。即模式的四要素:名字、上下文、问题和解决方案。
分类:23种设计模式:<br> 创建型:5种<br> 结构型:7种<br> 行为型:11种<br>
为什么使用设计模式:<br>* 尽量用一种标准的方式描述设计经验<br>* 为设计者提供一种通用的语言<br>* 增加复用性,减少设计的多样性<br>* 增强设计变更的灵活性<br>* 提高设计文档的质量<br>* 增强设计的可理解性<br>
3.单例模式:
* 单例模式指的是一个类只能有一个实例,这样的类被称为单例类,或者单态类,即Singleton Class
* 单例类的特点<br> * 单例类只可有一个实例<br> * 它必须自己创立这唯一的一个实例<br> * 它必须给所有其它的类提供自己这一实例<br>
单例模式的思路是:一个类能返回一个对象的引用(并且永远是同一个)和一个获得该实例的方法(静态方法,通常使用 getInstance 名称)。<br> 那么当我们调用这个方法时,如果类持有的引用不为空就返回该引用,否者就创建该类的实例,并且将实例引用赋值给该类保持的那个引用再返回。<br> 同时将该类的构造函数定义为私有方法,避免其他函数使用该构造函数来实例化对象,只通过该类的静态方法来得到该类的唯一实例。<br><br>对于 JS 来说,巨大的灵活性使得其可以有多种方式实现单例模式,使用闭包方式来模拟私有数据,按照其思路可得<br>
<br> var single = (function() {<br> var unique;<br> function getInstance() {<br> if (unique === undefined) {<br> unique = new Construct();<br> }<br> return unique;<br> }<br> function Construct() {<br> // ... 生成单例的构造函数的代码<br> }<br> return {<br> getInstance: getInstance<br> }<br> })();<br>
2.添加构造方法内部属性<br> function Student(newId,newName){<br> if(Student.unique == undefined){<br> this.id = newId;<br> this.name = newName;<br> Student.unique = this;<br> }else{<br> return Student.unique;<br> }<br> }<br> <br> let s1 = new Student(111,"小明");<br> let s2 = new Student(222,"老王");<br> console.log(s1.id,s1.name);<br> console.log(s2.id,s2.name);<br> s2.id = 666;<br> s2.name = "heihei";<br> console.log(s1.id,s1.name);<br> console.log(s2.id,s2.name);<br> console.log(s1 === s2);<br>
3.闭包<br> 对于灵活的JS来说,任何问题都能找到 n 种答案,只不过让我自己去掂量孰优孰劣而已,下面就列举闭包实现单例模式的方法,无非也就是将创建了的单例缓存而已。<br> let singletion = (function (newId,newName){<br> var unique;<br> function Student(newId,newName){<br> this.id = newId;<br> this.name = newName;<br> }<br> if(unique==undefined){<br> unique = new Student(newId,newName);<br> }<br> return function(){<br> return unique;<br> };<br> })(1,"小明");//切记必须自运行 为什么呢?<br> <br> let s1 = singletion();<br> let s2 = singletion();<br> s1.id = 666;<br> console.log(s1.id,s2.id);<br> console.log(s1 === s2);<br>
4.代理模式
代理模式的定义是把对一个对象的访问, 交给另一个代理对象来操作。<br> 如:<br> 一般人需要打官司,需要找代理律师(术业有专攻);<br> 你需要打扫房子,可以找保洁公司(术业有专攻);<br> 我们在租房子的时候去找中介(因为你对该地区房屋的信息掌握的不够全面,希望找一个更熟悉的人去帮你做)<br><br><br>* 应用场景:<br>如果已有的方法在使用的时候需要对原有的方法进行改进,此时有两种办法:<br>1、修改原有的方法来适应。这样违反了“对扩展开放,对修改关闭”的原则。<br>2、就是采用一个代理类调用原有的方法,且对产生的结果进行控制。这种方法就是代理模式。<br>使用代理模式,可以将功能划分的更加清晰,有助于后期维护!<br><br>class Nurse{<br> constructor() {<br> <br> }<br> takeBabyEat()<br> //假设要扩展功能,可以在这里添加代码<br> console.log("Nurse:takeBabyEat");<br> }<br> }<br> class Mother{<br> constructor(newNurse) {<br> this.nurse = newNurse;<br> }<br> takeBabyEat(){<br> this.nurse.takeBabyEat();<br> }<br> }<br> <br> let n = new Nurse();<br> let m = new Mother(n);<br> m.takeBabyEat();<br>
4.工厂模式
工厂模式:就是用工厂的思路,创建对象。工厂是造产品的。现在用工厂来造对象。即一个工厂可以制造很多种类型的对象,这些对象一般具有共同的父类,即相似的类。<br> 为什么使用工厂模式?<br> 使用一个类(通常为单体)来批量生成实例.<br><br> 以下几种情景下工厂模式特别有用:<br> 对象的构建十分复杂<br> 需要依赖具体环境创建不同实例<br> 处理大量具有相同属性的小对象 <br><br> 我们所熟悉的工厂是不是重复生产,编程中称为迭代!<br> 比如生产一颗螺丝钉,一个流水线就是不停的生产螺丝钉。<br> 再如联想电脑,联想公司的笔记本生产线只负责生产笔记本,不能生产出TV吧。<br> 但是如果有TV生产线,那么TV生产生只能生产TV,而且每天都是重复的工作。<br> 当然笔记本生产想也是重复的。<br> 编程中我们也想让编程跟流水线一样,想用的时候开启一下工厂就可以得到一个想要的程序!<br> 注意,每次得到的程序和已经得到的程序不会是同一个程序。<br> 就好像生产出两台笔记本,肯定不是同一个笔记本!!<br> function Factory(color){//生产笔记本的流水线<br> return {<br> "screen":"this is screen",<br> "keybord":"this is keybord",<br> "mouse":"this is mouse",<br> "USB":"this is API of USB",<br> "storage":"this is storage",<br> "color":color<br> }<br> }<br> //来一个黄色的笔记本<br> var _yellow=Factory("yellow");<br> //来一个黑色的笔记本<br> var _black=Factory("black");<br> //来一个紫色的笔记本<br> var _purple=Factory("purple");<br> //console.log(_yellow,_black,_purple);<br> //是不是很完美<br>
5.抽象工厂模式
抽象工厂模式:使用子类来决定一个变量成员应该为哪个具体的类的实例.<br>抽象工厂<br>抽象工厂模式是所有形态的工厂模式中最为抽象和最具一般性的一种形态。<br>抽象工厂模式是指当有多个抽象角色时,使用的一种工厂模式。<br>抽象工厂模式可以向客户端提供一个接口,使客户端在不必指定产品的具体的情况下,创建多个产品族中的产品对象。<br> function AbstractFactory(){//生产5.8inch两毫米厚度钻石手机屏幕<br> return {<br> "thickness":"2mm",<br> "size":"5.8inch",<br> "material":"Diamonds"<br> }<br> }<br> function Iphone(){<br> this.shell="铝合金";<br> this.model="7Plus";<br> this.screen=AbstractFactory();<br> }<br> function Mate8(){<br> this.shell="铝合金";<br> this.model="Mate8";<br> this.screen=AbstractFactory();<br> }<br> function P9(){<br> this.shell="铝合金";<br> this.model="P9";<br> this.screen=AbstractFactory();<br> }<br> //那货是个热门货,什么手机都能用,要发财的节奏<br>
6.观察者模式
定义:<br>观察者模式是软件设计模式的一种常见的设计模式,又称发布订阅模式。在这种模式中,并不是单纯的一个对象调用另一个对象的方法,而是一个对象订阅另一个对象的特定活动并在其状态发生改变后获得通知,然后执行相应的操作。订阅者也称为观察者,而被观察的对象则被称为发布者或主题。当一个事件发生,发布者将会向所有订阅此事件的对象以事件对象的形式传递消息。<br>比如说:前段时间世界杯,很多人都看球赛,但人精力还是有限的,经常可能会因为这样或哪样的原因错过看球赛的时间,在这种情况下很多直播网站提供了一个很贴心的服务,那就是开播提醒,当用户订阅了这个提醒,那么在某个时刻比如球赛开播前5分钟系统会给所有订阅开播提醒的用户以短信或者其他有效形式发送通知,提醒用户球赛马上开播了,这个就是观察者模式的典型应用。<br>
要素:<br>观察者模式最重要的两个要素是:发布者、订阅者(观察者),发布者发送消息,订阅者订阅特定消息并接受发布者发送的消息。<br>
//观察者(订阅者) 订阅update消息<br> var sub1 = {<br> update: function(what) {<br> console.log(what+"sub1根据消息做什么");<br> }<br> }<br><br><br> var sub2 = {<br> update: function(what) {<br> console.log(what+"sub2根据消息做什么");<br> }<br> }<br><br><br> var sub3 = {<br> update: function(what) {<br> console.log(what+"sub3根据消息做什么");<br> }<br> }<br> <br> //发布者<br> class Dep{<br> constructor(newSubs) {<br> this.subs = newSubs;<br> }<br> //消息<br> information(){<br> for(let i=0; i
7.适配器模式
结构模式_适配器模式<br>* 应用场景:<br> 适配器模式,一般是为要使用的接口,不能完全符合本应用或本系统使用,而需引入的中间适配层类或对象的情况;<br> 如:手机充电器,Android手机的充电线没法给iPhone手机充电,因为,口不对,插不进去,如果有一个能够Android手机的充电线的头转换成能插在iPhone手机上的设备,这个就是适配器(转接口,转接头),恰好已经有了。<br> 再如:你需要6v的电压,但是,目前墙上有一个提供220v电压的插孔,怎么办,有个设备能把220v转成6v,交流转成直流,这个设备就是适配器。<br> 由于旧的系统,或第三方应用提供的接口(更多特指函数的参数),与我们定义的接口不匹配,就无法使用这样旧的,或第三方的接口,这时我们就使用适配类继承待适匹配的类,并让适配类实现接口的方式来引入旧的系统或第三方应用的接口;<br> class OldClass{<br> constructor() {<br> <br> }<br> oldFun(param1){//假设在使用oldFun的地方突然有两个参数<br> //此时就需要一个转换函数来实现该功能<br> <br> }<br> }<br> <br> class Adapter{<br> constructor(newOldClass) {<br> this.OldClass = newOldClass;<br> }<br> //newFun就是转换函数<br> newFun(param1,param2){<br> this.OldClass.oldFun(param1);<br> param2 = "heihei";//模拟对参数2的操作<br> }<br> }<br> <br> //定义一个适配器,由适配器把旧类的对象包装起来。<br> let a = new Adapter(new OldClass());<br> //调用适配器的newFun函数,最终还是得调用旧类的oldFun函数,但满足了操作两个函数的功能<br> a.newFun(1,2);<br>
子主题
* 用闭包的方式实现mult(5)(6)(7),表示三个数的乘法(5*6*7)<br> function fun(m){<br> return function(n){<br> return function(k){<br> return m*n*k;<br> };<br> }<br> }<br> console.log(fun(5)(6)(7));<br>
闭包与函数对象
函数对象
函数的三种定义方式
函数声明 声明的方式有函数的提升<br>function test(ord){<br> alert(“亲”+ord+“!”);<br>}<br>
函数表达式(匿名函数)<br>var test = function(ord){<br> alert(“亲”+ord+“!”);<br>}<br>
let test = new Function(参数1,参数2...,"函数体");<br><br>示例:<br>// test();<br>// function test(){ // 有变量提升<br>// console.log("heihei");<br>// }<br>// test(); <br>// let test = function(){<br>// console.log("heihei");<br>// } <br>// let test = new Function("param","console.log(param)");<br>// test(666);<br>
函数是功能完整的类
* ECMAScript 中函数实际上是功能完整的对象。即函数就是一个对象
格式:<br> var functionName = new Function(arg1,..., argN, function_body)<br> 每个 arg 都是一个参数,最后一个参数是函数主体(要执行的代码)。这些参数必须是字符串。<br>
示例一(无参):<br> var sayHello = new Function("alert(\"hello 哥们1111!\");"); <br>
示例二(有参):<br> var sayHi = new Function("sN", "sM", "alert(sN + sM);");<br> 等价于以前的:<br> function sayHi(sN, sM) {<br> alert(sN + sM);<br> }<br>
既然定义一个函数就是创建一个函数对象。<br> * 那么只要执行函数定义的代码,就会创建新的函数对象<br>
回忆闭包中,一旦父函数被调用一次,闭包就会新创建一个函数。<br> function f1(){<br> var n = 250;<br> function f2(){<br> n++; <br> alert(n);<br> }<br> return f2;<br> }<br> var f21 = f1();//f21就是f2<br> f21();//调用f2;<br> f21();//调用f2;<br> var f22= f1();//f22就是f2<br> f22();//调用f2;<br> f22();//调用f2;<br> 虽然f21和f22的代码一样,但是,它们是两个不同的对象,即,每个的n值不一样。<br>
所以函数等价于类?<br><br> * 函数名作为参数和返回值:<br> * 函数名能作为返回值,那么匿名函数也就可以作为返回值。<br><br> 当我们知道函数是对象,函数名是对象名(变量名)时,函数名作为另外一个函数的参数和返回值就不难理解了。还记得当时讲数组的sort函数是,参数就是另外一个函数名。<br>
this的回顾:
1.事件绑定的方法<br>2.构造函数<br>3.类中出现的方法<br>4.普通函数<br>
arguments
* arguments对象保存函数的所有参数,虽然可以像数组一样的访问每个参数,但是,并不是标准的数组(没法使用push等函数);
arguments对象不但保存着所有的参数,而且还有一个名叫callee的属性。Callee属性是个指针,指向了arguments对象所在的函数。Callee属性有个好处,看如下阶
示例:<br> function fun(a){<br> console.log(a);<br> for(let i=0;iarguments.length; i++){<br> console.log(arguments[i]);}<br> }<br> fun(11,23,34,53,63);<br><br>
乘递归的示例,即可明白<br>function fun(n){<br> let c = 0;<br> if(n==1){<br> return c = 1;<br> }else{<br> c = arguments.callee(n-1)*n;<br> }<br> <br> return c;<br> }<br> <br> console.log(fun(10));<br>如果函数名进行修改,函数体不用修改。<br>
匿名函数
* 匿名函数(anonymous)的概念:
没有名字的函数就是匿名函数。当某个函数,function 关键字后面没有标识符的时候,那么它就是一个匿名函数(lamda,拉姆达函数)。
如:<br> function(){<br> alert(“亲,我来自无名函数”);<br>}<br>以前曾经写过 以下的代码:<br> window.onload = function(){<br> ……<br> }<br>这就是把匿名函数赋给了事件属性。<br>
匿名函数的四种写法
* 写法一: 定义一个函数,把函数名赋给 onload属性<br>function test(){<br> alert("亲1");<br>}<br>
* 写法二 : 定义一个匿名函数,直接赋给 onload属性<br>window.onload = function(){<br> alert("亲2");<br>}<br>
* 写法三 :定义一个匿名函数赋给一个变量;然后把变量赋给onload事件属性; 比写法二多了个中间变量而已<br>var test = function(){<br> alert("亲3");<br>}<br>
* 写法四: 定义一个匿名函数赋给一个变量,用变量(当作函数名)来调用函数;<br>var test = function(){<br> alert("亲4");<br>}<br>test();<br>
常见用法
匿名函数的常见用法:<br> * 函数表达式(var test = function(){})<br> * 事件处理函数 (window.onload = funciont(){})<br> * 自运行(立即执行)<br> * 闭包里的返回值 (闭包中会讲)<br><br>其实,当把匿名函数赋给一个变量时,就知道还可以用在何处(如:作为另外一个函数的参数),但不能进行运算<br>
自运行:
* 什么是自运行(函数)<br>* 自运行(函数)示例:<br><br> 能够自己运行的一个函数。即,不用别人调用就能运行的函数。这是学习闭包的基础。<br> (function(){alert(“亲4”);})()<br><br>推导一下:<br>
1、已知:<br>var test = function(){<br> alert("亲4");<br>}<br>test();<br>
2、把test()中的test等量代换就是 <br> (function(){alert(“亲4”);})() <br> 不要急着问它的好处,不要急着觉<br> 得它有点多此一举,因为,还没有<br> 学习闭包,所以,不能体现它的好处<br>
* 自运行(函数)的其它写法
* 写法一:最外面加括号<br>(function(){<br> console.log("123");<br> }());<br> //这是jslint推荐的写法,好处是,能提醒阅读代码的人,这段代码是一个整体。<br>
* 写法二:最后的括号前面加括号;<br>// (function(){<br>// console.log("heihei");<br>// })();<br>
* 写法三: function前面加运算符,常见的是!与void 。<br>// !function fun(){<br>// console.log("111");<br>// }();<br>// void function fun(){<br>// console.log("111");<br>// }();<br><br>
闭包
官方解释
闭包是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。(函数就是一个表达式)<br> JavaScript中所有的function都是一个闭包。不过一般来说,嵌套的function所产生的闭包更为强大,也是大部分时候我们所谓的“闭包”。<br>* 什么是闭包:闭包是指在函数外部访问函数作用域中变量(局部变量)的函数;或者说闭包就是能够读取其他函数内部变量的函数;或者说闭包是指有权访问另一个函数作用域中的变量的函数;<br> 由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成“定义在一个函数内部的函数”。<br>
通俗解释:
闭包是指有权访问另外一个函数作用域中的变量的函数.可以理解为(能够读取其他函数内部变量的函数)
运用
记数器:
//全局变量 全局变量降低函数的独立性<br>// var count = 0;<br>// function add(){<br>// return count++;<br>// }<br>// console.log(add());<br>// console.log(add());<br>// console.log(add());<br> <br>
//局部变量 函数执行外 局部变量销毁<br>// function add(){<br>// var count = 0;<br>// return count++;<br>// }<br>// console.log(add());<br>// console.log(add());<br>// console.log(add());<br><br><br>
过程
//plus定义在add的内部,可以访问add局部变量count<br> //f为一个全局变量,通过赋值后,成为add的返回值,也就是plus方法<br> //访问到了add中的局部变量count<br> //所以count虽然是局部变量,但不允许被销毁,plus就是闭包<br>
// function add(){<br>// var count = 0;<br>// function plus(){<br>// return count++;<br>// }<br>// return plus;<br>// }<br>// <br>// var f = add();<br>// <br>// console.log(f());<br>// console.log(f());<br>// console.log(f());<br>
//变身<br>// function add(){<br>// var count = 0;<br>// return function(){<br>// return count++;<br>// }<br>// }<br>// <br>// var f = add();<br>// <br>// console.log(f());<br>// console.log(f());<br>// console.log(f());<br>
//继续变身<br>// var f = (function (){<br>// var count = 0;<br>// return function(){<br>// return count++;<br>// }<br>// }());<br>// <br>// console.log(f());<br>// console.log(f());<br>// console.log(f());<br>
闭包的作用:
正常函数执行完毕后,里面声明的变量被垃圾回收处理掉,但是闭包可以让作用域里的 变量,在函数执行完之后依旧保持没有被垃圾回收处理掉<br>* 可以读取函数内部的变量<br>* 让这些变量的值始终保持在内存中。<br>* 增加块级作用域<br>
//java,C,C++都有块作用域,即一对花括号里定义的变量,只在该花括号里起作用。<br>//JS中,就算在花括号里定义的变量(会做声明的提前),属于整个函数内部<br>//JS中,没有块作用域,但是在闭包的写法里,可以体现出来。<br>function outerFunc(){<br> var outVar = 10;<br> var innerF = function (){<br> var innerVar = 20;//该变量虽然隶属于outerFunc内部,但是它的作用域范围只在innerF对应的函数体内,属于块级作用域<br> }<br> alert(innerVar);<br> return innerF;<br>}<br>
使用闭包的注意事项:
* 由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。
* 闭包会在父函数外部改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。
* 示例:局部变量的累加<br> 看程序分析:<br><script type="text/javascript"><br>function outerF(){<br> var t=0;<br> function innerF(){<br> t++; <br> console.log(t);<br> }<br> return innerF;<br>}<br>var f = outerF();<br></script><br><br><br> <input type="button" value="累加一次" onclick="f()">
示例:事件绑定
function outerF(){<br> var t=0;<br> function innerF(){<br> t++; <br> console.log(t);<br> }<br> return innerF;<br>}<br>var f = outerF();<br>
* 用闭包的方式实现mult(5)(6)(7),表示三个数的乘法(5*6*7)<br> function fun(m){<br> return function(n){<br> return function(k){<br> return m*n*k;<br> };<br> }<br> }<br> console.log(fun(5)(6)(7));<br>
<script><br> let list = document.getElementsByTagName("li");<br> <br> for(var i=0; i<list.length; i++){<br> //list[i].index = i;<br> (function fun(i){//自运行<br> list[i].onclick = function(){<br> //alert(this.index+1);<br> alert(i);<br> }<br> }(i));<br> }<br></script>
带参匿名函数
* 带参匿名函数<br>//带参匿名函数<br>var test = function(str1,str2){<br> return str1+str2;<br>}<br>window.onload=function(){<br> alert(test(12,23));<br> alert(test("hello"," 亲"));<br>}<br>
5.函数的属性和方法
prototype属性:<br> 对于引用类型来说,prototype保存着所有实例方法的真正所在,即所有的实例方法都是在prototype中保存着,平时,我们在使用实例方法时,<br> 虽然用对象直接调用,但是真正的保存是在prototype中。在继承中prototype的作用更加明显<br> 我们创建的每个函数都有一个属性是prototype(原型),这是属性是个指针,指向一个对象,该对象的用途是包含所有实例共享的属性和方法。<br> 所有通过同一个构造函数创建的实例对象,都会共享同一个prototype。<br>
示例:<br> function Student(newId,newName,newAge){<br> this.id = newId;<br> this.name = newName;<br> this.age = newAge;<br> <br> //该行为是属于某个对象还是属于整个类组?<br>// this.sleep = function(){<br>// console.log("晚上睡不着,上课睡最香");<br>// }<br> }<br> <br> Student.prototype.sleep = function(){<br> console.log("晚上睡不着,上课睡最香");<br> }<br> <br> let s1 = new Student(1,"大黄",18);<br> let s2 = new Student(2,"小黄",19);<br> <br> s1.sleep();<br> s2.sleep();<br>
区分原型的属性和实例的属性:<br> 实例:用new调用构造函数创建出来的对象叫做实例。<br> 原型属性:写在prototype后面的叫做原型属性 。<br> 实例属性:创建出来的对象,重新给原型属性赋值后,就成为了实例属性。<br>注意原型图:<br> 函数(类)的属性:prototype<br> 实例的属性:_proto_<br><br>
6.apply()和call()
每个函数dui都有两个非继承而来的方法apply()和call(),这两个方法的用途都是用来调用函数(在特定的作用域中),实际上等于设置函数体内的this对象的值。调用函数,实际上就是调用该函数对象的call内部方法。
两者的区别:<br> apply()方法有两个参数,分别是运行函数的作用域,另一个是参数数组(可以是Array也可以是arguments)。<br> call()方法的第一个参数和apply()的第一个参数一样,其它参数就是调用函数的参数(相当于把,apply第二个参数的每个元素单列出来)<br>
//引申出接口的概念<br> //参数1为实力对象,后续参数为eat的参数<br> eat.call(m,"香蕉","牛奶");<br> eat.call(s,"老鼠","人");<br> eat.apply(m,["香蕉","牛奶"]);<br> eat.apply(s,["老鼠","人"]);<br>
apply()和call() 真正的用途:<br><br> 把函数和对象之间进行解耦<br> 即对象和函数之间可以没有关联<br>
收藏
收藏
0 条评论
下一页