JS对象学习笔记

1.创建对象(两种)

(1)//普通创建
var person = new Object();
// var person = {}//简写
//函数封装--工厂方式
function createPerson(name) {
    //特点:流水线生产
    //原材料
    var person = new Object();
    //加工
    person.name = name;
    person.showName = function () {
        console.log(this.name)
    }
    //出产品
    return person;//返回对象,否则无法创建,为undefine
}
var p1 = createPerson("huahua");//封装方式的创建
p1.showName();打印
(2)//new方法创建即构造函数创建
new关键字作用
/**
1.创建一个新对象
2.将构造函数的作用域赋给新对象(因此,this就指向了这个新对象)
3.指向钩子函数中的代码(为这个新对象添加属性)
4.返回新对象(不用写return)
*/
//改写如下
//构造函数无返回值
function CreatePerson(name){
    this.name = name
    this.showName = function(){
        alert(this.name)
    }
}

2.对象引用

//基本类型
    var num1 = 20;
    var num2 = num1;
    console.log(num1)//20
//引用类型
var arr1 = [1, 2, 3];
var arr2 = arr1;
arr2.push(4);
console.log(arr1)//[1,2,3,4]发生了改变

如果从一个变量向另一个变量复制引用类型的值,同样还是会将存储在变量对象中的值复制一份放到新变量分配的空间中,不同的是,复制的这个副本是一个指针,并不是具体的对象,这个指针指向存储在堆内存中的一个对象,复制操作结束后,两个变量实际上将引用同一个对象

引用类型

3.原型(prototype)的使用
我们创建的每一个函数都有一个prototype(原型)属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法,这个对象就是构造函数CreatePerson的原型对象,当调用CreatePerson创建出一个具体对象p1后,p1内部也有一个指针指向构造函数的原型对象,同样的道理,不管创建出多少对象,这些对象内部都会有个指针执行构造函数的原型对象,使用原型对象的好处是让所有被创建出来的对象共享这个原型对象所包含的属性和方法

function CreatePerson(name){
    this.name = name
}
//  每个函数都有一个prototype对象,即指针(对象的指针指向prototype对象的地址),指向一个对象(原型对象)
//创建出来的对象,也指向原型对象
CreatePerson.prototype.showName = function(){
    alert(this.name)
}
var p1 = new CreatePerson("小强")
var p2 = new CreatePerson("小花")
var p3 = new CreatePerson("小豆")
alert(p1.showName === p2.showName) // true
alert(p2.showName === p3.showName) // true
//    错误演示
    console.log(p1.prototype)//undeifined,原型是在构造函数上的且不可见的!!!

//浏览器产商 Chrome firefox自己实现了prototype可见,但不是标准!!!
有些浏览器没得
 console.log(p1.__proto__);//下划线左右两个,p1.__proto__指向原型对象
原型使用
面向对象选项卡:
//面向过程版的:
var oWrap = document.getElementById("wrap");
var aBtn = oWrap.getElementsByTagName("button")
var aDiv = oWrap.getElementsByTagName("div")
for(var i=0; i<aBtn.length;i++){
    aBtn[i].index = i
    aBtn[i].onmouseover = function () {
        for(var j=0;j<aBtn.length;j++){
            aBtn[j].style.backgroundColor = "white"
            aDiv[j].style.display = "none"
        }
        this.style.backgroundColor = "orangered"
        aDiv[this.index].style.display = "block"
    }
}
//面向对象版的:
/1./把面向过程的代码整理,功能封装
//   2.面向对象完善
//       (1).全局变量就是属性 (2).函数就是方法(3).既不是全局和函数,就封装成初始化方法
//3、调整this指向(出现嵌套代码块,一般this指向不同)
//id用来代表多个选项卡中选中的一个
    function Tab(id) {
        this.oWrap = document.getElementById(id);
        this.aBtn = this.oWrap.getElementsByTagName("button");
        this.aDiv = this.oWrap.getElementsByTagName("div");

    }

