原生JS 对象 包装类 原形 原型链
对象
用已学的知识点,描述一下你心目中的对象
var mrDeng = { name : "mrDeng",age : 40,sex : "male",health : 100,//可在控制台更改smoke : function () {console.log('I am smoking');mrDeng.health --;},drink : function () {console.log('I am drink');mrDeng.health ++;}
}
改进 第一人称:this
var mrDeng = { name : "mrDeng", 千万别是等于号age : 40,sex : "male",health : 100,//可在控制台更改smoke : function () {console.log('I am smoking');this.health --;},drink : function () {console.log('I am drink');this.health ++;}
}
1.属性的增、删、改、查
增
drink:function(){console.log('I am drinking');this.health ++;
}
meDeng.wife = "xiaowang";
// console.log(mrDeng.wife = "xiaoliu");
// console.log(mrDeng);
改
console.log(mrDeng);
console.log(mrDeng.sex = "male");
console.log(mrDeng.sex);
删 delete + 属性
当一个变量没有声明就是用报错,对象的属性没有就访问打印undefined,不会报错
var deng = {prepareWife : "xiaowang",name : "laodeng",sex : "male",gf : "xiaoliu",wife : "",divorce : function () {delete this.wife;this.gf = this.PrepareWife;},getMarried : function () {this.wife = this.gf;},changePrepareWife : function (someone){this.PrepareWife = someone;}
}
2.对象的创建方法
1.var obj = {} 叫plainObject 对象字面量/对象直接量
2.构造函数
(1) 系统自带的构造函数 new Object
var obj = new Object();
obj.name = 'abc';
obj.sex = 'female';
obj.say = function(){
}
var obj = {name : ""
}
系统提供的:new Object();Array();Number();Boolean();Date();
(2) 自定义
function Car(){//方便使用-人为的,构造函数特点:大驼峰式命名规则,只要是单词,首字母大写(小驼峰式:第一个外的首字母大写)this.name = "BMW";this.height = "1400";this.lang = "4900";this.weight = 1000;this.health = 100;this.run = function (){this.health --;}
}
var car = new Car();//每个都一样,但是每个都独立
var car1 = new Car();//不是一个人,不互通
console.log(car.run());
console.log(car1.health);
console.log(car.health);
demo
实现自己选配颜色
function Car(color){this.color = color;this.name = "BMW";this.height = "1400";this.lang = "4900";this.weight = 1000;this.health = 100;this.run = function (){this.health --;}
}
var car = new Car('red');
var car1 = new Car('green');
console.log(car/car1);
function Student(name,age,sex) { this.name = name; this.age = age; this.sex = sex; this.grade = 2017;}var student = new Student('zhangsan',18,'male');
注意事项
var obj = new Object(){ obj.name = 'abc'; obj.sex = 'female'; obj.say = function(){ }}
var obj = { name : ""//冒号}
构造函数内部原理
有new 则发生三步
1.在函数体最前面隐式的加上var this = {}
2.执行 this.xxx = xxx;
3.隐式的返回this
function Student(name,age,sex) { //var this = { // name : "" // age : // }; this.name = name; this.age = age; this.sex = sex; this.grade = 2017; // return this;}var student = new Student('zhangsan',18,'male');
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);
模拟构造函数
function Person(name, height){ var that = {}; that.name = name; that.height = height; return that;}var person = new Person('xiaowang', 180);var person1 = new Person('xiaozhang',175);
冷门知识
function Person(name, height){ var this = {}; this.name = name; this.height = height; this.say = function (){ console.log(this.say); } return {};//显示返回空对象,so person很person1都返回空对象 // return this;}var person = new Person('xiaowang', 180);var person1 = new Person('xiaozhang',175);// 但是return一个原始值不允许
Object.create(原型)方法
包装类
1.小知识
原始值不能有属性和方法,只有对象能有,对象包括对象自己,数组,function。
数字不一定是原始值。数字分两种:原始值数字才是原始值。数字,字符串分为两种。
var num = 123;数字
Var num = new number(123);也数字,对象123
console.log(num);console.log(num.abc='a');console.log(num.abc);console.log(num);console.log(num*2);//成了数字,没有了对象属性,同理字符串,布尔
不能有属性的两个原始值:undefined null
String();
Boolean();
Number();
var num = new Number(123);var str = new String('abcd');var bol = new Boolean('true');// undefined与null不可以有属性console.log(num.abc);
2.现象:
var str = “abcd”;str.length = 4;//理论上不可以str.abc = ‘a’;str.abc = undefined;
原始值不可能有属性和方法,因为经历了一个过程——包装类,才能调用
var num = 4;//包装类console.log(num.len = 3);//new Number(4).len = 3; delete// new Number(4).lenconsole.len(num.len);//undefined// num没有length
考题
基于一个理论:数组截断
var arr = [a,b,c,d];console.log(arr.length = 2);console.log(arr);
成哥真题
var str = "abcd";str.length = 2;// new String('abcd').length = 2;deleteconsole.log(str);//abcd
变式
var str = "abcd";str.length = 2;// new String('abcd').length = 2;delete// new String('abcd').lengthconsole.log(str.length);//4
原形
1.定义
原型是function对象的一个属性,它定义了构造函数制造出的对象的公共祖先。通过该构造函数产生的对象,可以继承该原型的属性和方法。原型也是对象。
构造函数产生的对象:
// Person.prototype = {} 是祖先 Person.prototype.name = "hehe";function Person() {}var person = new Person();
应用:
实例一:自己有取自己的
Person.prototype.LastName = "Deng";Person.prototype.say = function(){ console.log('hehe');}function Person() { // this.LastName = 'ji';先看自己后看父亲}var person = new Person();var person1 = new Person();
实例二:
Person.prototype.LastName = "Deng";Person.prototype.say = function(){ console.log('hehe');}function Person(name,age,sex) { this.name = name; this.age = age; this.sex = sex;}var person = new Person('xuming',30,'male');
2.提取共有属性。
function Car(color,owner) { this.owner = owner; this.carName = "BMW";//每次生产都得执行这三句,耦合 this.height = 1400; this.lang = 8900; this.color = color;}var car = new Car('red','prof.ji');
优化
Car.prototype.height = 1400;Car.prototype.lang = 8900;Car.prototype.carName = "BMW";function Car(color,owner) { this.owner = owner; this.color = color;}var car = new Car('red','prof.ji');var car1 = new Car('green','laodeng');
3.原形的增删改查
增
Person.prototype.lastName = "Deng";//原形属性没有改,想改,就要调用Person.prototyoe.lastNamefunction Person(name) { this.name = name;}var person = new Person('xuming');
console.log(person.lastName="james");//这不叫修改,这叫增加console.log(person);console.log(person.lastName);
删
console.log(delete person.name);console.log(person.name);console.log(delete person.lastName);console.log(person.lastName);//删除失效
优化
Car.prototype.height = 1400;Car.prototype.lang = 8900;Car.prototype.carName = "BMW";一步到位Car.prototype = { height : 1400, lang : 4900, carName : "BMW"}
改
2.对象如何查看对象的构造函数 — > constructor构造器
function Person(){}//可以手动更改//构造器constructor:谁生的Car.prototype = { constructor : Person}function Car(){}var car = new Car();console.log(car.constructor);
查
- 对象如何查看原型 — > 隐式属性 proto
function Person(){}var person = new Person();//浅紫色,隐式命名规则console.log(person);
person.prototype.name = 'abc';function Person(){}var person = new Person();// 私人属性:var __praviteconsole.log(person.__proto__)//__proto__里面放的是原形
Person.prototype.name = 'abc';function Person(){ var this = { // __proto__: Person.prototype }}//先看看自己有没有name属性,没有的话沿着proto指向找var perosn = new Person();console.log(perosn.name);
改变proto指向会使得指向更改
Person.prototype.name = 'abc';function Person() { // var this = { // // __proto__: Person.prototype // }}var obj = { name: "sunny"}var person = new Person();//换爹person.__proto__ = obj;
演示1
Person.prototype.name = "sunny";function Person() {}var person = new Person();Person.prototype.name = "cherry";person.name; 分析:自己没有,找proto,是Person.prototype:sunny,最后又改成cherry
演示2
Person.prototype.name = "sunny";function Person() {}Person.prototype.name = "cherry";var person = new Person();console.log(person.name); 同理分析cherry
演示3
Person.prototype.name = "sunny";function Person() {}var person = new Person();Person.prototype = { name : "cherry"}person.name; 答案:sunny。 .的写法是原有的基础上把原有的值改了,这一次是把原形改了,换了个新对象
简化:引用值的互相赋值
var obj = {name : "a"};var obj1 = obj;obj = {name : "b"};obj1:a,obj:b
Person.Prototype.name = "sunny";function Person() { //var this = {__proto__:Person.prototype}}//proto指向不变还是sunnyvar person = new Person();Person.prototype = {//把自己空间换了 name:'cherry'}// 更加简化// Perosn.prototype = {name:"a"};// __proto__ = Person.Prototype;// Person.Prototype = {name:"b"};
演示4
Person.prototype.name = "sunny";function Person() {}Person.prototype = { name: "cherry"}var person = new Person();person.name;答案:cherry预编译:函数 function Person() { } 提升到最上面,然后顺序执行,执行到最后一行,有new了,就有function Person() { var this = __proto__ Person.prototype } ,再访问:下面的把上覆盖
原型链引入
Grand.prototype.LastName = "Deng";function Gand(){}var grand = new Grand();Father.prototype = grand;function Father(){ this.name = "xuming";}var father = new Father();Son.prototype = father;function Son(){ this.hobbit = "somke";}var son = new Son();console.log(son.hobbit);console.log(son.name);//顺着链找console.log(son.toString);Grand.prototype.__proto__=Object.prototype是所有对象的最终原形console.log(Object.prototype);console.log(Object.prototype.__proto__);proto没了,so就是终端
原型链
如何构成原型链?
1.原型链上属性的增删改查
增,删,修改:只有本人有权限,子孙没有
console.log(delete Father.prototype.n);//删不了
特例:引用值调用修改
var grand = new Grand();Father.prototype = grand;function Father() { this.name = 'xuming'; this.fortune = { card1 : 'visa' }}var father = new Father();Son.prototype = father;function Son(){ this.hobbit = "somoke";}var son = new Son();
console.log(son.fortune);son.fortune = 200;console.log(son);console.log(father.fortune);son.fortune.card2 = 'master';cons.log(father);
demo
Grand.prototype.LastName = "Deng";function Grand(){}var grand = new Grand();Father.prototype = grand;function Father(){ this.name = "xuming"; this.forture = { card1 : 'visa' }; this.num = 100;}var father = new Father();Son.prototype = father;function Son(){ this.hobbit = "smoke";}var son = new Son();
console.log(son.num++);100console.log(father);100console.log(son.num);101
演示
Person.prototype = { name : "a", sayName : function(){ console.log(this.name); }}function Person(){}var person = new Person();//答案:a
Person.prototype = { name : "a", sayName : function(){ console.log(this.name); }}function Person(){ this.name = "b";}var person = new Person();
小常识:
a.sayName()
sayName里面的this指向是,谁调用的这个方法,this就指向谁
person.sayName(); person调用的,b
如果Person.prototype.sayName(); a
Person.prototype = { height : 100}function Person(){ this.eat = function(){ this.height ++; }}var person = new Person();
console.log(person.eat);person.eat();console.log(person.eat);//默認return:undefined 查看要写代码
公司规范:数组,对象都用字面量创建
var obj = {};//对象自变量创建形式,有原形//与var obj1 = new Object();相同var obj = {};内部来一个new Object()所以要写对象字面量
绝大多数对象的最终都会继承自Object.prototype
(选择题真题)
例外:由于Object.create
console.log(Object.create());//报错,不写代码console.log(Object.create(null));
Object.create(原型)也能创造对象
// var obj = Object(原形);var obj = {name : "sunny", age : 123};var obj1 = Object.create(obj);// obj1成为了对象,obj1的原形是obj,所以obj1.name就是obj.name
Person.prototype.name = "sunny";function Person() {}var person = Object.create(Person.prototype);
2.关于toString:
只有undefined与null不能调用toString
数字可以,因为经过包装类一层层访问123.toString();
undefined没有包装类,是个原始值,没有原形,不能调用
console.log(undefined.toString);console.log(null.toString);obj.__proto__ = { name: sunny};console.log(obj.name);//自己加原形不管用
各个变量各个属性值调用toString返回结果不一样 变成字符串
var num = 123;console.log(num.toString);//字符串console.log(123.toString);//识别成浮点型
现象
var obj = {};obj.toString();---->[object Object]
原因
var num = 123;// num.toString();-->new Number(num).toString();Number.prototype.toString = function (){}// Number.prototype.__proto__ = Object.prototype
重写笔试题:写一个方法重写形式,写一个和系统同样的名,不同功能
// Object.prototype.toString = function (){// } Person.prototype = { toString : function () { return 'hehhe'; }}function Person () {}var Person = new Person();
本集多看弱项
3.小bug
console.log(0.4*100);//js精度不准console.log(Math.ceil(123.234));//向上取整console.log(Math.floor(123.99999));//下
随机生成0-100随机数
Math.random();//随机数生成函数(0,1)for(var i = 0;i < 10; i++){ var num = Math.random().toFixed(2)*100; console.log(num);//会出现偏差}
解决:先*100后取整
for(var i = 0; i < 10; i++){ var num = Math.floor(Math.random() * 100); console.log(num);}// 总结:可正常那个计算的范围:小数点前16后16
call/apply 必考
1.call
作用,改变this指向。借用别人的函数实现自己的功能
区别,后面传的参数形式不同。
call需要把实参按照形参的个数传出去 apply需要传一个arguments
function test(){}test()===test.call();//后面隐式默认
call里面可以传东西
function Person(name, age){ this.name = name; this.age = age}var person = new Person('deng',100);var obj = {}// Person.call(obj);// 会让Person里所有的this变成obj 即this=obj// 怎么传参:Person.call(obj,'cheng',300);Person.call(obj,'cheng',300);
企业级开发
//开发讲究快准狠,A写的代码能实现B的功能,省时function Person(name, age, sex) { this.name = name; this.age = age; this.sex = sex;}function Student(name, age, sex, tel, grade){ this.name = name; this.age = age; this.sex = sex; this.tel = tel; this.grade = grade;//后面覆盖前面}// call 借用别人的函数实线自己的功能function Person(name, age, sex) { this.name = name; this.age = age; this.sex = sex;}function Student(name, age, sex, tel, grade){ // var this = {name : "", age : "",sex : ""} Person.call(this, name, age, sex); this.tel = tel; this.grade = grade;}var student = new Student('sunny',123,'male',139,2017);
造车举例
function Wheel(wheelSize,style) { this.style = style; this.wheelSize = wheelSize;}function Sit(c,sitColor) { this.c = c; this.sitColor = sitColor;}function Model(height,width,len) { this.height = height; this.width = width; this.len = len;}function Car(wheelSize, style, c, sitColor, height, width, len) { Wheel.call(this, wheelSize,style); Sit.call(this,c,sitColor); Model.call(this, height, width, len);}var car = new Car(100,'花里胡哨的','真皮','red',1800,1900,4900);
2.apply:
apply只能传送一个数组形式的实参
Wheel.apply(this, [wheelSize,style]);
总结:
call:需要把实参按照形参的个数传进去
apply: 需要传一个arguments
作业:电子书js设计模式0-35页上部分
笔试题:用友2017校招前端
继承发展史
1.传统形式
过多的继承了没用的属性
Grand.prototype.lastName = "Ji";function Grand() {}var grand = new Grand();Father.prototype = grand;function Father() { this.name = "hehe";}var father = new Father();Son.prototype = father;function Son() {}var son = new Son();//一系列从头到尾继承,导致不想继续的也继承了
2.借用构造函数
不能继承借用构造函数的原型
每次构造函数都要多走一个函数实际浪费效率
function Person(name,age,sex){ this.name = name; this.age = age; this.sex = sex;}//实际上call apply不是继承function Student(name, age, sex, grade) { Person.call(this,name,age,sex); this.grade = grade;}var student = new Student();
3.共享原型
不能随便改动自己的原型
Father.prototype.lastName = "Deng";function Father(){ // Son想继承father的prototype}function Son(){}
实现方法
原型链
function Son()上面放上var father…
共有原形
Father.prototype.lastName = "Deng";function Father() {}function Son() {}Son.prototype = Father.prototypevar son = new Son();var father = new Father();
抽象成函数
Father.prototype.lastName = "Deng";function Father() {}function Son() {}function inherit(Target, Origin) { Target.prototype = Origin.prototype;}inherit(Son, Father);var son = new Son();//son.LastName = "Deng";
要先继承后使用,Son.lastName指向原来的空间
Father.prototype.lastName = "Deng";function Father() {}function Son() {}function inherit(Target, Origin) { Target.prototype = Origin.prototype;}var son = new Son();inherit(Son, Father); //先继承,后该原形不管用 son.lastName = undefined
不足:
son给自己多加一个属性,方便后续生产出的对象使用,不能个性实现,继承了,但是影响
Father.prototype.lastName = "Deng";function Father(){}function Son(){}function inherit(Target, Origin){ Target.prototype = Origin.prototype;}inherit(Son, Father);Son.prototype.sex = "male";//与father的prototype一致,一个变,都变Father.prototypevar son = new Son();var father = new Father();// 要实现:想继承但不相互影响
4.圣杯模式
通过原型链
function inherit(Target, Origin) { function F(){}; F.prototype = Origin.prototype; Target.prototype = new F();}Father.prototype.lastName = "Deng";function Father(){}function Son() {}inherit(Son,Father);var son = new Son;var father = new Father();console.log(Son.prototype.sex = "male");console.log(son.sex);console.log(father.sex);console.log(Father.prototype);
但是,constructor应该指向构造函数,然而,son.constructor = ƒ Father()????怎么回事?
原形上系统自带的一个属性叫constructor,默认指向他的构造函数
son.__proto__ --->new F().__proto__--->Father.prototype//指向紊乱了
实现继承:必会圣杯模式
function inherit(Target, Origin){ function F(){}; F.prototype = Origin.prototype; Target.prototype = new F(); Target.prototype.constructor = Target; Target.prototype.uber = Origin.prototype;//超级父级:超类}Father.prototype.lastName = "Deng";function Father(){}function Son(){}inherit(Son, Father);var son = new Son();var father = new Father();
颠倒
F.prototype = Origin.prototype;Target.prototype = new F();//不能颠倒,一定要在new之前改原形
类雅虎
闭包的作用:可以实现封装,属性私有化
function Deng(name, wife){ var prepareWife = "xiaozhang"; this.name = name; this.wife = wife; this.divorce = function(){ this.wife = prepareWife; } this.changePrepareWife = function(target){ prepareWife = target; } this.sayPreparewife = function(){ console.log(prepareWife); }}var deng = new Deng('deng','xiaoliu');
console.log(deng.sayPreparewife());console.log(deng.Preparewife)//直接看看不到 即私有化变量
F变成了私有化变量
var inherit = (function(){ var F = function(){};//F放在闭包,私有化变量 return function(Target,Origin){ F.prototype = Origin.prototype; Target.prototype = new F(); Target.prototype.constuctor = Target; Target.prototype.uber = Origin.prototype; }}());
离散数学(重要)——>CS专业(计算机专业),,,,概率论,人工智能
命名空间
就是对象
管理变量,防止污染全局,适用于模块化开发
一个页面,多人协作,合并冲突
1.老办法:命名空间
var org = { department1 : { jicheng : { name : "abc"; age : 123; }, xuming : { } }, department2 : { zhangsan : { }, lisi : { } }}var jicheng = org.department1.jicheng;jicheng.name;
2.新方法:闭包私有化变量
webpack
闭包(实现变量私有化)+立即执行函数
var name = "bac";var init = (function(){ var name = "abc"; function callName(){ console.log(name); } return function(){ callName(); }}())init();
协作也不冲突
var name = "bac";var init = (function(){ var name = "abc"; function callName(){ console.log(name); } return function(){ callName(); }}())var initDeng = (function(){ var name = 123; function callName(){ console.log(name); } return function(){ callName(); }}())
如何实现链式调用模式(模仿jquery)
obj.eat().smoke().drink().eat().sleep();
$('div').css('background-color','red').width(100).height(100).html(123).css('position','absolute').css('left','100px').css('top','100px');
模拟jQuery实现连续调用方法
var deng = { smoke : function () { console.log('Smoking...xuan cool!!!'); }, drink : function () { console.log('Drinking...good'); }, perm : function(){ console.log('perming...cool'); }}deng.smoke();deng.drink();deng.perm();//怎么实现JQ一样连续调用
为什么不能连续调用
console.log('Smoking...xuan cool!!!');// return undefined;
方法:
var deng = { smoke : function () { console.log('Smoking...xuan cool!!!'); return this; }, drink : function () { console.log('Drinking...good'); return this; }, perm : function(){ console.log('perming...cool'); return this; }}deng.smoke().drink().perm().smoke().drink();
查看属性
想实现num为几,就叫哪个媳妇
var deng = { wife1 : {name : "xiaoliu"}, wife2 : {name : "xiaozhang"}, wife3 : {name : "xiaowang"}, wife4 : {name : "xiaoli"}, sayWife : function(num) { switch(num) { case 1: return this.wife1; } }}
把上述代码简化:变量拼接属性名
var obj = { name : "abc"}
**obj.name---->obj[‘name’];**内部会转换成方括号,so这样写也对
方括号可以字符串拼接
功能实现
var deng = { wife1 : {name : "xiaoliu"}, wife2 : {name : "xiaozhang"}, wife3 : {name : "xiaowang"}, wife4 : {name : "xiaoli"}, sayWife : function(num) { switch(num) { case 1: return this['wife' + num];//字符串加啥都是字符串 } }}console.log(deng.sayWife(1));
对象的枚举
for in 循环
数据组的遍历:想知道十个人的信息,挨个知道
var arr = [1,3,3,4,5,6,7,8,9];//遍历 枚举 enumerationfor(var i = 0; i < arr.length; i++){ console.log(arr[i]);//遍历}
如果想查找(遍历)对象的呢(不知道啥类型,编辑器角度)
var obj = { name : "123", age : 123, sex : "male", height : 180, weight : 75 //prop:123}for(var prop in obj){ console.log(obj.prop);//不好使---obj.prop--->obj['prop']当成属性了}
正解:
var obj = { name : '13', age : 123, sex : "male", height : 180, weight : 178, __proto__ : { lastName : "deng"//也会把原形东西拿出来,不想把原形拿出来————hasOwnProperty }}for(var prop in obj) { console.log(obj[prop]); //console.log(obj['prop']);//跟obj.prop一样,这样也不对}
实现obj1里面属性+1返回
错误示范
var obj1 = { a : 123, b : 234, c : 456}var key;for(key in obj1) {//这样写也行 obj1.key ++;}
1.hasOwnProperty(重点)
过滤性方法
判断这个属性是否是自己的(不是原形链的)
true
false
不想把原形拿出来demo
var obj = { name : '13', age : 123, sex : "male", height : 180, weight : 178, __proto__ : { lastName : "deng" }}for(var prop in obj) { if(obj.hasOwnProperty(prop)){ console.log(obj[prop]); }}
自己设的一定能打印,系统设的一定不能
var obj = { name : '13', age : 123, sex : "male", height : 180, weight : 178, __proto__ : { lastName : "deng", __proto__ : Object.prototype//一旦延展的原型链的最顶端,不会打印最顶端 }}
2.in
和hasOwnProperty类似
var obj = { name : '13', age : 123, sex : "male", height : 180, weight : 178, __proto__ : { lastName : "deng" }}//console.log(height in obj)//height叫变量console.log('height' in obj)//height这个属性名存不存在于objconcole.log('lastName' in obj)
和hasOwnProperty的区别:
In判断能不能访问到这个属性或者原形(只能判断对象上能不能访问到这个属性,也可以在父级找)
hasOwnProperty判断属性属不属于这个对象
开发从来不用
3.instanceof(重点)
function Person(){}var person = new Person();var obj = {};// A对象是不是B构造函数构造出来的console.log(person instanceof Person);// ---->ture
看A对象的的原型链上有么有B的原形(重点)
console.log(person instanceof Object);---->tureconsole.log([] instanceof Array);---->tureconsole.log([] instanceof Object);---->tureconsole.log(person instanceof Array);---->falseconsole.log(obj instanceof Person);---->false //两个没关系
解决的问题
判断变量是数组还是对象(机器识别)
typeof([])"object"typeof({})"object"//需求:var arr = [] || {};
第一种方法:
var obj = {};//var obj = [];obj.constructor//直接区分出来了
第二种方法:
[] instanceof Array //truevar obj = {};obj instanceof Array //false
第三种方法:toString
Object.prototype.toString.call([]);//Object.prototype.toString = function (){//谁调用,this就是谁//识别this://返回相应结果//}// obj.toString();// call.toString();Object.prototype.toString.call([]);//数组会替换thisObject.prototype.toString.call(123);Object.prototype.toString.call({});//区别数组和对象
控制台验证
Object.prototype.toString.call([]);"[object Array]"Object.prototype.toString.call({})"[object Object]"Object.prototype.toString.call(123);"[object Number]"
this
1.函数预编译过程 this —> window
function test(c) { //var this = Object.create(test.prototype); //相当于 // { // __proto__ : test.prototype // } var a = 123; function b(){}}//AO{// arguments : [1],//自带的// this : window,//自带的// c : 1,// a : undefined,// b : function() {}//}test(1);new test();//new导致this指向发生了改变,不在是window了
验证
function test(){ console.log(this);}test();
2.全局作用域里 this —> window
console.log(window);
3.call/apply 可以改变函数运行时this指向
4.obj.f(); f()里面的this指向obj)
谁调用的方法,this就指向谁,如果没人调用这个方法,空执行,this是window
var obj = { a : function () { console.log(this.name)//谁调用,就用谁的name }, name : 'abc'}obj.a();//obj调用
5.this题
条件判断为假的情况有: 0 、false 、’’ 、 null 、undefined 、未定义对象。
函数声明写在运算符中,其为 true,但 放在运算符中的函数声明在执行阶段时找不到的 。
另外,对未声明的变量执行 typeof 不会报错,会返回 undefined
this一马平川题
var name = "222";var a = { name : "111", say : function(){ console.log(this.name); }}var fun = a.say;//a.say代表function的函数引用,fun在全局上执行,相当于函数在全局执行fun()//222全局执行也没人调用a.say()//111var b = { name : "333", say : function(fun){ //this---->b fun();//不是this.fun(),谁也没调用,预编译,上面得this--->window,222 }}b.say(a.say);//a.say---是上面的函数体, 222b.say = a.say;//a.say上面的函数拷贝到b.say(代替b.say)b.say();//333
arguments
arguments.callee
func.caller
arguments
function test(){ console.log(arguments.callee); }test();//返回自己的函数体
应用:
var num = (function(n){ if(n == 1) { return 1; } return n*阶乘(n-1);}(100))
立即执行函数的阶乘:只能用callee做
var num = (function(n){ if(n == 1) { return 1; } return n*arguments.callee(n-1);}(100))
在那个函数里面,就打印哪个
function test(){ console.log(arguments.callee); function demo(){ console.log(arguments.callee); } demo();}
caller: demo在哪个环境调用的
function test () { demo();}function demo() { console.log(demo.caller);}test();
克隆
1.浅层克隆
var obj = { name : 'abc', age : 123, sex : 'female'}var obj1 = {}function clone(origin,target){ for(var prop in origin){ target[prop] = origin[prop]; }}clone(obj,obj1);//打印obj1显示已经copy过去了
实现容错:
var obj = { name : 'abc', age : 123, sex : 'female'}var obj1 = {}function clone(origin,target){ var target = target || {}; for(var prop in origin){ target[prop] = origin[prop]; } return target;}clone(obj,obj1);
原始值没问题,但是引用值拷贝:
var obj = { name : 'abc', age : 123, sex : 'female', card : ['visa', 'unionpay']}var obj1 = {}function clone(origin,target){ var target = target || {}; for(var prop in origin){ target[prop] = origin[prop]; } return target;}clone(obj,obj1);
2.深层克隆
两个人,克隆,只考虑引用值的数组、对象 核心:区分数组和对象
var obj = { name : 'abc', age : 123, sex : 'female', card : ['visa','unionpay',[1,2]]}var obj1 = { card : [obj.card[0],obj.card[1],[]]}clone(obj, obj1);
var obj = { name : 'abc', age : 123, card : ['visa', 'master'], wife : { name : "bcd", son : { name : "aaa" } }}var obj1 = { name : obj.name, age : 123, card : []//重新开始循环,发现里面都是原始值,card : [obj.card[0],obj.card[1]], wife : { name : "bcd", son : { name : "bcd", son : }}//里面是不是原始值,第一个是,第二个不是, 建立新的对象,进行循环}
遍历对象 for(var prop in obj)
遍历除了可以遍历对象,还可以遍历数组
var arr = ['a','b','c']for(var prop in arr) { arr[prop]}
步骤:
1.判断是不是原始值 typeof()如果是object引用值,不是obj,基本是原始值 null最后讲
2.数组还是对象 三种方法: instanceof toString constructor,建议使用toString,因为
另外两个有小问题,不会遇到
父子域:一个页面里面可能还有个子页面 跨父子域 [] instanceof Array ——>false应该ture
3.建立相应的数组和对象
// 递归function deepClone(origin,target) { var target = target || {};//容错 toStr = Object.prototype.toString, arrStr = "[object Array]";//比对}
代码实现
var obj = { name : 'abc', age : 123, card : ['visa', 'master'], wife : { name : "bcd", son : { name : "aaa" } }}var obj1 = {} function deepClone(origin,target) { var target = target || {};//容错 toStr = Object.prototype.toString, arrStr = "[object Array]"; for(var prop in origin) { if(origin.hasOwnProperty(prop)) {//防止原型链上的 if(typeof(origin[prop]) == 'object') { if(toStr.call(origin[prop]) == arrStr) { target[prop] = []; }else{ target[prop] = {}; } deepClone(origin[prop],target[prop]);//递归 }else{ target[prop] = origin[prop]; } } } return target;}
优化
function print(){ function deepClone(origin, target){ var target = target || {}, toStr = Object.prototype.toString, arrStr = "[object Array]"; for(var prop in origin) { if(origin.hasOwnProperty(prop)) {//null问题 if(origin[prop] !== "null" && typeof(origin[prop]) == 'object') { //绝对不等于,隐式类型转换也不行 if(toStr.call(origin[prop]) == arrStr) { target[prop] == []; }else{ target[prop] = {}; } deepClone(origin[prop],target[prop]); }else{ target[prop] = origin[prop]; } } } return target; }
三目运算符简化代码
function print(){ function deepClone(origin, target){ var target = target || {}, toStr = Object.prototype.toString, arrStr = "[object Array]"; for(var prop in origin) { if(origin.hasOwnProperty(prop)) {//null问题 if(origin[prop] !== "null" && typeof(origin[prop]) == 'object') { //绝对不等于,隐式类型转换也不行 target[prop] = (toStr.call(origin[prop]) == arrStr) ? [] : {}; deepClone(origin[prop],target[prop]); }else{ target[prop] = origin[prop]; } } } return target; }
数组
数组的定义
区分对象的定义方式
(1) 自面量
(2) 构造函数——系统自带
(3) 自定义构造函数
(4) Var Obect.create()
数组
1.数组字面量 var arr = [];
var arr = [1,2,3,,,5];//稀松数组
2.new Array(length/content);
构造方法 var arr = new Array(1,2,3,4,5);
区别
var arr = new Array(10);//返回长度为10的稀松数组var arr1 = [10]; var arr = new Array(10.2);//长度为10.2 报错
数组的读和写
arr[num] //不可以溢出读 结果undefinedarr[num] = xxx;//可以溢出写,撑长数组
JS中,数组就算没有第10位也不报错,因为数组是基于对象的
数组常用的方法
1.改变原数组7个
reverse,sort,push,pop,shift,unshift,
push把数组的最后一位增加
封装push()
var arr = [1,2,3];Array.prototype.push = function (){//不能写形参,因为不知道有几个,所以只能用arguments for(var i = 0; i < arguments.length; i++) { this[this.length] = arguments[i]; } return this.length;}
pop删除:把数组的最后一位剪切出去
arr.pop(); 不能传参
shift:把前面减 arr.shift()
unshift:和push方向相反,在前面加东西
封装unshift
数组不能向前面放东西,所以用新数组,在拼接起来(concat)
reverse:逆反
sort
arr.sort();//升序排序
arr.sort().reverse()//降序
但是这个排序是按ASCII排的,so
var arr = [1,2,10,2,4,5];不能实现想要的排序
实现排序:(冒泡排序)
1.必须两个形参
2.看返回值
(1)返回值为负数,前面的数放在前面
(2)为正数,后面的数在前
(3)为0,不动
var arr = [1,2,10,2,4,5];arr.sort(function (a, b) { if(a > b) { return 1; }else{ return -1; }});
简化代码
arr.sort(function (a, b) { if(a - b > 0) { return a - b; }else{ return a - b; }});
最终
arr.sort(function (a, b) { return a - b;//升序 //return b - a;//降序});
给一个有序数组乱序
Math.random() 返回(0,1)随机数// var arr = [1,2,3,4,5,6,7];// arr.sort(function () {// return Math.random() - 0.5;//实现可正可负// });
对象年龄排序
var cheng = { name : "cheng", age : 18, sex : 'male', face : "handsome"}var deng = { name : "deng", age : 40, sex : undefined, face : "amazing"}var zhang = { name = "zhang", age = 20, sex = "male"}var arr = [cheng, deng, zhang];arr.sort(function (a, b) { // if(a.age > b.age) { // return 1; // }else{ // return -1; // } return a.age - b.age;}
字符串长度排序
var arr = ['ac','bcd','cccc','asfsadshilk','casuicbniasbnciuas'];arr.sort(function (a, b){ return a.length - b.length;})
字节长度排序
function retBytes(str) { var num = str.length; for(var i = 0; i < str.length; i++){ if(str.charCodeAt(i) > 255){ num ++; } } return num;}var arr = ['a邓','ba邓','cc邓cc','老邓',"残邓",'asdoifqwoeiur','asdf'];arr.sort(function (a, b){ return retBytes(a)-retBytes(b);})
splice:切片
// arr.splice(从第几位开始,剪切多少长度,在切口处添加新的数据)arr.splice(1,2);demovar arr = [1,1,2,2,3,3];arr.splice(1,1,0,0,0);var arr = [1,2,3,5];//实现把4填进去arr.splice(3,0,4);//鼠标光标在前面arr.splice(-1,1);//倒数第一位
-1倒数第一位;1倒数 第二位怎么实现的
splice = function(pos) {pos += pos>0?0:this.length; //负数}
2.不改变原数组
concat,join—>split,toString
- concat连接
var arr = [1,2,3,4,5,6];var arr1 = [7,8,9];arr.concat(arr1);
toString
把数组变成字符串
Slice截取
var arr = [1,2,3,4,5,6];// 1.两个参数,slice(从该位开始截取,截取到该位)// var newArr = arr.slice(1,3);// 2.一个参数slice(从第几位开始截取,截取到最后)var newArr = arr.slice(1)var newArr = arr.slice(-4)//-4+6位// 3.没参数:全截取
join
实现字符串连接
var arr = [1,2,3,4];arr.join("-")//必须是字符串形式arr = [1-2-3-4];
split()互逆方法:按照什么拆分
var arr = [1-2-3-4];arr.split("3")//必须是字符串形式
类数组
是对象,可以当数组一样用
类数组
1.可以利用属性名模拟数组的特性
2.可以动态的增长length属性
3.如果强行让类数组调用push方法,则会根据length属性值的位置进行属性的扩充。
function test() { console.log(arguments); arguments.push(7);//报错}test(1,2,3,4,5,6);
现象
//完成类数组的基本形态构建var obj = { "0" : 'a', "1" : 'b', "2" : 'c', "length" : 3, "push" : Array.prototype.push}obj.push('d');//导致length=4并且"3":d
类数组:是对象,可以当数组一样用
var obj = { "0" : 'a', "1" : 'b', "2" : 'c', "length" : 3, "push" : Array.prototype.push, "splice" : Array.prototype.splice//加上他就变成可以当数组用了,像数组了}//类数组组成部分:属性要为索引(数字)属性,必须有length属性,最好加上push
length内部操作手法:
Array.prototype.push = function(target) { this[this.length] = target; this.length ++;}//如果对象调用,则Array.prototype.push = function(target) { obj[obj.length] = target; obj.length ++;}
类数组所有元素遍历出来
var obj = { "0" : "a", "1" : "b", "2" : "c", name : "abc", age : 123, length : 3, push : Array.prototype.push, splice : Array.prototype.splice}for(var prop in obj){ console.log(obj[prop])}
封装type
typeof([])-- array
typeof({})-- object
typeof(function)-- function
typeof(new Number())-- new Object
typeof(123)-- number
分两类:1、原始值 引用值 2、区分引用值
function type(target) { var template = { "[object Array]" : "array", "[object Object]" : "object", "[object Number]" : "number - object", "[object Boolean]" : 'boolean - object', "[object String]" : 'string - object' } if(target === null){ return "null"; } // if(typeof(target) == 'function') { // return 'function'; // }else if(typeof(target) == "object") = { if(typeof(target) == "object"){ // 数组; // 对象; // 包装类Object.prototype.toString var str = Object.prototype.toString.call(target); return template[str]; }else{//原始值 return typeof(target); }
数组去重,在原型链上编程 hash哈西
var arr = [1,1,1,1,2,2,2,2,2,1,1,1,0,0];Array.prototype.unique = function() { var temp = {}, arr = [], len = this.length;//也是优化,不用每次都this了 for(var i = 0; i < len; i++){ if(!temp[this[i]]) {//如果有0,!0==true,所以还是"abc"吧 temp[this[i]] = "abc"; arr.push(this[i]); } } return arr;}
三目运算符
形式:判断语句? 若为真,执行,并返回结果:若为假,执行,并返回结果
三目运算符其实就是简化版的if(){…}else{}语句
条件判断?是 :否 并且会返回值
var num = 1 > 0 ? 2 + 2 : 1 + 1;var num = 1 > 0 ? ("10" > "9" ? 1 : 0) : 2;
try…catch
try{}catch(e) {}一行代码报错影响后面代码执行
finally{}
//try...catchtry{ console.log('a'); console.log(b); console.log('c');}catch(e) {}console.log('d');//执行到b就不执行了,在try里面发生的错误,不会执行错误后的try里面的代码,打印ad
关于catch
try{ console.log('a'); console.log(b); console.log('c');}catch(e){//error error.message error.name ---> error console.log(e.name + " : " + e.message); }console.log('d');
小问题
try{ console.log('a'); console.log(b); console.log(c);//虽然错误,但是不执行}catch(e){ console.log(e.name + " : " + e.message); }console.log('d');
Error.name的六种值对应的信息:
1.EvalError:eval()的使用与定义不一致
2.RangeError:数值越界
3.ReferenceError:非法或不能识别的引用数值
4.SyntaxError:发生语法解析错误
5.TypeError:操作数类型错误
6.URIError:URI处理函数使用不当
es5严格模式
如今:基于es3.0+es5.0的新增方法 使用的,如果产生冲突,则遵循es3.0的
要讲的是怎么让他遵循es5.0解决,即es5.0的严格模式,则产生冲突的部分用es5.0,否则es3.0
“use strict”
不再兼容es3的一些不规则语法。使用全新的es5规范。
demo1:es5不允许使用arguments.callee
// es5.0严格模式的启动"use strict"//放在逻辑的最顶端function test() { console.log(arguments.callee);}test();
demo2
function demo() { console.log(arguments.callee);}demo();//es3.0function test() { "use strict"//内部es5.0 console.log(arguments.callee);}test();
两种用法:
全局严格模式
局部函数内严格模式(推荐)
就是一行字符串,不会对不兼容严格模式的浏览器产生影响
为什么用字符串"use strict":可能在老浏览器执行,浏览器版本问题——向后兼容
es5不允许用with(){} with可以改变作用域链,with(obj) obj作为最顶端的AO
var obj = { name : "obj"}var name = 'window';function test() { var name = 'scope'; with(obj) {//如果with里面添加了对象,with(obj),会把对象当做with要执行的代码体的作用域链的最顶端 console.log(name); }}test();
演示
var obj = { name:"obj", age:234}var name = "window";function test(){ var age = 123; var name = "scope"; with(obj){ console.log(name);//obj console.log(age);//234 }}test();
with作用:简化代码
var org = { dp1 : { jc : { name : 'abc', age : 123 }, deng : { name : "xiaodneg", age : 234 } }, dp2 : { }}with(org.dp1.jc) {//直接访问org.dp1.jc里面的 console.log(name);}
应用:document也是对象
document{ write : function () {}}with(document) { write('a');}
不支持with,arguments.callee,func.caller,变量赋值前必须声明,局部this必须被赋值,(Person.call(null/undefined) 赋值什么就是什么),拒绝重复属性和参数
"use strict"function test(){ console.log(this);//undefined}test();
new了
"use strict"function Test(){ console.log(this);//控制台显示constructor的名}new Test();
预编译在es5严格模式下this不在指向window,没有指向(空),this必须被赋值,赋值什么就是什么
"use strict"function Test(){ console.log(this);}Test.call({});
赋值123
"use strict"function Test(){ console.log(this);}Test.call(123);
123是原始值:ES3就会变成包装类
function Test(){ console.log(this);}Test.call(123);
严格模式,在全局,this指向window
"use strict"console.log(this);
es5拒绝重复属性和参数。。es3里面重复属性和参数是不报错的
function test (name , name){ console.log(name);}//test(1,2);//test(2);
参数报错
"use strict"function test (name , name){ console.log(name);}test(1,2);
属性不报错
"use strict"var obj={ name:'112', name:'111'}test(1,2);
关于eval:
es3不能用eval();——能改变作用域
eval能执行字符串
"use strict";var a = 123;eval('console.log(a)');//字符串在eval里面执行
面试题:为什么不用with();
with可以改变作用域链,改变作用域链,都会降低效率
青春在线内部文档https://www.yuque.com/docs/share/7773dc1a-cd7d-4bf2-9b5a-170194ad9a56
MDN网站
原生JS 对象 包装类 原形 原型链相关推荐
- JS 面向对象编程、原型链、原型继承(个人学习总结)
一.面向对象 1. 面向对象 是所有语言 都有的一种编程思想,组织代码的一种形式 基于对象的语言:JS语言 面向对象的语言:c++ java c# 2. 面向对象 3大特征 封装:将重用代码封装到函数 ...
- javaScript核心学习 (二)函数和对象,继承原型链
javaScript的函数和对象,继承原型链 一.函数 1.初始函数 2.创建函数 2.1 参数设置 2.2 函数声明 来创建函数 2.3 函数表达式创建函数 3.变量作用域 4.匿名函数 5.回调函 ...
- vue js 对象下的原型_如何使用Vue.js和Pusher创建实时原型反馈应用程序
vue js 对象下的原型 by Neo Ighodaro 由新Ighodaro 如何使用Vue.js和Pusher创建实时原型反馈应用程序 (How to create a realtime pro ...
- [js高手之路]原型对象(prototype)与原型链相关属性与方法详解
一,instanceof: instanceof检测左侧的__proto__原型链上,是否存在右侧的prototype原型. 我在之前的两篇文章 [js高手之路]构造函数的基本特性与优缺点 [js高手 ...
- js 中对象--对象结构(原型链基础解析)
对于本篇对于如何自定义对象.和对象相关的属性操作不了解的话,可以查我对这两篇博客.了解这两篇可以更容易理解本篇文章 用构造函数创建了一个对象 obj对象的本身创建了两个属性 x=1 ,y=2 对 ...
- js的继承和原型链(更新中)
话不多说,直接上MDN链接 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Inheritance_and_the_prototype_ ...
- 深入理解 js 之继承与原型链
原型链与继承 当谈到继承时,JavaScript 只有一种结构:对象.每个实例对象(object )都有一个私有属性(称之为proto)指向它的原型对象(prototype).该原型对象也有一个自己的 ...
- javascript数据类型,对象,继承及原型链
楔子 说起来我不是个很好学的人,每每遇到学不懂的东西,就抓耳挠腮,左顾右盼,恨不得有个神仙立马出现抓起书上的东西一把塞进我脑子里,然后我就会了.省的又要记又要理解该多好.可我也明白这只不过梦里的事,Y ...
- 【js细节剖析】通过=操作符为对象添加新属性时,结果会受到原型链上的同名属性影响...
在使用JavaScript的过程中,通过"="操作符为对象添加新属性是很常见的操作:obj.newProp = 'value';.但是,这个操作的结果实际上会受到原型链上的同名属性 ...
最新文章
- 「SAP技术」SAP 如何看序列号被包在哪些HU里?
- 配置windows失败,不能进入系统
- 60. Leetcode 面试题 10.03. 搜索旋转数组 (二分查找-局部有序)
- android中几种定位方式详解
- mysql 账户管理_Mysql账户管理原理与实现方法详解
- mysql乐观锁与事务_Mysql中的读锁,写锁,乐观锁及事务隔离级别和并发问题
- 冲击年薪50万的AI学习指南,限时免费~
- BootstrapTable的使用教程
- cs6导入库闪退 flash_flash cs6源文件怎么修复,导入老跳出意外格式,我是用flash cs6做的。我还有一半没有导出 swf 呢?...
- 小米平板2wifi驱动下载_Xiaomi小米随身WiFi驱动下载
- PMP考试答题技巧-模拟题库
- PPT:动画出现设置
- 数美科技:全栈防御体系怎么样护航游戏ROI增长
- 虚拟机Oracle VM VirtualBox 共享文件夹放的文件打不开,找不到指定路径问题
- oracle现金流量表逻辑,财务学习:现金流量表内在逻辑研究
- 1237 -- 地盘划分
- Linux第7章Gdk及Cairo基础,GNOME 平台的2D图形编程(GTK,GDK,Cairo...) 简介 [转]...
- jQuery特效,网站模板,商城模板,网页特效各种前端源码免费下载
- RTX 3060 快速配置GPU版本tensorflow
- mes系统多少钱,企业要不要上mes系统?
热门文章
- C. Web of Lies cf#736Div.2
- windows dism命令镜像修复方法
- jzoj5245 【NOIP2017模拟8.8A组】Competing Souls
- 2021SC@SDUSC-PALISADE(九)BGV的API分析
- jfif格式的图片怎么改成jpg
- 2020-03-29-近红外数据格式转换
- CCPC2019吉林省赛东北地区赛游记
- linux 预览md文件_微软 Win10 Dev 预览版 20246 发布:来自最新 FE_RELEASE 开发分支 - Windows 10,微软...
- 分布式事务:Alibaba Seata 如何实现分布式事务
- jmeter设置中文