习题2:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>frame</title>
</head>
<body>
<script type = "text/javascript">
a = 100;
function demo(e){
function e(){}
arguments[0] = 2; // 更改实参的值
document.write(e);
if(a){
var b = 123; //不执行里面
function c(){
}
}
var c;
a = 10;
var a;
document.write(b);
f = 123; //直接赋值,被放在GO中
document.write(c);
document.write(a);
}
var a;
demo(1);
document.write(a);
document.write(f);
</script>
</body>
</html>
习题3:
题目在闭包精细版里的1小时52分钟处(就是求字节数)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>frame</title>
</head>
<body>
<script type="text/javascript">
function retByteslen(target) {
var count,
len;
count = len = target.length;
for(var i = 0; i < len; i ++){ //进行了优化 ,不用每次都计算target.length 将这个值保存出来赋给len
if(target.charCodeAt(i) >= 255){ //进行了优化,不用进行多次比较,只进行了一次比较,因为 不管是中文还是英文,都先加一,判断中文个数在进行再次加一
count ++;
}
}
console.log(count);
}
</script>
</body>
</html>
习题4:
逗号运算符:若是逗号前面是表达式,就计算前面的,然后,若是逗号后面是表达式,就计算后面的表达式,都计算完了,将后面表达式的值返回。
var a = (1 - 1, 1 + 1); // a = 2
例1:
var f = (
function f(){
return "1";
},
function g(){
return 2;
}
)();
console.log(typeof f); //结果为number
习题5:
//所有变量未经声明就使用肯定报错,唯一一个 不报错的就是放在typeof中 并且返回undefined
var x = 1;
if(function f(){}){ f当完条件之后对自己产生变化,一个括号将函数圈在里面,无论括号里面是不是将它当作条件,无论内部如何执行,他依然是括号,是括号就要将里面的东西变为表达式,将它变成表达式它就不是函数定义了,f就消失了
x += typeof f; //未经声明的变量只有放在typeof操作符中才不报错,返回undefined(字符串类型)
}
console.log(x); //若是1加上非字符串类型的undefined得到的结果为非数NaN,此题结果为1undefined
56.对象
1.用已学的知识点,描述一下你心目中的对象。
例1:(包含了四个属性两个方法)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>frame</title>
</head>
<body>
<script type="text/javascript">
var mrDeng = {
name : "mrDeng", //属性
age : 40, //属性
sex : "male", //属性
health : 100, //属性
smoke : function (){ //方法
console.log('I am smoking');
this.health --; // 等价于 mrDeng.health --
},
drink : function (){ //方法
console.log('I am drinking');
this.health ++; //等价于 mrDeng.health ++;
}
marry : function(someone){
this.wife = someone;
},
}
delete mrDeng.name //删除
</script>
</body>
</html>
调用时:
mrDeng.smoke() 这是调用函数,使用方法,并且返回undefined ,如果没写return,控制台就返回undefined
mrDeng.smoke 这是函数体引用 不改变什么
2.属性的增、删、改、查
(1)增加:mrDeng.wife = "小刘" //可以写入console.log中,也可以直接写在控制台中,但是不用document.write
(2)查:如上问中,就是查询、
(3)删:delete mrDeng.name //再访问时结果为undefined
3.对象的创建方法
(1)var obj = {} plainObject 对象字面量/对象直接量
(2)构造函数(结构上和函数没有任何分别)
a.系统自带的构造函数 new Object()(执行一次生产一个对象,并且每个对象都是一模一样的,且相互独立的)可以通过var obj = new Object();通过它能产生一个真真切切的对象
b.自定义
例1:
function Person(){
}
var person = new Person(); //有new就能生成对象
例2:
function Car(){ //就是一个函数,所以冒号什么的,逗号什么的都不用写,它就是一个函数! 在外部进行更改时属性也只能通过=号
this.name = "BMW"; //双引号?
this.height = "1400";
this.length = "4900";
this.health = 100;
this.run = function (){ //只能用this,不能用名字进行区分,因为刚生产时都是一样的没有什么区别,
this.health --;
}
}
var car1 = new Car();
var car2 = new Car();
car1.name = "sjska";
car2.name = "fjakwigo";
例3:
function Car(color){ //参数才能使函数发生变化,才能变成自定义环节
this.color = color;
this.name = "BMW";
this.height = "1400";
this.length = "4900";
this.health = 100;
this.run = function (){
this.health --;
}
}
var car1 = new Car('green');
var car2 = new Car('red');
car1.name = "sjska";
car2.name = "fjakwigo";
javascript中对象是非常灵活的 可以通过增删改查,但是java c++只要定义了对象 那么这个对象就是固定的不能改变,
在外部通过增加属性的方式来增加一个方法的话,只能通过=号,不能写冒号: ,在对象内部大括号中写冒号: ,
构造函数就这一个特点:大驼峰式命名规则:TheFirstName
小驼峰式命名规则:theFirstName
57.构造函数内部原理
构造函数必须加new,本来就是一个函数但是加上new就能实现构造函数的原理
1.在函数体最前面隐式的加上this = {}
2.执行 this.xxx = xxx;
3.隐式的返回this
例1:
function Student(name,age,sex){
//第一步在逻辑的最顶端生成隐式的var this = {}
//第二步就是AO { this :{name : 'xiaoliu'}};
/* var this = {
name : ""
age:.....
};*/
this.name = name;
this.age = age;
this.sex = sex;
this.grade = 2016;
//第三步return this;
}
var student = new Student('xiaoliu',1324,'male');
例2:
function Person(name,height) {
//var this = {}
this.name = name;
this.height = height;
this.say = function () {
console.log(this.say);
}
//return this
}
console.log(new Person('xiaoliu',180).name);
例3:
function Person(name,height) {
//var this = {}
this.name = name;
this.height = height;
this.say = function () {
console.log(this.say);
}
//return {}; //结果返回空对象
//return 142; //返回原始值则不影响结果,其他的会影响结果
}
console.log(new Person('xiaoliu',180).name); //有new就不可能返回原始值
例4:模拟构造函数过程,可以执行但是不这么用,因为还有深层次的东西无法模拟
function Person (name , age){
var that = {};
that.name = name;
that.age = age;
return that
}
var person1 = new Person ('xiaoliu' , 20);
var person2 = new Person ('xiaowang' , 30);
58.包装
原始值是坚决不能有自己的属性与方法的,它是独立的值,对象可以有,
数字类型对象: var num = new Number(123);
字符串类型对象: var str = new String('fafa');
布尔类型对象: var bol = new Boolean(true);
null undefined不可以拥有属性,会报错
例1:注释部分就是包装类
var str = 'abcd';
str.length = 2;
//new String('abcd').length = 2; delete
//new String('abcd').length = 4 字符串类型对象本身就有length属性
console.log(str.length); //4
//new String('abcd').length = 2; delete 该截断还是会截断的,不过和真正的str没有任何关系
console.log(str); // abcd
例2:
var num = 4;
num.len = 2;
//new Number(4).len = 2 ;delete
//new Number(4).len 这个Number与上一个Number不是一个 这个里面没有len属性所以返回undefined
console.log(num.len); //undefined
对象包装类下 30分开始往后都是例题
1.
var str = "abc";
str += 1; //str = abc1
var test = typeof(str); //字符串 String
if(test.length == 6){
test.sign = "typeof的返回结果可能为String" //包装的过程 赋完值就销毁
} //新生成 new String(String).sign ,什么也没有
console.log(test.sign); //输出结果undefined
2.
function Person(name,age,sex){
var a = 0; //保存到了AO中
this.name = name;
this.age = age;
this.sex = sex;
function sss(){ //产生了闭包
a ++;
document.write(a);
}
this.say = sss;
}
var oPerson = new Person();
oPerson.say(); //调用函数,方
法,a+1
oPerson.say(); //更改同一个变量a的值,a再加1
var oPerson1 = new Person(); //新生成一个对象,和别的对象彼此独立
oPerson1.say(); //a从0开始++
//结果为1 2 1
备注:alert 弹出框 ,用法:alert('我是小美女');
59.原型
1.原型是function对象的一个属性,它定义了构造函数制造出的对象的公有祖先。通过该构造函数产生的对象,可以继承该原型的属性和方法。原型也是对象。
例1:
Person.prototype.name = "呵呵";
function Person(){
}
var person = new Person(); //person.name = 呵呵,自己本身没有name属性,但是自己祖先有,可以直接拿过来用,这样描述的就是一种继承
var person1 = new Person(); //与person共有一个祖先,Person.prototype有什么属性,它俩就有什么属性
例2:
Person.prototype.name = "呵呵";
function Person(){
this.name = "哈哈哈"; //自己身上有属性的话取自己的,可近的来,没有的话去父亲那里找
}
var person = new Person();
var person1 = new Person();
例3:
Person.prototype.name = "呵呵";
Person.prototype.say = function(){
console.log('啦啦啦');
}
function Person(){
}
var person = new Person(); //这些对象身上没有属性和方法,它用的是它原型上的,是一种借用,是一种继承关系,并不属于真正的自己
var person1 = new Person();
2.利用原型特点和概念,可以提取共有属性
例1:
Car.prototype.height = 1400; //共有属性,避免冗余
Car.prototype.lang = 4900;
Car.prototype.carName = "BMW";
function Car(color,owner){
this.color = color;
this.owner = owner;
}
var car = new Car('red','LFY');
var car1 = new Car('green','LFF');
3.对象属性上增删和原型属性上增删改查
例1:
Person.prototype.lastName = "LFY";
function Person(name){
this.name = name;
}
var person = new Person('xiaoming');
改:在控制台更改person.lastName时,只是更改了自己的属性值。自己的属性值增加了lastName,调用时也是从自己属性中调用,但是原型并没有改变,要更改原型,只有使用Person.prototype.lastName 才能更改原型,其实使用person.lastName时不叫更改属性,这叫往自己里添加属性,但是要是没有的话 会在原型里找
增:改都不可能,更不能增了,后代是不可能修改原型里的值的
删:在控制台打出delete person.abc 结果为true,因为删除一个本来就不存在的东西当然可以,所以显示true,同理所以delete person.lastName结果显示true,但是person.lastName的值还是存在并没有删掉
例2:
Person.prototype.lastName = "LFY";
function Person(name){
this.name = name;
}
var person = new Person('xiaoming');
例3:原型的另一种写法,既然它是对象,那就可以按对象那么写
Car.prototype = {
height :1400,
lang : 4900,
carName : "BMW"
}
function Car(){
}
var car = new Car();
4.对象如何查看原型,隐式属性-__proto__:
例1:
在我们用new生成新对象时,三段式:生成空对象,this,返回
但是在这里就第一步有区别,刚开始这个对象并不是空的,里面上来就有东西,里面的东西就是一个属性,放的就是如下:
var this = {
__proto__ : Person.prototype //当你访问这个对象的属性时,这个对象身上如果没有这个属性的话它就会通过__proto__属性指向的索引去找Person.prototype身上有没有自己想要的属性,相当于一个连接的关系把原型和自己连接到一起了
};
__proto__里面存的是这个对象的原型,每个对象都有一个 __proto__属性指向它的原型。
例2:
Person.prototype.name = "LFG"
function Person(){
}
var obj = { //将对象的原型指向它,当调用person.name时访问的是obj而不是Person.prototype.name
name : 'LYY',
}
var person = new Person();
person.__proto__ = obj; //将指向的原型进行更改
例3:(1)
Person.prototype.name = "abc";
function Person(){
}
var person = new Person()
Person.prototype.name = "sunny"; //person.name = "sunny" 补充:这个里面改变的是属性,是房间里的东西,但是房间没变,结果为sunny
(2)
Person.prototype.name = "abc";
function Person(){
}
Person.prototype.name = "sunny"; //这条语句放在放在new语句之前之后没什么分别,但是下面的两道例题就不一样了,这个改变的是房间里的东西,并没有改变房间,而下面的一道例题,最后改变了房间,所以__proto__会指向new(生成对象)之前的房间
var person = new Person()
例4
Person.prototype.name = "abc";
function Person(){
// var this = {
// __proto__ : Person.prototype //__proto__指向的是原来的的值,Person.prototype再后面已经更改了值
//}
}
var person = new Person()
Person.prototype = { //person.name = "abc",因为这个Person.prototype已经不是上面那个__proto__指向的Person.prototype了,这个是新的
name : "sunny" //补充:这个直接改变的是房间,不是属性,所以不同,而且,在对象生成完才更改的房间,已经不起作用了,因为对象已经生成完了,引用已经确定了
}
例5:
Person.prototype.name = "abc";
function Person(){ //考虑预编译环节,将函数声明提升到最前面,只有在new后才会生成对象,所以在最后的位置上才生成对象,而中间出现的后一个的更改会将前面的值覆盖掉。上一个题不一样,例4在生成对象之后才进行的更改房间,已经晚了,对象已经生成完了,__proto__已经指向之前的房间了。而这个题,在生成对象之前并且__proto__并没有指向任何房间时进行更改,后面的值当然会覆盖掉之前的值
/* var this = {
__proto__ : Person.prototype
}*/
}
Person.prototype = {
name : "sunny"
}
var person = new Person();
5.对象如何查看对象的构造函数
例1:
Car.prototype.name = 123;
function Car(){
}
var car = new Car();
//在控制台打出car.constructor就能找到对象的构造函数,这是Car.prototype自带属性,是隐式的,是浅粉色的,要是主动在Car.prototype中添加属性,就是显式属性,是紫色的
例2:constructor虽然是系统隐式给的,但是可以手动更改
function Person(){
}
Car.prototype = {
constructor : Person, //更改后car.constructor就变为了Person,car找错了父亲
}
function Car(){
}
var car = new Car();
6.总结:就是原型为Car.prototype,它是一个对象,里面有constructor和__proto__属性,用法是car.constructor可以找到对象car的构造函数,car.__prpto__可以找到对象的的原型,它是在构造函数第一步的this中的,car.__proto__指向的是Car.prototype,每个对象都有一个__proto__属性指向自己的原型,Car.prototype中也有这个属性,不过指的是Car.prototype这个对象的原型,还有默认person.__proto__ 指向Person.prototype
问题:
var a = {
name : "1z",
}
var b = a;
var a = {
name : "b", //因为这个不是在原有基础上进行改变,而是重新开始了一个新对象和之前的就没有关系了,要是在原有基础上进行更改,那么一个变,另一个也变,因为是引用值
}
60.原型链:把原型上面再一个原型,再加一个原型,再加一个原型,这样的一个方法,把原型连成链,依照链的顺序,像作用域链一样的访问的一个东西,叫做原型链,原型链的连接点就是__proto__,原型链的访问顺序和作用域链的访问顺序是一样的,差不多,都是可近的来,近的往远的进行排查,近的有,就用近的,近的没有就往远了找
1.Object.prototype是所有对象的最终原形
例1:
Grand.prototype.Lastname = "Deng"; // Grandl.prototype.__proto__ = Object.prototype; Object.prototype是所有对象的最终原形,里面就没有__proto__属性了,因为没有原型了
function Grand (){
}
var grand = new Grand();
Father.prototype = grand;
function Father(){
this.name = "xuming";
}
var father = new Father();
Son.prototype = father;
function Son(){
this.hobbit = "smoke";
}
var son = new Son();
2.原型链属性的增删改查(基本上与原型是一致的)
查;查看属性就是可近的来,近的没有就往远了找,一直找到终端,终端都没有就undefined
删:原型链上的属性通过子孙是不可以删的,通过自己可以删
改:不能说子孙完全不能修改这个父亲的属性
例1:
还是上面那个代码
在控制台写son. fortune.card2 = "hahha",然后父亲构造函数中的fortune就有card1和card2两个属性
因为这种修改是引用值自己的修改,因为他是引用值,引用值自己给自己加属性是可以的,这不算赋值的修改,这算一种调用的修改,这种修改是可以的,但是直接加值,覆盖型的修改是不行的,.card2这种修改只限于引用值的修改,原始值是不行的,原始值你只能覆盖,也不能干别的
例2:
Grand.prototype.Lastname = "Deng";
function Grand (){
}
var grand = new Grand();
Father.prototype = grand;
function Father(){
this.name = "xuming";
this.fortune= {
card : "vise",
}
this.num = 100; //在控制台son.num ++后,先出现的100什么都不是,然后再访问father.num = 100,son.num=101,所以son在将num取出来就行赋值后,就是自己的东西了,所以自己就多了一个num属性并且是101
}
var father = new Father();
Son.prototype = father;
function Son(){
this.hobbit = "smoke";
}
var son = new Son();
3.谁调用的方法内部this就是谁-原型案例
例1:
Person.prototype ={
name : 'a',
sayName : function(){
console.log(this.name); //sayName里面的this指向是,谁调用的这个方法,this就是指向谁,所以调用person.sayName()时结果为b,(person就是Person,一个是对象,一个是构造函数)
} //所以当调用Person.prototype.sayName时,结果为a
}
function Person(){
this.name = "b";
}
var person = new Person();
例2:
Person.prototype ={
height : 100,
}
function Person(){
this.eat = function (){ //使用person.eat方法时只是改变了height属性的值并不会返回什么值,除非自己设定,但是在这里也没什么用,默认返回undefined
this.height ++; //在进行调用person.eat()时返回的是undefined,控制台每次访问返回的都是return值,因为这个eat方法默认是undefined,所以在自己没有设置return时,都返回undefined
} //在调用了person.eat()之后,person.height的值改变+1,但是person.__proto__(Person.prototype)原型的值不改变还是100。
}
var person = new Person();
补充:
1. var obj = {}; //这是对象自变量的创建形式,这个对象有原型,平时能用对象自变量就用对象自变量,最好不要用下面的那种形式。在公司中,数组和对象必须用自变量的写法,最好不要用其它方式
var obj1 = new Object(); //Object() 这是系统给咱们提供的构建函数,上面语句和这个语句得实际上是一样的,在上一条语句上,系统会在内部实现var obj= new Object(),这个对象原型是obj1.__proto__ -- > Object.prototype
2.
Person.prototype = {} /*-- >Object.prototype*/ //person的原型就是对象自变量,最终就是Object.prototype
function person(){
}
4.Object.create(原型);的用法
例1:
Person.prototype.name = "sunny";
function Person(){
}
var person = Object.create(Person.prototype); //Object.create(原型),这条语句就创建了一个以Person.prototype为原型的对象,但是你要是在自己的构造函数(工厂)中添加一些东西的话,那就不一样了,仅仅是原型一样了
5.绝大多数对象的最终都会继承自Object.prototype,但不是所有,因为下面的例题就是特例
例1:
var obj = Object.create(null); //Object.create(),括号里的东西只能是对象或者null,放置null的话,会生成一个空对象,什么也没有,原型也没有,访问obj时,是空的。但是你要是通过obj.__proto__ = {name : "sunny"};加上原型的话,系统让你加,访问obj时会有原型,但是系统不认,访问里面的属性时会显示undefined。
总结:人为加的原型不好使,系统不会读里面的属性。所以说原型这个东西是隐式的内部属性,自己加是不管用的,就是系统给了,咱们可以去改,但是系统没有这个东西,自己加,系统是不认的。
例2: var obj = Object.create(124); //不能放原始值,会报错,但是可以放数组,数组也算object
6.toString()
var num = 123;
num.toString(); //是正确的,因为数字经过包装类Number(123)可以一层一层地往上找,最终的原型一定含有toString属性,所以最终是可以访问的
null.toString()或者undefined.toString() //是报错的,因为它俩不能经过包装类,没有原型,也不是对象,所以没有toString属性,或者说只有它俩和自己构造出的没有原型的东西没有toString,剩下的都有
123.toString() //也是错的,因为系统会把它看成浮点数,因为小数点优先级最高,所以会报错
补充:
(1) var obj = {}; obj.toString(); //对象上面调用的toString是Object.prototype中的toString,毋庸置疑。
(2) var num = 134;
num.toString(); // -->new Number(num).toString();
Number.prototype.toString = function(){ // new Number原型就是Number.prototype,
// 而Number.prototype上面就有一个toString方法
}
Number.prototype.__proto__ = Object.prototype //Number.prototype也有原型,它的原型就是Object.prototype,这就是原型链
//所以Number.prototype上面有toString属性,我就不用Object.prototype上面的tiString属性了,所以num.toString()调用的是自己重写过的,不是Object.prototype上的
这里补充一个重写的概念,重写就是:原型上是有这个方法的,然后我自身又写了一个和原型上的方法,同一个名字但不同功能的方法叫做重写。叫同一个名字的函数的不同重写方式。
重写一般是应用于后端静态语言,像java,C++等都有一些方法重写,一个类里面有很多方法,方法名字都不一样,返回值类型不同,形参列表不同,所以这叫重写,通过你返回值,形参列表的不同,不同传参调用不同的方法,这个叫真正意义上的重写。