版本三开始看一边

1基础

JavaScript存在6种数据类型

number,string,undefined,boolean,null,object

强制转换方法

Number()

Boolean()

String()

type of  操作符用来检测数据类型(只能用来精确的检测基本数据类型)

console.log(typeof 1); //number
console.log(typeof false);//boolean
console.log(typeof undefined);//undefined
console.log(typeof 'string');//string

console.log(typeof Function);//function
console.log(typeof null);//object
console.log(typeof {a:1});//object
View Code

 instanceof  操作符用来检测引用类型的类型()

例如  A instanceof B ; 检测A是否是B的实例

var arr=[1,2,3]
var obj={a:1}
var fun=()=>{}
console.log(arr instanceof Array);//true
console.log(obj instanceof Array);//false
console.log(fun instanceof Array);//false

console.log(arr instanceof Function);//false
console.log(obj instanceof Function);//false
console.log(fun instanceof Function);//true

//JS中 所有的引用类型都是Object的实例(万物皆对象)
console.log(arr instanceof Object);//true
console.log(fun instanceof Object);//true
console.log(obj instanceof Object);//true
View Code

 

Number

  1. 分为 number和NaN 
  2. 精度又分为整型和浮点型(进度最高是17位小数点)
  • 整型方法 parseInt()
  • 浮点型方法 parseFloat()
  • toFixed(num)  返回数值的字符串会保留num个小数位表示
  • toString(num) 将数字转换成几进制
  • toLocalString()  返回数值的字符串会保留三位小数
  • valueOf()  返回原来的数值
  •   var num=10.23848;
       
      console.log(num.toLocaleString());//返回对象表示的基本类型的数值保留三位小数(四舍五入)
      console.log(num.toFixed(2));//10.24   保留几位小数会四舍五入
      console.log(num.toString(8));//重写了toString(num)方法 将数字转换成几进制
      console.log(num.valueOf());//返回对象表示的基本类型的数值

     

     3.number能取得的最大值和最小值

  • Number.MAX_VALUE
  • Number.MIN_VALUE

 

isNaN()判断一个类型的值是不是NaN

console.log(isNaN(10))
console.log(isNaN('10'))
console.log(isNaN(true))

console.log('-------------')
console.log(isNaN('10a'))
console.log(isNaN('blue'))
console.log(isNaN(NaN))
console.log(isNaN('a10'))
View Code

 

 

各类型转换成Boolean为false的情况

//数字转换成Boolean为false的情况
console.log(Boolean(0))
console.log(Boolean(NaN))


//字符串转换成Boolean为false的情况
console.log(Boolean(''))

//null转成Boolean为false
console.log(Boolean(null))

//undefined转成Boolean为false
console.log(Boolean(undefined))
View Code

 

Object类型(object的每个实例都具有下列属性和方法)

var obj=new Object();

constructor :保存着用于创建当前的函数的对象;构造函数(constructor)就是Object();

hasOwnProperty(propertyName) :判断给定的属性在当前对象实例中是否存在(不是原型种)[propertypName必须用字符串形式包裹起来]

例如:    obj.hasOwnProperty('name');

isPrototypeOf(object) 用来判断传入的对象是否是传入对象的原型

propertyIsEnumerable(propertyName):用于检测给定的属性是否能够使用for-in语句进行枚举[propertypName必须用字符串形式包裹起来]

toLocaleString():返回对象的字符串表示.该字符串与执行环境的地区对应

toString():返回对象的字符串表示

valueOf():返回对象的字符串,数值或布尔值表示,通常与toString()的返回值相同

 

执行环境和作用域

执行环境:定义了变量或函数有权访问其他数据,决定了它们各自的行为;

全局作用域:当代码在一个环境中执行时,会创建变量对象的一个作用域链(保证对执行环境有权访问的所有变量和函数的有序访问)

局部作用域:局部作用域中的变量可以在局部环境与全局变量互换使用

内部环境可以通过作用域链访问所有的外部环境,但外部环境不能访问内部环境中的任何变量和函数.

 

延长作用域链的方法两种(这么说是因为有些语句可以在作用域链前端临时增加一个变量对象,该变量对象会在代码执行中被移除)

  1. try-catch语句中的catch块
  2. with语句
function buildUrl(){
    var qs="?debug=true";

    with(location){
        var url=href+qs;
    }
    return url;
}
console.log(buildUrl())
View Code

 

函数的内部属性

arguments (是个类数组对象 主要用途是保存函数的参数,)和this(代表的是执行环境)

和callee 和caller(严格模式下不能使用  也不能为caller赋值 否则会导致错误)

这个对象还有一个名叫callee的属性(指向拥有arguments对象的函数)

