JS1 - 变量与原型链

一、变量的类型和计算

1、JavaScript数据类型

ECMAScript标准规定了7种数据类型,其把这7种数据类型又分为两种:原始类型和对象类型。

原始类型:

  • Null:只包含一个值:null
  • Undefined:只包含一个值:undefined
  • Boolean:包含两个值:true和false
  • Number:整数或浮点数,还有一些特殊值(-Infinity、+Infinity、NaN)
  • String:一串表示文本值的字符序列
  • Symbol:一种实例是唯一且不可改变的数据类型
  • BigInt 是一种内置对象,它提供了一种方法来表示大于 253 - 1 的整数。这原本是 Javascript中可以用 Number 表示的最大数字。BigInt 可以表示任意大的整数

对象类型:

  • Object:自己分一类丝毫不过分,除了常用的Object,Array、Function等都属于特殊的对象


2、变量类型

按照存储方式分为值类型和引用类型

  • 值类型:undefined、string、number、Boolean
  • 引用类型 :数组、对象、null、函数 ( 引用类型有个特点可以无限扩展属性 )
//值类型
var a = 100;
var b = a;
a = 200;
console.log(b)//100

//引用类型
var a = {age:20};
var b = a;
b.age = 20;
console.log(a.age);//21

值类型赋值时相当于把变量赋值一份,所以两个变量啊a,b是隔离的,互相不受影响;

引用类型相当于指向同一个对象,a,b指向同一个对象,那么修改一个变量的属性相当于修改引用对象的属性,所以a,b会互相影响;

typeof undefined;//undefined
typeof 'abc';//string
typeof 123;//number
typeof true;//boolean

typeof {};//object
typeof [];//object
typeof null;//object
typeof console.log;//function
//前面4个是值类型,后面的引用类型
  • typeof只能区分值类型,不能区分引用类型;
  • typeof null是引用类型是因为null也是一个指针,但是它指向的是一个空对象;
  • typeof console.log可以检测出是function类型是因为函数类型是js中一个很重要的存在。

不适用场景
当你用 typeof 来判断引用类型时似乎显得有些乏力了:

typeof [] // object
typeof {} // object
typeof new Date() // object
typeof /^\d*$/; // object

除函数外所有的引用类型都会被判定为object。

另外typeof null === 'object’也会让人感到头痛,这是在JavaScript初版就流传下来的bug,后面由于修改会造成大量的兼容问题就一直没有被修复…



3、变量计算

⑴、强制类型转换

  • 字符串拼接
  • == 运算符
  • if语句
  • 逻辑运算
100 ==100//true
0 == ''//true
null == undefined // true

