一、 包装对象
* 在js内部,当我们去调用字符串、数字、布尔值这些基本数据类型的属性或者方法的时候,js会在内部先把这些基本数据类型转成一个对应的对象类型(包装对象),然后再去调用包装对象身上的这些属性或者方法
*
* 包装对象有
* String
* Number
* Boolear
*
* 注意:
* 1、null与undefined没有对应的包装对象
* 2、基本数据类型只能使用对应的包装对象身上的属性或者方法,不能添加
* 因为使用后,包装对象就消失了,所以只能用,不能添加
var str='kaivon';console.log(str.charAt(0)); //kconsole.log(str.length); //6console.log(str.substring(1)); //aivon//内部执行的过程/*var str=new String('kaivon');console.log(str.length);*/var num=12.456;console.log(num.toFixed(2)); //12.46 把数字转成字符串,并用四舍五入的方法截取小数点后面的位数//内部执行的过程/*var num=new Number(12.456);console.log(num.toFixed(2));*///基本数据类型只能用对应包装对象身上的方法或者属性,不能添加var str1='kaivon1';str1.a=12;console.log(str1.a); //undefined
二、hasOwnProperty
* 作用
* 判断一个属性是不是自己对象身上的(主语是对象,不会找到原型更不会找到Object),(主语是原型,就只在原型身上找)
* 语法
* 对象.hasOwnProperty(属性)
* 参数
* 要检测的属性
* 返回值
* true 自身属性
* false 非自身属性
* 注意
* 1、这个方法是Object身上的方法
* 2、不会顺着原型链往外面去查找属性,只查找自身
function Person(name){this.name=name;}Person.prototype.country='china';var p1=new Person('kaivon');console.log(p1.name); //kaivonconsole.log(p1.country); //chinaconsole.log(p1.hasOwnProperty('name')); //trueconsole.log(p1.hasOwnProperty('country')); //false 因为这个属性在原型身上
三、constructor
* 概念
* 每个对象身上都会有这个属性,默认指向该对象对应的构造函数
* 这个属性不是放在对象身上,放在对应的原型对象身上
* 作用
* 查看对象的构造函数(构造函数的函数名)
* 语法
* 对象.constructor
* 返回值
* 对象的构造函数
* 注意:
* 这个属性是可以被修改的
function Coder(name){this.name=name;}/**Coder.prototype.age=18;Coder.prototype.sex='男';*/ //这种写法没有问题Coder.prototype={constructor:Coder, //这种写成对象的写法,会不经意间把constructor改成别的,所以也就自己把constructor设定为对应的构造函数的名字age:18,sex:'男'};console.log(c1.constructor==Coder); //ture