function inner(n){
        if(n<=1){
            return 1;
        }
        return n*arguments.callee(n-1)
    }
    // 重写后的inner()函数体内没有在引用函数名inner ,这样无论引用函数时使用的是什么名字,都可以保证完成递归调用
    var outer=inner;
    
    inner=function(){
        return 0;
    }

    console.log(outer(5))//120
    console.log(inner(5))//0
View Code

这个对象还有一个名叫caller的属性(保存着调用当前函数的函数的引用,如果在全局作用域中调用当前函数,它的值为null)

function outer(){
        inner()
    }

    function inner(){
        // console.log(inner.caller)
        console.log(arguments.callee.caller)
    }

    console.log(inner());//null
    console.log(outer());//outer
View Code

 

函数属性和方法

length  表示函数接受的命名参数的个数

prototype 是函数的原型函数(prototype属性是不可以枚举的,因此使用for-in无法发现)

每个函数都包含两个非继承来的方法(都是用来改变this的指向 只是接受的参数不同):apply(this,arr) 和call(this,1,3)   

apply(this,arr)   接受数组,类数组

function sum(num1,num2){
        return num1+num2
    }

    function callSum1(num1,num2){
        return sum.apply(this,arguments)
    }

    function callSum2(num1,num2){
        return sum.apply(this,[num1,num2])
    }
View Code

call(this,1,2,3) 接受的参数必须逐个列举出来

function sum(num1,num2){
        return num1+num2
    }


    function callSum(num1,num2){
        return sum.call(this,num1,num2)
    }
View Code

 

理解对象
ECMAScript 中有两种属性:数据属性访问器属性。
1.数据属性(包含一个数据值的位置。在这个位置可以读取和写入值。数据属性有 4 个描述其行为的)
特性。
  1.  [[Configurable]]:表示能否通过 delete 删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。像前面例子中那样直接在对象上定义的属性,它们的这个特性默认值为 true。
  2.  [[Enumerable]]:表示能否通过 for-in 循环返回属性。像前面例子中那样直接在对象上定义的属性,它们的这个特性默认值为 true。
  3.  [[Writable]]:表示能否修改属性的值。像前面例子中那样直接在对象上定义的属性,它们的这个特性默认值为 true。
  4.  [[Value]]:包含这个属性的数据值。读取属性值的时候,从这个位置读;写入属性值的时候,把新值保存在这个位置。这个特性的默认值为 undefined。
var person = {
name: "Nicholas"
};
对于像前面例子中那样直接在对象上定义的属性,它们的[[Configurable]]、[[Enumerable]]
和[[Writable]]特性都被设置为 true,而[[Value]]特性被设置为指定的值。
View Code
 
2. 访问器属性
(访问器属性不能直接定义,必须使用 Object.defineProperty()来定义单个属性),
(访问器属性不能直接定义,必须使用 Object.defineProperties()来定义多个属性),
 
访问器属性有如下 4 个特性。
  1.  [[Configurable]]:表示能否通过 delete 删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为数据属性。对于直接在对象上定义的属性,这个特性的默认值true。
  2.  [[Enumerable]]:表示能否通过 for-in 循环返回属性。对于直接在对象上定义的属性,这个特性的默认值为 true。
  3.  [[Get]]:在读取属性时调用的函数。默认值为 undefined。
  4.  [[Set]]:在写入属性时调用的函数。默认值为 undefined。
(支持 ECMAScript 5 的这个方法的浏览器有 IE9+(IE8 只是部分实现)、Firefox 4+、Safari 5+、Opera12+ 和 Chrome )
访问器属性不包含数据值;它们包含一对儿 getter 和 setter 函数(不过,这两个函数都不是必需的)。
在读取访问器属性时,会调用 getter 函数,这个函数负责返回有效的值;在写入访问器属性时,会调用setter 函数并传入新值,这个函数负责决定如何处理数据。
在这个方法之前,要创建访问器属性,一般都使用两个非标准的方法:(没有这个方法之前使用的)
__defineGetter__()__defineSetter__()
(这两个方法最初是由 Firefox 引入的,后来 Safari 3、Chrome 1 和 Opera 9.5 也给出了相同的实现。使用这两个遗留的方法,可以像下面这样重写前面的例子。)
请看下面的例子。
//定义访问器的旧有方法
// var book={
//     _year:2004,
//     edition:1
// }

// book.__defineGetter__('year',function(){
//     return this._year;
// })

// book.__deifneSetter__('year',function(newValue){
//     if(newValue>2004){
//         this._year=newValue;
//         this.edition+=newValue-2004;
//     }
// })

// book.year=2005;
// console.log(book.edition)


//修改单个特性Object.defineProperty(obj,attr,{})
// var book = { 
//  _year: 2004, 
//  edition: 1 
// }; 

