for循环,if循环,初识函数,this关键字
一,关于for循环与if循环的嵌套使用
1.求出指定数组arr
的平均值和大于平均数的值
思路分析:
①遍历数组使用for循环
②求和对sum进行赋值操作
③求出平均值sum/arr.length
④作比较并输出大于平均数的值if
代码实现:
var a =[5,9,6,3,7,4,2,13,19,27];
var sum=0;
var average;
for (var i=0;i<a.length;i++){ //这里for循环遍历数组
sum+=a[i]; //求和并保存总和在sum变量中
}
average=sum/a.length; //求出平均数
console.log("该数组平均数为:"+average)
for (var i=0;i<a.length;i++){ //遍历数组元素
if (a[i]>average){ //输出大于平均值的元素
console.log("大于平均值的数组元素:"+a[i]);
}
}
2.将指定数组a
从大到小排列
思路分析
代码实现
var a = [4,7,3,1,9];
for(var i =0;i<a.length-1;i++)
{
for(var j=0;j<a.length-i-1;j++)
{
if(a[j]<a[j+1])
{
var temp = a[j];
a[j]=a[j+1];
a[j+1]=temp;
}
}
}
console.log(a); // [9,7,4,3,1]
二,初识函数与this关键字及对象
1.函数
1.定义函数的两种方式
①函数式声明(直接写)
function f(){
}
②以函数表达式的方式定义函数(即声明一个变量来储存该函数)
var a = function f( ){
}
提示:函数的声明与变量声明相同,加载初期
区别:调用第一个函数是直接写f();
即可
但是第二个函数的调用就只能写a();
写f();
就调用不到了
③自调用函数(又叫及时执行函数)或者说匿名函数
(function(){
console.log(0)
})()
该函数涉及到的this指向是全局变量
2.数据类型
函数本身也是一种数据类型,首先函数是一种对象,所以它属于引用数据类型,其次既然是对象,那就是也可以使用语法糖的形式
例子
var Person = function(name, age, sex){
//something
};
Person.prototype.body = function(){
//some body
};
Person.prototype.head = function(){
// person head
};
/*use Person Object*/
var tengfei = new Person("tengfei",22,"male");
tengfei.body();
tengfei.head();
3.函数中的实参和形参
形参相当于函数中定义的变量,实参是在运行时的函数调用时传入的参数。
可以类比为形参就是函数声明时的变量,实参是我们调用该函数时传入的具体参数。
小知识:既然上面说到函数也是一种对象,可以使用语法糖的方式去调用下面的属性,这里就可以使用fn.length
去查看函数的形式参数的格式,这里的fn
指的是函数的名字,如果用一个变量比如a去接收函数的话那函数的形式参数个数查看就用变量名a.length
去查看
4.当传入的参数过多或者过少的情况
①过多,不影响,当想用多出来的实参时,写入arguments
语句,然后arguments就会把传入的参数按顺序放入arguments
这个类数组中,然后当需要使用参数时就像调用数组里的元素一样去调用arguments
的元素
②过少,则形式参数的返回值是undefined
5.方法
当函数在对象中,作为对象数组的一个成员,他有一个特殊名字叫做方法,也就是说对象数组里的所有成员,除了当成员是函数时被叫做方法,其他的成员就叫做对象的属性
PS:这里提到一句,方法只能由对象访问,方法的访问者一定是方法的持有者,但是方法的调用者不一定是方法的持有者(后面再补充啦)
2.this关键字(今日份爆炸〣( ºΔº )〣)
1.this是系统提供的一个关键字,它代表一个对象,它代表的是代码执行环境对象(至今不理解╭(°A°`)╮),这么来解释就比较容易理解了,首先一定有个对象去调用函数,this代表的是代码执行环境对象,也就是说谁去调用这个函数,谁就是this代表的对象,即函数的调用对象是this代表的对象
2.例题
function fn(num1,num2) {
console.log(this)//win
console.log(num1)//100
console.log(num2)//obj1
}
var obj1={name:"obj1"}
obj1.say=function(cb) {
var obj2={name:"obj2"}
obj2.say=cb
cb(100,this)//cab(100,obj1)
}
obj1.say(fn)
直接来个难一点的题hhh
思路分析:先按顺序来。
首先声明了一个fn函数,有两个形参,然后下面是打印this代表的对象,num1的值,以及num2的值。
然后声明了一个对象obj1,里面存放了name属性其值为obj1。
再是给obj新添加了了一个方法say
方法say里声明了对象obj2,里面存放了name属性其值为obj2。
然后将obj2新添加一个属性它的值为形参cb接收到的实参的值
然后调用函数cb并传入参数100和this
最后obj1调用它对象数组下的方法say并传入实参fn
首先我们说一下console.log(this)//win
这句,这里先去看什么时候,是谁让这个代码块运行起来,也就是何时fn
函数被调用了,看到这句cb(100,this)//cab(100,obj1)
看似是调用cb函数,但是阅读整个结构知道cb
实际存储的是传入进来的实参的值,这里是把fn函数作为参数传入进来用cb
来存储,所以这一句实际上是在执行fn
函数,这里要补充一点fn
实际上是它上级Window的属性,所以调用fn
函数的调用者是window。
这一句很简单,console.log(num1)//100
就是打印100就不提了
cb(100,this)//cab(100,obj1)
这句同理,什么时候谁让这个代码跑起来的,谁去调用了这个函数,所以就看到最后一行代码,obj1调用它对象数组下面的方法say,这个方法会运行,函数根据位置不同叫法也不同,这里也是函数嘛,所以要让这个函数运行起来,实际上是obj1调用它对象数组下面的方法say,所以这里的this指代的对象时是obj1,作为参数传进fn
的参数num2里,所以console.log(num2)//obj1
打印的是obj1
完毕!(^ワ^)
3.对象
1.关键字new
new 后面跟的是一个函数名
用new来调用函数
1.找一个对象,构造函数prototype属性指向的原型对象,对这个对象进行扩展,扩展出来的对象就是新创建的扩展对象
2.用这个扩展对象去调用new后面的函数(构造函数)
3.表达式的结果:
如果函数的返回值是数据基本数据类型,表达的结果就是这个’构造过’后对象
如果函数的返回值是引用数据类型,表达式的结果就是函数的返回值,创建过的对象就消失了
关于构造函数
构造函数的第一个字母(没有规定必须大写,但是一般为了跟普通的函数区别开,要大写)(而且如果没有写过原型对象,这里针对的自构建的函数,也就是新声明的。)
每一个函数都有一个属性叫prototype==>每一个对象(引用数据)都有一个__proto__
①.如果把它当做普通函数调用,prototype这个属性就没有什么用
2.如果用new关键字来调用函数,这个prototype属性指向的对象就是创建的对象的原型对象
3.把prototype属性指向的对象 放在扩展对象的__proto__属性中(也就是说扩展对象的原型对象的属性__proto__指向的是构造函数属性prototype指向的原型对象)
4.我们称一个对象的__proto__属性指向的对象为这个对象的原型对象
Ps:关于对象的设置与获取
获取
xx.xx 取对象的成员:先取扩展空间的成员 扩展空间没有 就去__proto__属性里取,一层一层依次向上取,直到null都没有,就取到undefined
设置
obj.xx=100
不管原型上有没有这个属性,都会在自己(扩展空间去操作)
2.例子
function fn () {
this.name="karen"
this.say=function () {
console.log("666")
console.log(this)
}
return true
}
var re=new fn()
//var re={} ; re.fn()
//console.log(re)//{name:"karen",say:func}
var fm=re.say
fm()//"666" window
re.say()"666" fn 这一行暂时想不通
4.原型对象(新增)
原型对象
一个对象它为什么有点语法? 为什么有[]取数据的方法? 为什么能够保存数据 为什么能够调方法 ?
是因为系统为我们做出了这些功能? 原型对象上就有这些功能
对象的原型模型对象称为原型对象==>对象自己没有的属性和方法,原型对象上有的它也能用
(结合new关键字一起理解)
PS(1.任何对象都有一个原型对象,这个对象的constructor属性指向了这个对象的构造函数。
2.构造函数的意义:创建对象,类型划分)
4.1原型链(扩展)
1.简而言之,就是不仅仅是创建的对象有原型对象(针对new而言),原型对象也有原型对象,这样一层一层的向上找,这里下面简单的写了其中一部分,
4.作用域(新增)
1.没有函数就不谈作用域,作用域是针对与函数而言的
2.关于变量,window下的声明的变量叫做全局变量所有区域都可以用,函数作用域下声明的变量叫局部变量(仅限本区域有效)
所以也可以这么来说,即函数里面可以访问外面的数据,函数外面不能访问里面的数据
3.函数的调用(注意):函数的代码执行,是在函数声明的作用域下执行 不是在调用的作用域下执行代码,例
var name = 'lili';
var obj = {
name: 'liming',
prop: {
name: 'ivan',
getname: function() {
return this.name;
}
}
}
console.log(obj.prop.getname()); //getname()是在prop下声明的,所以打印的是ivan
var test = obj.prop.getname;
console.log(test()); //test()是在window下声明的,所以打印的是lili
4.关于函数的声明提前问题
①如果是显式声明,则提前到本作用域的第一行
②如果是隐式声明,则提前到全局作用域第一行
③这里也就顺带一提声明的相关问题,做题的总结:
当同一个作用域内有相同的标识符,他们的声明提前顺序如下
1.变量声明
2.形参声明
3.形参赋值(实参给形参上数据)
4.函数声明
(后来做题的时候发现这几句简直太重要,所以提醒自己在做题的时候一定要先把这几个提升,最好是自己把真正的代码写出来,就可以一气呵成)
一些方法
一,字符串
1.charAt
简而言之就是取出指定字符串对应下标的字符
例如
var str = "thnjk";
var re = str.charAt(2);
打印结果就是n
2.concat
拼接字符串,如
var str = "thnjk";
var str1 = "nmd"
var re = str.concat(str1,str,str1)
会将传入的字符串全部拼接起来,可以容纳多个参数
3.indexOf
用于检测子串是否含有指定字符串,有则返回第一次检测到该字符串的起始位置,没有则返回-1
Ps:1.lastIndexOf是从末尾开始检测,同理indexOf,只是说是从后面向前面检测
4.slice
str.slice(s,e)
返回一个新的字符串,包含从 s 到 e (不包括该元素)的 str 中的元素。
(方法并不会修改字符串,而是返回一个子字符串)
如果是数组,则返回一个新的数组,效果同上
(方法并不会修改数组,而是返回一个子数组)
5.split
把一个字符串分割成字符串数组。
将字符串以指定字符(第一个参数)进行分割,(第二个参数)返回指定数目个数的字符串
var str = "thnjk";
var re = str.split("n")
打印结果“th”,“jk”,存放在数组中
(该方法可以将字符串转换成数组)
(Array.from同样也可以)
6.substr&substring
都是返回一个新字符串(指定长度),不同的是传入的参数
substr:第一个是起始下标,第二个是截取字符数
substring:第一个是起始下标,第二个是结尾下标(但不包括该下标)
二,数组
1.concat
连接两个或更多的数组,同字符串concat。
2.join
将数组所有元素以指定分隔符来分割数组中的元素,成为一个字符串(该方法会使数组转化为字符串)
如
var arr = new Array(3)
arr[0] = "George"
arr[1] = "John"
arr[2] = "Thomas"
console.log(arr.join("."))//George.John.Thomas
3.pop
删除数组最后一个元素并返回该值,然后该方法会改变数组的长度
自我实现思路:
(可用for循环能实现的,不过循环长度要比原长度减一)
4.push
向数组的末尾添加一个或更多元素,并返回新的长度。
自我实现思路:
(直接设置原长度+1下标的元素的值就行了)
5.reverse
颠倒数组中元素的顺序。
自我实现思路:
(for循环倒着循环数组)
6.shift
删除并返回数组的第一个元素
自我实现思路:
(先取出最后一个元素然后for循环,重新遍历数组,其长度-1)
7.slice
从某个已有的数组返回选定的元素并成为一个新数组,且该数组并不是修改原数组,而是返回一个子数组
自我实现思路:
(for循环,将起始下标和结束下标设为形参,传入for循环的起始下标和结束下标)
8.sort
对数组的元素进行排序
自我实现思路:
(冒泡排序即可)
9.splice
删除元素,并向数组添加新元素。
var re=arr.splice(1,2,"hello","h5")//从下标为1的位置删除2个元素,然后就在这个位置添加"hello","h5"元素
这里的三个参数:
第一个是规定添加/删除项目的位置,负数则是从倒数开始
第二个是删除项目数量,为0,就不会删除项目
第三个是增加的项目
10.unshift
向数组的开头添加一个或更多元素,并返回新的长度。
自我实现思路:
(将添加的元素放入类数组,转为数组,再用concat将原数组和新数组拼接)
遍历器(常用归纳)
字符串数组方法常用,思路归纳
谈谈你对函数的理解(待解决问题)
一些总结
方法的自我实现有利于思维的拓展
原型与原型链的思维,会构成一个完整的体系,让编写者清楚地知道自己的行为(尤其是对象相关问题)
this,回调函数,闭包,作用域是核心,思维的理顺利于业务的开发和工具设计
关于学习,恒心比起一鼓作气更为重要,当学完原型链之后,整体出现斗志下滑的情况,学习状态松懈,需要及时调整心理,比如突然考试袭击,降低自己浮躁的心态,方法虽然简单,又多,但是却是极其实用的工具,记住利于业务,自我实现方法利于思维与深层次的学习,和构成系统的完整性
(关于方法的学习,最好是先有完整的思路体系,再去对对应的思维树去回忆对应的方法,构建知识体系远比方法的记忆和掌握更重要)