js基础学习

js视频:
53:如果函数中return语句后边不跟任何值就相当于返回一个undefined,
如果函数中不写return,则也会返回undefined.
56:立即执行函数:函数定义完立即被执行。
function(){
alert("我是匿名函数");
}//这是一个函数对象,只不过没有名字,要想让她立即执行,则只需()括起来这个匿名函数,使其成为一个整体,然后在()就相当于调用

(function(){
alert("我是匿名函数");
})()//这就相当于函数对象()的形式来调用,

为什么匿名函数要加括号?
是因为如果不加括号,就会把{alert("我是匿名函数");}当作一个代码块处理,而前边的function()就多余出来,会报错。加上括号就是作为一个整体,成为函数对象,跟下边的a一样
var a=function(){
alert("我是匿名函数");
}//a就是函数对象,要想执行,则只需a()
还可以给其传参数:
(function(a,b){
console.log(a);
console.log(b);
})(123,456)//给a传123,给b传456

58:变量的声明提前:
使用var关键字声明的变量,会在所有代码执行之前被声明(但并未被赋值),下面两种等效:
console.log("a="+a);//结果:a=undefined
var a=123
即:
var a;
console.log("a="+a);//结果:a=undefined
a=123;
以上等效,如果变成:
console.log("a="+a);//结果:会报错。因为a还没有声明。
a=123;
58:函数的声明提前:
a.使用函数声明形式创建的函数function 函数名(){}
它会在所有的代码执行之前就被创建,所以可以在此函数定义出现之前就调用函数。
fun();//调用在前,定义在后,不出错,会打印出haha
function fun(){
console.log("haha");
}
b.使用函数表达式创建的函数,不会被提前,所以不能在函数定义前调用。
fun2();//报错
var fun2=function(){
console.log('haha');
}
58:js中一共有两种作用域:
a.全局作用域:
-直接编写在script标签中的js代码,都在全局作用域
-全局作用域在浏览器页面打开时创建,在页面关闭时销毁
-在全局作用域中有一个全局对象window,它代表的是一个浏览器窗口,由浏览器创建,可以直接使用
-在全局作用域中,
创建的变量都会作为window对象的属性保存
创建的函数都会作为window对象的方法保存
-全局作用域中的变量都是全局变量,在页面的任意部分都可以访问的到。
b.函数作用域:
-调用函数时创建函数作用域,函数执行完后,函数作用域销毁。
-每调用一次函数就创建一个新的函数作用域,他们之间是独立的
-函数作用域可以访问全局的,反之则不行。
var c=33;
function fun(){
console.log("c = "+c);
var c=10;
}
fun();//会输出c = undefined,因为函数作用域中有,故变量声明提前。不会采用全局的。
59:a.在函数中不使用var声明的变量都是全局变量。
var c=33;
function fun(){
c=10;
d=100;
}
fun();
console.log("c = "+c);//c也成为全局,c = 10
console.log("d = "+d);//d是全局,d =100
b.定义形参就相当于在函数作用域中声明了变量。
var e=23;
function fun(e){
console.log(e);
}
fun();//会显示undefined,因为这时候相当于在函数中有var e;
60:举两个例子:
1) var a=123;
function fun(){
alert(a);
a=456;
}
fun();//调用函数,得到123
alert(a)//456
2) var a=123;
function fun(a){//与1相比,多了一个形参,则相当于在函数中声明了变量var a
alert(a);
a=456;
}
fun();//调用函数,得到undefined,因为a已经声明了
alert(a)//123.因为456改变的是函数作用域声明的a
3)alert(c);//会报错,因为c没有声明,
c=true;
61:解析器即浏览器在调用函数时,每次都会向函数内部传递进一个隐含的参数,这个参数就是this
根据函数调用方式的不同,this指向不同的对象
a.以函数形式调用时,this永远都是window
var name="全局";
function fun(){
console.log(this.name);
}
fun();//以函数形式调用,所以this是window,而window.name是全局,所以:全局

