本章节主要从讲解三个知识点,1.对象的理解 2.上下文this 3.面向对象的思想以及应用
js中对象有两种理解方式
1.狭义的理解就是{ }定义的对象,它是一组无序的属性集合
var demo = {
"name":"xiaoming",
"age":15,
"hobby":["sleep","swim","sing"],
}-------->demo就是一个用{ }定义的对象
2.广义的理解就是js中万物皆对象,如dom,数组,function()等
var div = docment.getElementsByTagName("div")[0];
div.age = 15;
div.hobby = ["sleep","sing"];
就像之前在讲解闭包的时候,解决闭包的方法有两个方案 1.IIFE 2.强制添加属性,为什么能强制添加属性?因为它是一个对象,就是上面的div是一个dom对象,我们也可以去对其强制添加属性。
window Date String Number等 如var str = new String("hello"); 也是一个对象
注意:基本类型不是对象
json一定是对象,但对象不一定是json
如下 json中 key一定是字符串,
var obj = {
"-":"-",
"@@@":"@@@",
"2017":"2017",
"呵呵":"呵呵"
}
获取数据时,一定要用[]的方法,获取的值一定要加"" 如 obj["2017"]
若是对象则有两种取值方法 xxx.key/xxx["key"]
不知道大家是否还记得之前在写运动动画框架的时候,在回调方法里我们通过apply/call给方法指向一个this。为什么要指向那个this?接下来我们来一一讲解 先看看下面的demo 的输出
Document
从输出的日志中,我们可以看到this的指向问题
其实this的指向和函数的调用者有关,onclick的调用者是my_div,win_fun的调用者是window,在平时的开发中window会省略。
上面五点关键点,其实我们就可以总结为一句话,谁调用了方法,那么方法里的this就指向调用的对象。
下面来个小例子
function fun(a,b,c,d,e) {//part1
alert(this.callee.length);
}
function f(a,b) {
arguments[0](10,20,30,40,50); //part2
}
f(fun,5,6,7);//part3
首先我们来看看part3 第一个参数传的是一个函数,但是还没有去调用,在part2部分,通过argument这个类数组去获取实参的参数,并且去调用part3传进来的第一个参数的这个函数,到了part1部分,该函数在part2中被调用,这个时候里面的this是谁?这个this是part2的arguments,因为fun方法是在part2那里被调用了,使用方法里面的this指向的是调用对象也就是arguments,所以alert弹出的值是2。arguments.callee表示形参的类数组,所以arguments.callee.length表示的是形参的数量。
乘胜追击,再来一个例子
var num = 4;//(1)
var obj = {
num: 6,//(2)
fn:(function() {
this.num *= 2;//(3) var num ; this.num *=2;
num = num *2; //(4) num = num*2;
var num = 4;//(5)------------->num = 4;
return function() { return function(){
this.num *= 2;//(6) this.num *= 2;
num*=3;//(7) num *=3;
alert(num);//(8) alert(num);
}
})()
};
var fn = obj.fn;//part1
alert(num);//part2
fn(); //part3
obj.fn(); //part4
alert(window.num);//part5
alert(obj.num); //part6
part1
首先我们看到obj对象的fn方法其实是IIFE,创建及调用,所以里面的this都是window,所以(3)处的num=window的num*2=8,那么(4)出的num是那个?别急我们先来看看(5)处的num,由于参数提升fn方法里的代码就变成了右边,所以(4)处的num = underfined*2 = underfined;(5)处num就变成了4;
part2
此时alert(num)输出的是window.num,由于obj的fu方法IIFE的缘故,已将window.num变成了8,所以输出8.
part3
在未执行part3之前 window.num = 8 ; obj.num = 6; obj.fn方法里面局部变量num = 4;
因为fn是IIFE的函数,所以在此调用时,只会走(6 7 8),(6)这里的this还是window-->fn()=window.fn(),所以num是window的,num = 2*8 = 16;(7)由于闭包,这里的num是obj.fn方法里的局部变量 num = 4*3=12;(8)所以弹出12
part4
在未执行part4之前 window.num = 16 ; obj.num = 6 ; obj.fn方法里的局部变量 num = 12;
obj.fn() 只会走(6 7 8) 此时的this就是obj了 (6)obj.num = 6*2 = 12;(7)由于闭包num还是那个局部变量num = 3*12 = 36;(8)弹出的是36
part5
在未执行part5之前 window.num = 16 ; obj.num = 12; obj.fn方法里的局部变量 num = 36;
此时window.num = 16 ,弹出16
part6
此时的obj.num = 12 , 弹出12
function fn() {
this.name = "张晓龙";
this.age = 30;
this.sex = "男";
}
var obj = new fn();
console.log(obj.age);
new的作用调用该方法,并且返回一个对象。
接下来我们再看看fn方法里面的this,在创建对象时调用了fn方法,并且返回了一个fn对象,那么谁去创建?谁去调用?方法里的this不是指定调用者?
此时fn里的this指向是是一个空对象-->{ },然后最终对象创建好了返回的对象就是该对象,不妨我们可以在fn方法中输出this。
所以new方式创建对象的过程中需要经历几个步骤
/* 构造函数*/
function Student(name,sex,age) {
this.name = name;
this.sex = sex;
this.age = age;
this.hobby = ["学习","运动","尊师爱友"];
this.study = function() {
alert("好好学习 天天向上");
}
}
var xiaoli = new Student("小丽","女",23);
var xiaohong = new Student("小红","女",18);
var xiaowei = new Student("小伟","男",24);
console.log(xiaoli);
console.log(xiaohong);
console.log(xiaowei);
同样,我们可以通过对象的方式去调用xiaoli xiaohong xiaowe 三个对象
我们来看看他们的输出日志
可以看到对象本身的内容就是函数。
function CreateImg(name,src) {
this.name = name;
this.dom = document.createElement("img");
this.dom.src = src;
document.body.appendChild(this.dom);
}
var img1 = new CreateImg("jd","1.jpg");
console.log(img1);
我们可以通过构造函数去创建dom对象,去操控dom对象。
function Teacher() {
this.name = "along";
this.age = 30;
//return 10; // return是一个基本类型 null、undefined、number、string、boolean 无视这个return 该return谁就return谁,但是return会阻止函数调用
//return {a:1,b:2}; // 假如return是一个引用类型的话如 {}、[]、正则、函数、DOM元素、Math等,则会覆盖原有,以你返回的为准
}
var p1 = new Teacher();
console.log(p1);
上面代码有两个return 第一个返回的是基本类型,那么在new一个对象的时候,还是返回对象无视这个return,但在return只有的代码不执行。第二个返回的是一个对象,那么该返回的对象会覆盖new返回的对象,输出日志即可看到。