//记得加this,指向
Tab.prototype.changeTab = function (obj) {
    for(var j=0;j<this.aBtn.length;j++){
        this.aBtn[j].style.backgroundColor = "white"
        this.aDiv[j].style.display = "none"
    }
    obj.style.backgroundColor = "orangered"
    this.aDiv[obj.index].style.display = "block"
}
//初始化方法
  Tab.prototype.init = function () {
    var That = this
    for(var i=0; i<this.aBtn.length;i++){
        this.aBtn[i].index = i;
        console.log("外层",this)
        this.aBtn[i].onmouseover = function () {
            That.changeTab(this)
            console.log("内层",this)
        }
    }
}
//创建对象,调用
var t1 = new Tab("wrap")
    t1.init()
    var t2 = new Tab("wrap2")
    t2.init()

3.包装对象
字符串为啥可以使用:charAt、indexOf、replace等方法?
-----基本类型都有其对应的一个包装对象,例如:字符串类型对应的包装对象是String,数字的包装对象是Number,布尔类型对应的包装对象是Boolean。根据原型知识,我们可以猜测一下charAt可能是挂载到String构造函数原型上的,所以当str对象去调用charAt方法是可以正常运行的

String.prototype.charAt = function(){}
//给String构造函数自定义一个方法,看普通的字符串是否也能够使用
//创建一个字符串对象
var str1 = new String("hello")
String.prototype.test = function(){
    alert(1)
}
//创建一个基本类型字符串
var str2 = "hello2"
str2.test()  // 弹出1
//如果给str2挂载一个属性,看看效果
str2.num = 10
alert(str2.num) // undefined
//从上面的代码我们知道了 基本类型的str2可以使用方法,实际上使用的是String身上的方法
上面代码实际上执行了以下几个步骤:
1.创建String 类型的对象
2.在对象上调用指定的方法
3.销毁这个对象

4.原型链:
原型链就是实例对象和原型之间的链接。每个函数都有一个prototype属性,这个prototype指向一个对象(利用包装对象.prototype.方法名 = function(){}创建的方法),这个对象叫做原型,通过构造函数创建出来的实例也有一个内部指针指向原型,这样就形成实例对象和原型直接的链接,我们把这个链接称为原型链。

原型链的层级关系

原型链有多层,最外层为Object.prototype

function Fn1(){
this.num = 10;
}
Fn1.prototype.num = 20
Object.prototype.num = 30
var f1 = new Fn1()
console.log(f1.__proto__)
console.log(f1.__proto__.__proto__.num)  //30
-------------------------------------------------------------------------------------------------
//es6 中获取原型,取代__proto__的方法Object.getPrototypeOf(对象实例)
    console.log(Object.getPrototypeOf(f1) === f1.__proto__);//true
//注意:prototype 是在构造函数上,__proto__在对象上

//访问属性的优先级---就近原则,例如:f1,Fn.prototype, Object.prototype上都有num属性,
//那么alert(f1.num)的时候,首先取出的是f1身上的值,如果f1身上没有,那么才访问Fn.prototype,
//以此类推,访问到最外层Object.prototype,如果最终都没有就返回undefined
alert(f1.num)
控制台
关系图

5.面向对象的相关属性和方法

//hasOwnProperty
    function Fn() {
     this.name = 20;
    }
    Fn.prototype.age = 40;
    var f1 = new Fn();
    alert(f1.hasOwnProperty("name"))//true
    alert(f1.hasOwnProperty("age"))//false
    alert(Fn.hasOwnProperty("name"))//true
//constructor
    console.log(f1.constructor)//查看该对象的构造函数
    console.log(Fn.prototype.constructor)

function Fn1(){}
// 指向Fn1的
    Fn1.prototype.name = 10
    Fn1.prototype.age = 20
  // 指向Object的,把一个对象赋值给原型对象,被后面的对象覆盖了
    Fn1.prototype = {
        name: 10,
        age: 20
    }
    // 指向Object
    console.log(Fn1.prototype.constructor)
 // 当一个构造函数新创建出来后,会自动生成下面一句话
 Fn1.prototype.constructor = Fn1
    // 上面的写法不经意间就会把constructor修改掉,因此,我们需要手动去修正
    function Fn1(){}
    Fn1.prototype = {
        constructor: Fn1,
        name: 10,
        age: 20
    }
    // 指向Fn1
    console.log(Fn1.prototype.constructor)