b.以方法形式调用时,this是调用方法的那个对象
function fun(){
console.log(this.name);
}
var obj={
name:"haha",
sayHello:fun
}
console.log(obj.sayHello==fun)//true
obj.sayHello();//haha,
c.当以构造函数形式调用时,this就是新创建的那个对象
62: d.要注意以下:
var name="全局";
function fun(){
console.log(name);//要注意这里不再是this.name
}
fun();//全局
var obj={
name:"haha",
sayHello:fun
}
obj.sayHello();//这里是重点。结果:全局,因为name在函数中未找到,会去全局中找,所以是全局。这时候不是this.name
63:使用工厂方式创建大量对象核心思想:
即将要创建对象的共性部分提取出来,然后通过传入不同参数来构建他们的不同部分。
function createPeople(name ,age){
var obj=new Object();
obj.name=name;
obj.age=age;
obj.sayName=function(){
alert(this.name);
}
return obj;
}
var obj1=createPeople("孙悟空",14);
var obj2=createPeople("猪八戒",18);
但是使用工厂方法创建的对象,使用的构造函数都是Object,即new Object(),导致无法区分多种不同类型的对象
64: 为了解决上述问题,可以创建一个构造函数,专门用来创建一种类型的对象,比如Person类型,Dog类型
--构造函数就是一个普通的函数,创建方式和普通函数没有区别
不同的是构造函数习惯首字母大写,类似java中的类名
--构造函数和普通函数的区别就是调用方式
普通函数是直接调用fun();
构造函数需要使用new关键字来调用: new Fun();就相当于java一样构造对象,使用类名
a.构造函数
function Person(){}
var per=new Person();
console.log(per);//object Object
b.普通函数
function Person(){}
var per=Person();
console.log(per);//undefined,因为没有返回值
构造函数的执行流程:
1)立刻创建一个新的对象,//类似var obj=new Object();这样
2)将新建的对象设置为函数中的this,在构造函数中可以使用this来引用新建对象//var per=new Person(),per就是新建对象
3)执行函数中的代码
4)将新建的对象作为返回值返回
function Person(){
this.name="孙悟空" //这里的this就是per
this.sayName=function(){
alert("hello myName is:"+this.name);
}
}
var per=new Person();
console.log(per.name);//孙悟空
65:目前我们的方法是在构造函数内部创建的,也就是构造函数每执行一次就会创建一个新的sayName方法
执行10000次就会创建10000个新的方法,而10000个方法都是一样的。可以使所有对象共享一个。
解决办法1:将方法定义在全局作用域
function Person(){
this.name="孙悟空" //这里的this就是per
this.sayName=fun;
}
//将函数提取到全局,但是会污染全局命名空间,即大家名字冲突造成覆盖,见后续的原型。
function fun(){
alert("hello myName is:"+this.name);
}
66:原型prototype
a.我们所创建的每一个函数(不管是普通还是构造),解析器都会向函数中添加一个属性prototype
这个属性对应着一个对象,即原型对象
b.如果函数作为普通函数调用prototype没有任何作用
c.当以构造函数的形式调用时,它所创建的对象中都会有一个隐含的属性指向该构造函数的原型对象
可以通过__proto__来访问该属性//var per =new Person(),即per中有该隐含对象
即:console.log(per.__proto__==Person.prototype)//true
d.原型就相当于一个公共区域,所有同一个类的实例都可以访问到这个原型对象//per ,per1,per2都可以
e.可以将对象中共有的内容,统一设置到原型对象中,这样就避免了全局污染
f.当我们访问对象的一个属性或方法时,会先在对象自身中寻找,如有则直接使用,没有就去原型对象中寻找。
举例:
function Person(){
this.name="孙悟空"
}
Person.prototype.sayName=function(){
alert(this.name);
}
var per=new Person();
per.sayName();//孙悟空
g.当不想用原型中的变量或方法时,直接全局覆盖即可,因为他首先会在自身寻找。
h.以后创建构造函数时,可以将这些对象共有的属性和方法统一添加到构造函数的原型对象中,这样不用分别为每一个对象添加,
也不会影响到全局作用域,这样每个对象都有了。

可以详细再看看本集视频。
67: 1) 使用in检查对象中是否含有某个属性时,如果对象中没有但是原型中有,也会返回true,//所以就显得不够精确
2) 可以使用对象的hasOwnProperty()来检查对象自身中是否含有该属性。
function MyClass(){

}
MyClass.prototype.name="孙悟空";
var mc =new MyClass();
console.log("name" in mc);//true
console.log(mc.hasOwnProperty("name"));//false
console.log(mc.hasOwnProperty("hasOwnProperty"));//false,因为本身也没有这个方法,会往上找原型
console.log(mc.__proto__.hasOwnProperty("hasOwnProperty"));//false,发现原型里也没有这个方法
console.log(mc.__proto__.__proto__.hasOwnProperty("hasOwnProperty"));//true,原型里没有后,会去原型的原型里去找
console.log(mc.__proto__.__proto__);//[object Object]
console.log(mc.__proto__.__proto__.__proto__);//null,到头了

即:当我们使用一个对象的属性或者方法时,会在自身中寻找,自身如果有,则直接使用;
若没有则去原型对象中找,如果原型对象中有则使用;
若仍然没有,则会去原型的原型中去寻找,直到找到Object对象;
Object对象的原型没有原型,如果在Object中仍没有找到某个属性或方法,则返回undefined
一般也就使用两级proto,即console.log(mc.__proto__.__proto__);就到头了
68:当我们直接在页面中打印一个对象时,实际输出的是对象的toString()方法的返回值。
如果我们希望在输出对象时不输出[object Object],可以为对象添加一个toString()方法。
var per = new Person("孙悟空",18,"男");
console.log(per);//[object Object]
per.toString=function(){//但是这样只是修改此对象,其他对象依然还是[object Object]
return "haha";
}
console.log(per);//haha
所以可以这样搞,给原型对象添加
Person.prototype.toString=function(){
return "haha";
}
或者:
per.__proto__.toString=function(){
return "haha";
}
这样创建的每个对象都可以使用了。
69:垃圾回收:var obj=new Object();
obj=null;//js会自动进行垃圾回收。只有没有引用此对象,所以对于不使用的对象,可以将引用变为null
70:js对象三种:内件对象,宿主对象,自定义对象
w3school离线手册有内建对象的介绍。
永远向数组的最后一个位置添加元素,不用记索引值:arr[arr.length]=70;
arr[arr.length]=80;
arr[arr.length]=90;//不用记索引,直接在最后添加。
71:

原文地址:https://www.cnblogs.com/yyzyxy/p/7425839.html