四、for in
for(var attr in obj){console.log(attr,obj[attr]);}
//如果不想找到原型添加的属性---通过hasOwnProperty判断
//如果只想遍历自己身上的属性for(var attr in arr){if(arr.hasOwnProperty(attr)){console.log(attr,arr[attr]);}}
五、instanceof
* 作用
* 二元运算符,和==,>,<是同一类东西,用来查找对象与构造函数在原型链上有没有关系
* 语法
* 对象 instanceof 构造函数
* 返回值
* true 有关系
* false 没关系
*
* 可以用来做类型判断
function Person(name){this.name=name;}var p1=new Person('kaivon');console.log(p1 instanceof Person); //trueconsole.log(p1 instanceof Array); //falseconsole.log(p1 instanceof Object); //true
六、toString
* 作用
* 把对象类型转成字符串
* 注意
* 系统对象下的这个方法都是它对应原型对象身上的方法,自己写的对象下的这个方法是属于Object原型身上的方法
//用toString做类型判断var num=0;var str='kaivon';var b=true;var n=null;var u=undefined;var arr1=[];var obj1={};var fn=function(){};var d=new Date();var re=new RegExp();console.log(Object.prototype.toString.call(num)); //[object Number]console.log(Object.prototype.toString.call(str)); //[object String]console.log(Object.prototype.toString.call(b)); //[object Boolean]console.log(Object.prototype.toString.call(n)); //[object Null]console.log(Object.prototype.toString.call(u)); //[object Undefined]console.log(Object.prototype.toString.call(arr1)); //[object Array]console.log(Object.prototype.toString.call(obj1)); //[object Object]console.log(Object.prototype.toString.call(fn)); //[object Function]console.log(Object.prototype.toString.call(d)); //[object Date]console.log(Object.prototype.toString.call(re)); //[object RegExp]在对象原型下将对象类型转成字符串,call修正this的指向
七、call
* 作用
* 调用函数并且改变this的指向
* 语法
* 函数名.call(thisArg,arg1,arg2...)
* 参数
* thisArg 函数中this指向的值
* arg1,arg2... 从call里的第二个参数开始,都是真正函数里的参数
* 返回值
* undefined
*
* 注意:thisArg的值为null或者undefined的时候,this是指向window
function fn(){console.log(this);}fn(); //windowfn.call(1); //this指向数字fn.call('kaivon'); //this指向字符串fn.call('true'); //this指向布尔值fn.call([1,2,3]); //this指向数组fn.call({}); //this指向对象fn.call(null); //this指向windowfn.call(undefined); //this指向window
function fn1(name,age){console.log(this,name,age);}fn1.call(1,'Sigo',18); //Number 'Sigo' 18fn1('Sigo',18); //window 'Sigo' 18
apply的作用和call的作用一样只是语法不一样
八、赋值与赋引用
基本数据类型
var str1='kaivon';var str2='kaivon';console.log(str1==str2); //true//基本数据类型的赋值,就是把值复制了一下var n1=2;var n2=n1+5;console.log(n1,n2); //2 7//基本数据类型的比较,比较的是值相等就相等var n3=10;var n4=10;console.log(n3==n4); //true
复杂数据类型
var obj1={a:10,b:20};var obj2={a:10,b:20};console.log(obj1==obj2); //false 数值是相同,但是内存的引用地址不一样//复杂数据类型的比较,比较的不光是值,并且还要比较引用地址,如果两个都相等,那他们就相等var obj3={a:10,b:20};var obj4=obj3;console.log(obj3==obj4); //true//复杂数据类型的赋值,它不光把值复制了一下,并且还复制了一下在内存中的引用地址var arr1=[1,2,3];var arr2=arr1;arr2.push(4); //arr2与arr1的引用地址是相同的,所以无论修改哪个,两个都会变console.log(arr2); //[1, 2, 3, 4]console.log(arr1); //[1, 2, 3, 4]var arr3=[4,5,6];var arr4=arr3;arr4=[7,8,9]; //arr4又赋值了,所以就又开了一块内存,引用地址就不一样了console.log(arr4); //[7, 8, 9]console.log(arr3); //[4, 5, 6]
九、浅拷贝与深拷贝
//拷贝就是将一个对象的值复制到另一个对象那里去,但是应用地址不一样, 所以两个对象之间就不会有关系了。//这是浅拷贝,既考虑不那么周到,如果对象的值也有对象就不适用window.onload=function(){var p1={a:1,b:20};function a(obj){var newObject={};for( attr in obj){newObject[attr]=obj[attr];}return newObject;}var p2=a(p1);p2.a=10;console.log(p2); //a: 10 b:20console.log(p1); //a:1 b:20}
//深拷贝var p3={a:1,b:[20,10,30],c:{d:40}}function b(obj){var newObject={};if(typeof obj !='object'){return obj;}//如果要复制的对象里有个属性的值是数组,那复制的结果就必需还是数组if(obj instanceof Array){//obj.constructor==Array这个判断条件也可以newObject=[];}else{newObject={};}for( attr in obj){newObject[attr]=b(obj[attr])}return newObject;}var p4=b(p3);console.log(p4);
十、继承
* 属性继承
* 通过call的方法调用构造函数继承属性
* 方法继承
* 通过for in的方法继承原型身上的方法
*
* 注意:
* 1、继承其它对象的属性的时候,一定要用call去修正一下this的指向
* 2、继承其它对象的方法的时候,不能直接赋值,要用for in的方法去赋值,不然会出现对象引用的关系(引用地址 )继承属性
function Person(name,age){this.name=name;this.age=age;}//创建一个对象function Coder(name,age,job){/*this.name=name;this.age=age;*///Person(name,age); 直接调用函数(普通函数调用方式)的话,this指向了window,就会有问题 ,Person.call(this,name,age);this.job=job;}
方法继承
function Person(name){this.name=name;}Person.prototype.say=function(){console.log('我叫'+this.name);}var p1=new Person('Sigo');//创建一个对象function Coder(name,job){Person.call(this,name); //属性继承this.job=job;}for(var attr in Person.prototype){//Coder.prototype[attr]=Person.prototype[attr];//如果只想继承构造函数原型身上自己的方法,就需要做以下的判断if(Person.prototype.hasOwnProperty(attr)){Coder.prototype[attr]=Person.prototype[attr]; //将Person原型say的方法继承给Coder了}}Coder.prototype.coding=function(){console.log('我的工作是'+this.job+',我正在加班');}var c1=new Coder('Sigo','前端');c1.say(); //我叫Sigop1.say(); //我叫Sigoc1.coding(); //我的工作是前端,我正在加班