// Object.defineProperty(book, "year", { 
//  get: function(){ 
//  return this._year; 
//  }, 
//  set: function(newValue){ 
//  if (newValue > 2004) { 
//  this._year = newValue; 
//  this.edition += newValue - 2004; 
//  } 
//  } 
// }); 
// book.year = 2005; 
// alert(book.edition); 


//修改多个特性Object.defineProperties(obj,{})
var book={};
Object.defineProperties(book,{
    _year:{
        value:2014
    },
    edition:{
        value:1
    },
    year:{
        get:function(){
            return this._year
        },
        set:function(newValue){
            if(newValue>2004){
                this._year=newValue;
                this.edition+=newValue-2004
            }
        }
    }
})
console.log(book.year)
console.log(book.edition)
console.log(book.year=2050)
View Code

 

读取属性的特性 Object.getOwnPropertyDescriptor()

支持这个方法的浏览器有 IE9+、Firefox 4+、Safari 5+、Opera 12+和 Chrome。
 
  • 使用 ECMAScript 5 的 Object.getOwnPropertyDescriptor()方法,可以取得给定属性的描述符。
  • 这个方法接收两个参数:属性所在的对象和要读取其描述符的属性名称。
  • 返回值是一个对象,如果是访问器属性,这个对象的属性有 configurable、enumerable、get 和 set;
  • 如果是数据属性,这个对象的属性有 configurable、enumerable、writable 和 value。例如:
var book={};
Object.defineProperties(book,{
    _year:{
        value:2014
    },
    edition:{
        value:1
    },
    year:{
        get:function(){
            return this._year
        },
        set:function(newValue){
            if(newValue>2004){
                this._year=newValue;
                this.edition+=newValue-2004
            }
        }
    }
})

var descriptor=Object.getOwnPropertyDescriptor(book,"_year")
console.log(descriptor)//{value: 2014, writable: false, enumerable: false, configurable: false}
console.log(descriptor.value);//2014
console.log(descriptor.configurable)//false
View Code

 

 

创建对象

 Object 构造函数或对象字面量都可以用来创建单个对象

缺点:使用同一个接口创建很多对象,会产生大量的重复代码。为解决这个问题,人们开始使用工厂模式的一种变体。

 