//自己添加的num属性是可以被打印出来的,系统自带的没办法for in循环出来
    Fn1.prototype.num = 10
    for(var attr in Fn1.prototype){
        console.log(attr)   //把constructor name age num属性打印了一遍,没打印值
    }

//instanceof 用来测试一个对象在其原型链中是否存在一个构造函数的 prototype 属性
alert(f1 instanceof Fn1)  //true
alert(f1 instanceof Array) //false

//toString()
//    toStringtoString的作用是把对象转换成字符串,如果是系统自带的对象去调用toString方法, 那么toString方法在原型对象上,如果不是系统自带的对象去调用toString方法,那么toString在Object.prototype上
    var arr =[1,2,3]
//    调用的是Array.prototype原型对象上的toString();
console.log(arr.toString())
    console.log(f1)//toSting()在Object上
//    改写应用与分割字符
    Array.prototype.toString = function () {
        return this.join("-")
    }
    console.log(arr.toString())
//转换16进制颜色
    var num1 = 255;
    console.log(num1.toString(16))//打印ff

//判断类型(推荐第三种)
 //    判断类型方法 consructor instanceof toString
    var arr=[]
    console.log(arr.constructor == Array)//true
    console.log(arr.prototype)//undefined
    console.log(arr.prototype  instanceof Array)//false
    console.log(arr instanceof Array)//true
    console.log(arr.toString() === Array)//false
    // //call(对象)改变内部this指向,应用某一对象的一个方法,用另一个对象替换当前对象
    console.log(Object.prototype.toString.call(arr))//[object Array]
    console.log(Object.prototype.toString.call())//[object Undefined] 因为没有传入
console.log(Object.prototype.toLocaleString.call(arr))//1-2-3

6.call()方法和apply()方法。都是调用一个对象的一个方法,以另一个对象替换当前对象,可以理解为借用一个对象的方法。传参形式不同!

   function Fn1(){

    }
    function Fn2(){

    }
   Fn1.prototype.showAge = function (age,age2) {
       alert(age)
       alert(age2)
   }
var f1 = new Fn1()
    var f2 = new Fn2()
    f1.showAge(20);
    f1.showAge.apply(f2)//undefind
    f1.showAge.call(f2,20,63)//多个分隔开
    f1.showAge.apply(f2,[20,23])//可传多个参数,多个用数组

7.继承

function Parent(name, age) {
        this.name = name;
        this.age = age;
    }
    Parent.prototype.showName = function () {
        alert(this.name)
    };
    function Child(name, age) {
//Parent里面的this指向会出现问题,直接调用Parent()函数,相当于window.Parent(),那么函数里面的this是指向window的,这个时候,我们需要修正Parent里面的this,让Parent里面的this指向Child才行
      //Parent.call(name, age)
  //不能具体指明对象,new的对象,很多且不同
        Parent.call(this, name, age)
    }
//继承方法,把Parent的原型赋值给Child原型
//对象引用,两个对象指向同一个地址,,任何一个对象的修改都会影响另一个对象
//    Child.prototype = Parent.prototype;
    //影响:父中和子中都有同样的方法。解决如下:
function extend(obj1,obj2){
        //循环obj2的内容,赋给obj1。for in专门循环对象
        for (var attr in obj2) {
            obj1[attr] = obj2[attr]
        }
    }
//封装extend方法的原因,直接对象赋值给对象的话,会造成对象的引用,两者相互影响
    Child.prototype.showAge = function () {
        alert(this.age)
    };
    var c1 = new Child("小红", 222)
    c1.showName()
    c1.showAge()
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,686评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,668评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,160评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,736评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,847评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,043评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,129评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,872评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,318评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,645评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,777评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,861评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,589评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,687评论 2 351

推荐阅读更多精彩内容