var a = true;
if(a){
//}
var b = 100;
if(b){}
//都会发生强制类型转换

console.log(10 && 0)//0
console.log('' || 'abc')//abc
console.log( !window.abc )//true

//判断一个变量会当做true还是false
var a = 100;
console.log(!!a);

⑵、何时使用===,何时使用==

仅有这种情况使用==

if(obj.a==null){
    // 此时条件相当于obj.a===null||obj.a===undefined,简写形式
    // 这是jQuery源码中推荐的写法
}

除此之外,其它情况均建议使用===



4、JS内置函数 - 数据封装类对象

Object、array、bollean、number、string、functiondate、regexp/正则表达式、error

⑴、数值方法

数值对象仅包含了几个任何对象均定义的默认方法

方法名称描述
constructor()返回创建该对象实例的函数。默认是数值对象
toExponential()强制将数值以指数形式显示
toFixed()可把 Number 四舍五入为指定小数位数的数字
toLocaleString()以字符串的形式返回当前对象的值。该字符串适用于宿主环境的当前区域设置
toPrecision()定义显示一个数多少位数(包括位小数的左和右)
toString()返回该数值的字符串格式
valueOf()返回数值

⑵、布尔方法

如下为相关方法及描述的列表:

方法名称描述
toSource()返回一个包含布尔对象的源字符串;可以使用这个字符串创建一个等价的对象
toString()按照布尔结果返回“true”或 “fales”
valueOf()返回布尔对象的原始值

⑶、字符串方法

如下为相关方法及描述的列表:

方法名称描述
charAt()返回指定位置的字符。
charCodeAt()返回指定位置字符的数值。
concat()返回布尔对象的原始值。
indexOf()返回匹配子字符串第一次出现的位置,如果不存在就返回-1。
lastIndexOf()返回匹配子字符串最后一次出现的位置,如果不存在就返回-1。
localeCompare()比较两个字符串,并返回以数字形式表示的比较结果。
length()返回字符串的长度。
match()用于匹配正则表达式。
replace()通过与正则表达式找到子串位置,并替换为新指定的字符串。
search()执行与一个正则表达式进行的搜索。
slice()提取并返回一个子串。
split()将字符串分割成多个子串,并存储进字符串数组。
substr()返回字符串中指定位置,指定长度的子串。
toLocaleLowerCase()大写字符转为小写,同时尊重当前语言环境。
toLocaleUpperCase()小写字符转为大写,同时尊重当前语言环境。
toLowerCase()大写字符转为小写。
toString()返回表示该对象的一个字符串。
toUpperCase()小写字符转为大写。
valueOf()返回指定对象的原始数值。

⑷、HTML字符串格式化工具

如下为相关方法及描述的列表:

方法名称描述
anchor()创建一个HTML锚作为一个超文本的目标。
big()创建一个以“大”字体表示的字符串,好比置于标签中一样。
blink()创建一个闪烁的字符串,好比置于标签中一样。
bold()创建一个粗体显示的字符串,好比置于标签中一样。
fixed()创建一个打字机字体显示的字符串,好比置于标签中一样。
fontcolor()创建一个特定字体颜色显示的字符串,好比置于标签中一样。
fontsize()创建一个特定字体大小显示的字符串,好比置于标签中一样。
italics()创建一个斜体显示的字符串,好比置于标签中一样。
link()创建HTML超级链接。
small()创建一个小字体显示的字符串,好比置于标签中一样。
strike()创建一个加了删除线显示的字符串,好比置于标签中一样。
sub()以下标的方式显示,好比置于标签中一样。
sup()以上标的方式显示,好比置于标签中一样。

⑸、数组方法

如下为相关方法及描述的列表:

方法名称描述
concat()返回两个数据经过联接后的数组。
every()如何数组内的元素均满足某测试函数,那么就返回true。
filter()原来的数组中能过通过过滤器的元素组成一个新的数组返回。
forEach()调用一个函数来处理数组中的每个元素。
indexOf()返回与指定元素相匹配的第一个位置,如果不存在就返回-1
join()连接数组中所有的元素,返回一个字符串
lastIndexOf()返回与指定元素相匹配的最后一个位置,如果不存在就返回-1。
map()调用一个函数处理数组中的每一个元素,将生成的结果组成一个新的数组,并返回
pop()返回数组中的最后一个元素,并删除。
push()在数组的最后增加一个元素,并返回新数组的长度
reduce()对数组中的所有元素(从左到右)调用指定的回调函数。 该回调函数的返回值为累积结果,并且此返回值在下一次调用该回调函数时作为参数提供。
reduceRight()对数组中的所有元素(从右到左)调用指定的回调函数。 该回调函数的返回值为累积结果,并且此返回值在下一次调用该回调函数时作为参数提供。
reverse()反转数组元素的顺序——第一个成为最后一个,最后成为第一。
shift()删除数组的第一个元素并返回。
slice()提取一段数组并返回一个新的数组
some()如果存在一个元素满足所提供的测试函数,就返回true。
toSource()代表一个对象的源代码。
sort()对数组中的元素排序。
splice()增删数组中的元素。
toString()返回一个表示数组及其元素的字符串。
unshift()在数组的首部添加新的元素,并且返回新数组的长度

⑹、时期方法

如下为相关方法及描述的列表:

方法名称描述
Date()返回今天的日期及时间。
getDate()按照本地模式返回指定日期是哪日。
getDay()按照本地模式返回指定日期是周几。
getFullYear()按照本地模式返回指定日期是哪一年。
getMilliseconds()按照本地模式返回指定日期是几毫秒。
getMinutes()按照本地模式返回指定日期是几分。
getMonth()按照本地模式返回指定日期的月份。
getSeconds()按照本地模式返回指定日期是几秒。
getTime()按照本地模式当前的格林威治时间。
getTimezoneOffset()以分钟为单位返回时间偏差。
getUTCDate()按照世界统一时间返回指定日期是几号。
getUTCDay()按照世界统一时间返回指定日期是周几。
getUTCFullYear()按照世界统一时间返回指定日的年份。
getUTCHours()按照世界统一时间返回指定日期是几时。
getUTCMilliseconds()按照世界统一时间返回指定日期的毫秒数。
getUTCMinutes()按照世界统一时间返回指定日期的分钟数。
getUTCMonth()按照世界统一时间返回指定日期的月份。
getUTCSeconds()按照世界统一时间返回指定日期的秒数。
setDate()按照本地模式设置日期。
setFullYear()按照本地模式设置年份。
setHours()按照本地模式设置小时。
setMilliseconds()按照本地模式设置毫秒数。
setMinutes()按照本地模式设置分钟数。
setMonth()按照本地模式设置月份。
setSeconds()按照本地模式设置秒数。
setTime()按照格林威治格式设置毫秒数。
setUTCDate()按照世界统一时间设置日期。
setUTCFullYear()按照世界统一时间设置年份。
setUTCHours()按照世界统一时间设置小时数。
setUTCMilliseconds()按照世界统一时间设置毫秒数。
setUTCMinutes()按照世界统一时间设置分钟数。
setUTCMonth()按照世界统一时间设置月份。
setUTCSeconds()按照世界统一时间设置秒数。
toDateString()返回日期的字符串。
toLocaleDateString()按照本地模式,返回日期的字符串。
toLocaleFormat()使用格式字符串,将日期转换为一个字符串。
toLocaleString()使用当前语言环境的约定将日期转换为一个字符串。
toLocaleTimeString()返回日期的“时间”部分作为一个字符串,使用当前语言环境的约定。
toSource()返回一个字符串代表一个等价的日期对象的来源,您可以使用这个值来创建一个新的对象。
toString()返回一个字符串代表指定的日期对象。
toTimeString()返回日期的“时间”部分以字符串形式。
toUTCString()使用通用时间约定,将日期转换为一个字符串。
valueOf()返回日期对象的原始值。

⑺、日期静态方法

如下为相关方法及描述的列表:

方法名称描述
Date.parse( )解析并返回日期和时间的字符串表示的内部毫秒表示日期。
Date.UTC( )返回指定的毫秒表示UTC日期和时间。

⑻、数学方法

如下为相关方法及描述的列表:

方法名称描述
abs()返回数值的绝对值。
acos()返回一个数值的arccos值。
asin()返回一个数值的arcsin值。
atan()返回一个数值的arctan值。
ceil()返回大于或等于整数最小的一个数字。
cos()返回一个数值的cos值。
exp()返回指数。
floor()返回小于等于一个数的最大数。
log()返回一个数值以e为底的对数。
max()返回最大值。
min()返回最小值。
pow()返回以e为底的幂。
random()返回0和1之间的一个伪随机数。
round()返回四舍五入后的值。
sin()返回sin值。
sqrt()返回一个整数的平方根。
tan()返回一个数值的tan值。
toSource()返回字符串“Manth”。

⑼、正则表达式方法

如下为相关方法及描述的列表:

方法名称描述
exec()执行一个字符串的搜索匹配。
test()测试匹配的字符串参数。
toSource()返回一个对象文字代表指定的对象;您可以使用这个值来创建一个新的对象。
toString()返回一个字符串代表指定的对象


5、JSON

  • JSON指的是JavaScript对象表示法(javascript object notation)

  • JSON是轻量级的文本数据交互格式,并不是编程语言

  • JSON独立于语言存在

  • JSON具有自我描述性,更容易理解

  • JSON可以将JavaScript对象中表示的一组数据转换为字符串,然后就可以在函数之间轻松地传递这个字符串,或者在异步应用程序中将字符串从Web客户机传递给服务器端程序

  • 它是基于JavaScript的一个子集。数据格式简单,易于读写,占用带宽小。

  • JSON简单说就是JavaScript中的对象和数组,所以这两种结构就是对象和数组两种结构,通过这两种结构可以表示各种复杂的结构。

    对象对象在js中表示为”{}”括起来的内容,数据结构为{key:value,key:value,…}的键值对的结构,在面向对象的语言中,key为对象的属性,value为对应的属性值,所以很容易理解,取值方法为对象.key 获取属性值,这个属性值的类型可以是数字、字符串、数组、对象几种。

    数组数组在js中是中括号”[]”括起来的内容,数据结构为[“java”,”javascript”,”vb”,…],取值方式和所有语言中一样,使用索引获取,字段值的类型可以是数字、字符串、数组、对象几种。经过对象、数组2种结构就可以组合成复杂的数据结构了。



6、题目

⑴、题目

  • JS中使用typeof能得到的哪些类型
  • 何时使用===何时使用==
  • JS中有哪些内置函数
  • JS变量按照存储方式区分为哪些类型,并描述其特点
  • 如何理解JSON

⑵、知识点

①、变量类型

JS变量最基本的分类就是值类型引用类型,两者有何区别呢,可以通过例子看出来。

以下是值类型的一个例子

var a = 100
var b = a
a = 200
console.log(b)

以下是引用类型的一个例子

var a = {age:20}
var b = a
b.age = 21
console.log(a.age)

typeof可以知道一个值类型是什么类型,而对于引用类型,它就无能为力了。但是它可以将引用类型区分出function

JS 中的某些表现,就已经体现了函数的特殊意义,例如:对象和数组,JS中没有内置的(不考虑 JS-WEB-API),而函数却内置了很多,例如 Object Array Boolean Number String Function Date RegExp Error。这些函数 JS 本身就有,因为他们是基础数据类型的构造函数

typeof可以区分类型有number string boolean undefined(值类型) function object(引用类型)

// 特例
typeof null // object 因为 null 也是引用类型。null 就相当于引用类型中的 undefined

那么针对第二个例子,如何将a的内容复制给b,并且保证b的修改不会影响到a呢?那就需要深度复制,意思就是对a的属性进行递归遍历,再依次复制。

②、变量计算

组简单的计算,就是数字的加减乘除、字符串的拼接和替换,这个太简单了。但是 JS 在值类型的运算过程中,特别需要注意和利用强制类型转换这一特性,有以下场景:

  • 字符串拼接
  • ==
  • 逻辑运算(if ! || &&

字符串拼接最常见的错误如下,特别要注意。如何规避呢 - 对进行计算的变量通过typeof来判断类型

var a = 100 + 10   // 110
var b = 100 + '10' // '10010'

接下来,==也会进行强制类型转换,如

100 == '100'   // true
0 == ''  // true
null == undefined  // true

针对100 == '100'就是和拼接字符串一样的类型转换,而针对下面两个例子,就是一个逻辑运算上的强制类型转换。所以,所有的地方都要使用===而不能使用==,但是 jquery 源码有一个特例,就是obj.a == null,使用很简洁。

最后,逻辑运算中的强制类型转换,先以if为例说明

var a = true
if (a) {
    // ....
}
var b = 100
if (b) {
    // ....
}
var c = ''
if (c) {
    // ....
}

所有经过if判断的变量,都会进行逻辑运算的强制类型转换,转换为true或者false

console.log(10 && 0)  // 0
console.log('' || 'abc')  // 'abc'
console.log(!window.abc)  // true

// 判断一个变量会被当做 true 还是 false
var a = 100
console.log(!!a)

日常开发中,以下变量会被转换为false

  • 0
  • NaN
  • ‘’
  • null
  • undefined
  • false 本身

除了以上几个,其他的都会被转换为true除了if之外,! || &&这三个运算符也会进行同样的转换,跟if是一个道理。因此,如何快速判断一个变量将会被if转换为什么呢?————!!a

⑶、答题

①、JS中使用typeof能得到的哪些类型?

可以通过以下程序进行验证

typeof undefined // undefined
typeof 'abc' // string
typeof 123 // number
typeof true // boolean
typeof {}  // object
typeof [] // object
typeof null // object
typeof console.log // function

②、何时使用===何时使用==

==会先试图类型转换,然后再比较,而===不会类型转换,直接比较。如下例子:

1 == '1' // true
1 === '1' // false
0 == false // true
0 === false // false
null == undefined // true
null === undefined // false

根据 jQuery 源码中的写法,只推荐在一个地方用==,其他地方都必须用===。这个用==的地方就是:

if (obj.a == null) {  // 这里相当于 obj.a === null || obj.a === undefined ,简写形式
}

③、JS中有哪些内置函数

Object Array Boolean Number String Function Date RegExp Error

④、JS变量按照存储方式区分为哪些类型,并描述其特点
  • 值类型 undefined string number boolean
  • 引用类型 object function

在 JS 中,所有的引用类型都可以自由设置属性

var obj = {}
obj.a = 100

var arr = []
arr.a = 100

function fn() {}
fn.a = 100

⑤、如何理解JSON

JSON 是什么?从 JS 角度回答,太简单了,console.log(JSON)得到JSON只是一个对象,有parsestringify两个方法,使用也非常简单

JSON.stringify({a:10, b:20})
JOSN.parse('{"a":10,"b":20}')

之所以误答,就是怕把这个问题复杂化了,因为 json 也是一种数据格式,这一点和 xml 一样。但是在 JS 的面试题中,如果问到这个问题,直接说明parsestringify两个方法的用法即可,面试官如果有追问,你再去继续回答。




二、原型和原型链

1、构造函数

⑴、构造函数实例

function Foo(name, age){
	this.name = name
	this.age = age
	this.class = 'class-1'
	// return this  // 默认有这一行
}
var f = new Foo('zhangsan', 20)
//  var f1 = new Foo('lisa', 21)  // 创建多个对象

⑵、构造函数- 扩展

  • var a = {} 其实是 var a = new Object() 的语法糖
  • var a = [] 其实是 var a = new Array() 的语法糖
  • function Foo{…} 其实是 var Foo = new Function(…)
  • 使用 instanceof 判断一个函数是否是一个变量的构造函数
  • 使用 instanceof Array 判断一个变量是否为 “数组”



2、原型规则和示例

  • 所有的引用类型 ( 数组、对象、函数 ) , 都具有对象特性, 即可自由扩展属性 ( 除了 “nul” 意外 )
  • 所有的引用类型 ( 数组、对象、函数 ), 都具有一个 proto ( 隐式原型 )属性, 属性值是一个普通的对象
  • 所有的函数, 都有一个 prototype ( 显示原型 ) 属性, 属性值也是一个普通的对象
  • 所有的引用类型 ( 数组、对象、函数 ) , proto ( 隐式原型 ) 属性值指向他的构造函数的 prototype ( 显示原型 ) 属性值
  • 当试图得到一个对象的某个属性时, 如果这个对象本身没有这个属性, 那么会去找它的 proto ( 即它构造函数的 prototype ) 中寻找

实例:

var obj = {}; obj.a = 100;
var arr = []; arr.a = 100;
function fn () {}
fn.a = 100;

console.log( obj._proto_ );
console.log( arr._proto_ );
console.log( fn._proto_ );

console.log( fn.prototype )

console.log( obj._proto_ === Object.prototype )

// 构造函数
function Foo(name, age){
	this.name = name
}
Foo.prototype.alertName = function(){
	alert( this.name )
}

// 创建示例
var f = new Foo('zhangsan')
f.printName = function(){
	console.log( this.name )
}

// 测试
f.printName()
f.alertName()
f.toString()  // 要去 f._proto_._proto_ 中查找 


3、原型链

在这里插入图片描述



4、instanceof

用于判断 引用类型 属于哪个 构造函数 的方法

f instanceof Foo 的判断逻辑是:f 的_proto_ 一层一层往上, 能否对应到 Foo.prototype, 再试着判断 f instanceof Object



5、答题

⑴、如何准确判断一个变量是数组类型

只有instanceof才能判断一个对象是否是真正的数组

var arr = []
arr instanceof Array // true
typeof arr // object,typeof 是无法判断是否是数组的

⑵、如何准确判断一个变量是数组类型

只有instanceof才能判断一个对象是否是真正的数组

var arr = []
arr instanceof Array // true
typeof arr // object,typeof 是无法判断是否是数组的

扩展:实际应用中,和数组同样重要、起同样作用并且更加灵活的数据结构还是“伪数组”或者“类数据”(jquery 就用到了)。因此,在实际应用中,只需要判断length属性是否是数字即可。

var arr = []
var likeArr = {
    0: 'aaa',
    1: 'bbb',
    2: 'ccc',
    length: 3
}

typeof arr.length === 'number' // true
typeof likeArr.length === 'number' // true

⑶、写一个原型链继承的例子

// 动物
function Animal() {
    this.eat = function () {
        console.log('animal eat')
    }
}
// 狗
function Dog() {
    this.bark = function () {
        console.log('dog bark')
    }
}
Dog.prototype = new Animal()
// 哈士奇
var hashiqi = new Dog()

// 其实,书中是为了演示了而演示,真正的实际 JS 开发中,根本不推荐这种两层甚至三层的继承。因为工作中项目本身业务就非常复杂,代码设计上就尽量求简,越简单的东西才越容易扩展和改变。

接下来,我将根据自己的开源项目 wangEditor 中的一段源码进行简化,通过实际的业务场景来使用原型和继承

// 构造函数
function DomElement(selector) {
    var result = document.querySelectorAll(selector)
    var length = result.length
    var i
    for (i = 0; i < length; i++) {
        this[i] = selectorResult[i]
    }
    this.length = length
}
// 修改原型
DomElement.prototype = {
    constructor: DomElement,
    get: function (index) {
        return this[index]
    },
    forEach: function (fn) {
        var i
        for (i = 0; i < this.length; i++) {
            const elem = this[i]
            const result = fn.call(elem, elem, i)
            if (result === false) {
                break
            }
        }
        return this
    },
    on: function (type, fn) {
        return this.forEach(elem => {
            elem.addEventListener(type, fn, false)
        })
    }
}

// 使用
var $div = new DomElement('div')
$div.on('click', function() {
    console.log('click')
})

⑷、描述 new 一个对象的过程

function Foo(name) {
    this.name = name
    this.type = 'foo'
}
var foo = new Foo('beijing')
  • 创建一个新对象
  • this指向这个新对象
  • 执行代码,即对this赋值
  • 返回this

⑸、zepto(或其他框架) 源码中如何使用原型链

解读优秀开源框架的源码或者设计,是成为程序大牛的毕竟之路。当然,解读源码是一件非常枯燥、成本非常高的事儿。因此我强烈推荐,不要去一意孤行闭门造车的解读枯燥的源码,而是通过在网上找到一些优秀的材料,来解读一个框架的设计。

就像一本厚厚的书,如何快速掌握书的内容?———— 知道个大致的故事结构,然后去看看别人(最好是名人)的一些点评,这样虽然花费时间很少,但是你也能比那些闷着头把书看完的人,了解到的东西更多。而且这种方式你可以高效率的阅读很多书,增加你的见识。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

后海 0_o

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值