工厂模式(这种模式抽象了创建具体对象的过程,考虑到在 ECMAScript 中无法创建类,开发人员就发明了一种函数,用函数来封装以特定接口创建对象的细节
缺点:函数 createPerson()能够根据接受的参数来构建一个包含所有必要信息的 Person 对象。可以无
数次地调用这个函数,而每次它都会返回一个包含三个属性一个方法的对象。工厂模式虽然解决了创建
多个相似对象的问题,但却没有解决对象识别的问题(即怎样知道一个对象的类型)。
如下面的例子所示
function createPerson(name,age,job){
    var obj=new Object();
    obj.name=name;
    obj.age=age;
    obj.job=job;
    // obj.sayName=function(){
    //     console.log(this.name);
    // }
    return obj;
}
//将公用方法提到外面 添加到原型上 减少内存开销
createPerson.prototype.sayName=function(){
        console.log(this.name);
    }

var person1=createPerson('panghu',18,'teacher')
var person2=createPerson('xiaofu',18,'doctor')

console.log(person1,person2);
// console.log(person1.sayName===person2.sayName);//false
console.log(person1.sayName===person2.sayName);//true
View Code
 

构造函数模式

  • ECMAScript 中的构造函数可用来创建特定类型的对象。
  • 像 Object 和 Array 这样创建对象 的原生构造函数,在运行时会自动出现在执行环境中。此外,也可以创建自定义的构造函数,从而定义自定义对象类型的属性和方法。
可以使用构造函数模式将前面的例子重写如下。
function Person(name,age,job){
    this.name=name;
    this.age=age;
    this.job=job;
    this.sayNam=function(){
        console.log(this.name);
    }
}

var person1 = new Person("Nicholas", 29, "Software Engineer"); 
var person2 = new Person("Greg", 27, "Doctor");
View Code
我们注意到,Person()中的代码除了与 createPerson()中相同的部分外,还存在以下不同之处:
  •  没有显式地创建对象;
  •  直接将属性和方法赋给了 this 对象;
  •  没有 return 语句。
此外,还应该注意到函数名 Person 使用的是大写字母 P。按照惯例,构造函数始终都应该以一个大写字母开头,而非构造函数则应该以一个小写字母开头。这个做法借鉴自其他 语言,主要是为了
区别于 ECMAScript 中的其他函数;因为构造函数本身也是函数,只不过可以用来创建对象而已。
 
要创建 Person 的新实例,必须使用 new 操作符。(以这种方式调用构造函数实际上会经历以下 4个步骤:)
  • (1) 创建一个新对象;
  • (2) 将构造函数的作用域赋给新对象(因此 this 就指向了这个新对象);
  • (3) 执行构造函数中的代码(为这个新对象添加属性);
  • (4) 返回新对象。
 
原型模式
1 理解原型对象

我们创建的每个函数都有一个 prototype(原型)属性,这个属性是一个指针,指向一个对象,(而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。)
优点:使用原型对象的好处是可以让所有对象实例共享它所包含的属性和方法。
在默认情况下,所有原型对象都会自动获得一个 constructor(构造函数)属性,这个属性包含一个指向 prototype 属性所在函数的指针。就拿前面的例子来说,
Person.prototype.  constructor 指向 Person。而通过这个构造函数,我们还可继续为原型对象添加其他属性和方法。

 

 

当为对象实例添加一个属性时,这个属性就会屏蔽原型对象中保存的同名属性;
换句话说,添加这个属性只会阻止我们访问原型中的那个属性,但不会修改那个属性。即使将这个属性设置为 null,也
只会在实例中设置这个属性,而不会恢复其指向原型的连接。不过,使用 delete 操作符则可以完全删
除实例属性,从而让我们能够重新访问原型中的属性
 
2. 原型与 in 操作符
有两种方式使用 in 操作符:单独使用和在 for-in 循环中使用。在单独使用时,in 操作符会在通
过对象能够访问给定属性时返回 true,无论该属性存在于实例中还是原型中。看一看下面的例子。
function Person(){};
Person.prototype.name='hanmeimei';
Person.prototype.age=20;
Person.prototype.job='Software Engineer';
Person.prototype.sayName=function(){
    console.log(this.name)
};

var person1=new Person(); 
var person2=new Person(); 

//obj.hasOwnProperty() 查看obj本身是否拥有某个属性
console.log(person1.hasOwnProperty("name"));//false
// name in obj 查看某个属性是否在obj原型上in 操作符会在通过对象能够访问给定属性时返回 true,无论该属性存在于实例中还是原型中
console.log("name" in person1);//true

person1.name='Greg';
console.log(person1.name);//hanmeimei 来自实例
console.log(person1.hasOwnProperty("name"));//true
console.log("name" in person1);//true

console.log('--------')
console.log(person2.name);// hanmeimei来自原型
console.log(person1.hasOwnProperty("name"));//true
console.log("name" in person2);//true

delete person1.name;
console.log(person1.name);//hanmeimei 来自原型
console.log(person1.hasOwnProperty('name'));//false
console.log("name" in person1);//true
View Code
在以上代码执行的整个过程中,name 属性要么是直接在对象上访问到的,要么是通过原型访问到
的。因此,调用"name" in person1 始终都返回 true,
无论该属性存在于实例中还是存在于原型中。同时使用 hasOwnProperty()方法和 in 操作符,就可以确定该属性到底是存在于对象中,还是存在于
原型中,如下所示。
    function hasPrototypeProperty(object, name) {
        if(name in object){
            return !object.hasOwnProperty(name);
        }
        return alert(name+'不存在实例和原型上')
    }
View Code

 Object.keys(obj) 要取得对象上所有可枚举的实例属性,可以使用 ECMAScript 5 的 Object.keys()方法。这个方法

接收一个对象作为参数,返回一个包含所有可枚举属性的字符串数组
    var obj = {
      a: 1,
      b: 2,
      c: 3
    }
    obj.__proto__.d = 3;
    let arr = Object.keys(obj);
    console.log(arr);//["a", "b", "c"]
View Code
 3 更简单的原型语法
为了从视觉上更好地封装原型的功能,更常见的做法是用一个包含所有属性和方法的对象字面量来重写整个原型对象,如下面的例子所示。
function Person(){ 
} 
Person.prototype = { 
 name : "Nicholas", 
 age : 29, 
 job: "Software Engineer", 
 sayName : function () { 
 alert(this.name); 
 } 
};
View Code
在上面的代码中,我们将 Person.prototype 设置为等于一个以对象字面量形式创建的新对象。最终结果相同,但有一个例外:constructor 属性不再指向 Person 了。前面曾经介绍过,每创建一个函数,就会同时创建它的 prototype 对象,这个对象也会自动获得 constructor 属性。而我们在这里使用的语法,本质上完全重写了默认的 prototype 对象,因此 constructor 属性也就变成了新对象的 constructor 属性(指向 Object 构造函数),不再指向 Person 函数。此时,尽管 instanceof操作符还能返回正确的结果,但通过 constructor 已经无法确定对象的类型了,如下所示。
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
posted @ 2021-05-10 01:06  还有什么值得拥有  阅读(40)  评论(0编辑  收藏  举报