uploadhub的技术博客 uploadhub的技术博客
首页
  • 学习笔记

    • 《HTML5和CSS3篇》
    • 《JavaScript基础篇》
    • 《JavaScript高级篇》
    • 《Ajax篇》
    • 《JavaScript模块化篇》
    • 《Node.js篇》
    • 《MongoDB篇》
    • 《Promise篇》
    • 《Git篇》
  • 《Vue2+Vue3篇》
  • 《React篇》
  • 一面-基础
  • 二三面-进阶
关于我
  • 分类
  • 标签
  • 归档

uploadhub

首页
  • 学习笔记

    • 《HTML5和CSS3篇》
    • 《JavaScript基础篇》
    • 《JavaScript高级篇》
    • 《Ajax篇》
    • 《JavaScript模块化篇》
    • 《Node.js篇》
    • 《MongoDB篇》
    • 《Promise篇》
    • 《Git篇》
  • 《Vue2+Vue3篇》
  • 《React篇》
  • 一面-基础
  • 二三面-进阶
关于我
  • 分类
  • 标签
  • 归档
  • JS基础知识(一)-变量类型和计算
  • JS基础知识(二)- 原型和原型链
    • 1.几道面试题(以点带面)
    • 2.涉及知识点
      • 2.1 构造函数
      • 2.2 5个原型rules
      • 2.3 原型规则补充
      • 2.4 原型链
      • 2.5 instanceof
    • 3.对前文问题的解答
      • 3.1 如何准确判断一个变量是数组类型
      • 3.2 写一个原型链继承的例子
      • 3.3 写一个封装DOM查询的例子
      • 3.4 描述 new 一个对象的过程
      • 3.5 手写一个简易的jQuery,考虑插件和扩展性
  • JS基础知识(三)- 作用域、闭包
  • JS基础知识(四)- 异步和单线程
  • JS基础知识(五)- 异步进阶
  • JS-Web-API(一)- DOM & BOM
  • JS-Web-API(二)- 事件
  • JS-Web-API(三)- Ajax
  • JS-Web-API(四)- 存储
  • HTTP协议及缓存机制
  • 开发环境
  • 运行环境
  • 一面-基础
uploadhub
2022-05-28
目录

JS基础知识(二)- 原型和原型链

# 1.几道面试题(以点带面)

  1. 如何准确判断一个变量是数组类型

  2. 写一个原型链继承的例子

  3. 写一个封装DOM查询的例子

  4. 描述 new 一个对象的过程

  5. 手写一个简易的jQuery,考虑插件和扩展性

# 2.涉及知识点

  1. 构造函数
  2. 构造函数 - 扩展
  3. 原型规则和示例
  4. 原型链
  5. instanceof

# 2.1 构造函数

  1. var a = {} 其实是 var a = new Object() 的语法糖

  2. var a = [] 其实是 var a = new Array() 的语法糖

  3. function Foo() {…} 其实是 var Foo = new Function(…)

  4. 使用 instanceof 判断一个函数是否是一个变量的构造函数

function Foo(name, age) {
  this.name = name;
  this.age = age;
  this.class = 'class-1';
  // return this;  // 默认有这一行
}
var foo = new Foo('zhangsan', 20);
var foo1 = new Foo('lisi', 22);  //创造多个对象
1
2
3
4
5
6
7
8

# 2.2 5个原型rules

  1. 所有的引用类型(数组、对象、函数),都具有对象特性,即可自由扩展属性(除了 ‘null’ 以外)

  2. 所有的引用类型(数组、对象、函数),都有一个 _proto_ 属性【隐式原型】,属性值是一个普通的对象

  3. 所有函数,都有一个prototype 属性【显式原型】,属性值也是一个普通的对象

  4. 所有的引用类型(数组、对象、函数), _proto_ 属性值指向它的构造函数的 “prototype” 属性值

  5. 当试图得到一个对象的某个属性时,如果这个对象本身没有这个属性,那么会去它的 _proto_ (即它的构造函数的prototype)中寻找

1.所有的引用类型(数组、对象、函数),都具有对象特性,即可自由扩展属性(除了 ‘null’ 以外)

// 原型和原型链
var obj = {};
obj.a = 100;

var arr = [];
arr.a = 100;

function fn() { }
fn.a = 100;
1
2
3
4
5
6
7
8
9

2.所有的引用类型(数组、对象、函数),都有一个 proto 属性【隐式原型】,属性值是一个普通的对象

console.log(obj.__proto__);  
// Object
console.log(arr.__proto__);
// [constructor: ƒ, toString: ƒ, toLocaleString: ƒ, join: ƒ, pop: ƒ, …]
console.log(fn.__proto__);
// ƒ () { [native code] }
1
2
3
4
5
6

3.所有函数,都有一个prototype 属性【显式原型】,属性值也是一个普通的对象。

console.log(fn.prototype);
// {constructor: f fn(); __proto__: Object}
1
2

4.所有的引用类型(数组、对象、函数), proto 属性值指向它的构造函数的 “prototype” 属性值

console.log(obj.__proto__ === Object.prototype);
// true
1
2

5.当试图得到一个对象的某个属性时,如果这个对象本身没有这个属性,那么会去它的 proto (即它的构造函数的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()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 2.3 原型规则补充

this、循环对象自身的属性

var item
for (item in f) {
	// 高级浏览器已经在 for in 中屏蔽了来自原型的属性
	// 但是这里建议大家还是加上这个判断,保证程序的健壮性
	if (f.hasOwnProperty(item)) {
		console.log(item)
	}
}

// 结果只有2个属性:name 、printName
1
2
3
4
5
6
7
8
9
10

# 2.4 原型链

// 原型和原型链-原型链

// 构造函数
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__ 中去寻找
console.log(f.toString()) // [object Object]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

image-20220910213125563

# 2.5 instanceof

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

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

function Foo(name, age) {
  this.name = name
}

// 创建示例
var f = new Foo('zhangsan');

console.log(f instanceof Foo);  // true
1
2
3
4
5
6
7
8

再试着判断 f instanceof Object

# 3.对前文问题的解答

# 3.1 如何准确判断一个变量是数组类型

var arr = [];
console.log(arr instanceof Array); // true
console.log(typeof arr); // object, typeof 是无法判断是否是数组的

function isArray(obj) {
	return Object.prototype.toString.call(obj) === '[object Array]';
}
console.log(isArray(arr)); // true
1
2
3
4
5
6
7
8

# 3.2 写一个原型链继承的例子

// 动物
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();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 3.3 写一个封装DOM查询的例子

function Elem(id) {
	this.elem = document.getElementById(id);
}
Elem.prototype.html = function(val) {
  var elem = this.elem;
  if (val) {
  	elem.innerHTML = val;
  	console.log(this)
  	return this; // 链式操作
  } else {
  	return elem.innerHTML;
  }
}
Elem.prototype.on = function(type, fn) {
	var elem = this.elem;
	if(elem.addEventListener) {
		elem.addEventListener('type', fn, false);
	} else if(elem.attachEvent) {
		elem.attachEvent('on' + type, fn);
	} else {
		elem['on' + type] = fn;
	}
    return this;
}

var div1 = new Elem('div1');
div1.html('有');
div1.on('click', alert('click')).html('youyi');
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

# 3.4 描述 new 一个对象的过程

  1. 创建一个新对象
  2. this 指向这个新对象
  3. 执行代码,即对this赋值
  4. 返回this
function Foo(name, age) {
  this = {};
  this.name = name;
  this.age = age;
  this.class = 'class-1';
  // return this;  // 默认有这一行
}
var foo = new Foo('zhangsan', 20);
var foo1 = new Foo('lisi', 22);  //创造多个对象
1
2
3
4
5
6
7
8
9

# 3.5 手写一个简易的jQuery,考虑插件和扩展性

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>test</title>
	<style>
	</style>
</head>
<body>
	<p>一段文字 1</p>
	<p>一段文字 2</p>
	<p>一段文字 3</p>

<script>  

class jQuery {
	constructor(selector) {
		const result = document.querySelectorAll(selector)
		const length = result.length
		for (let i = 0; i < length; i++) {
			this[i] = result[i]
		}
		this.length = length
		this.selector = selector
	}
	get(index) {
		return this[index]
	}
	each(fn) {
		for (let i = 0; i < this.length; i++) {
			const elem = this[i]
			fn(elem)
		}
	}
	on(type, fn) {
		return this.each((elem) => {
            elem.addEventListener(type, fn, false)
		})
	}
	// 扩展很多 DOM API
}


// 使用jQuery
const $p = new jQuery('p')
$p.get(1)
$p.each((elem) => console.log(elem.nodeName))
$p.on('click', () => alert('clicked'))


// 扩展-1、插件

jQuery.prototype.dialog = function(info) {
    alert(info)
}

// 扩展-2、造轮子

class myJQuery extends jQuery {
	constructor(selector) {
		super(selector)
	}
	// 扩展自己的方法
	addClass(className) {

	}
	style(data) {

	}
}

</script>
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#面试#JavaScript
JS基础知识(一)-变量类型和计算
JS基础知识(三)- 作用域、闭包

← JS基础知识(一)-变量类型和计算 JS基础知识(三)- 作用域、闭包→

最近更新
01
HTTP协议及缓存机制
05-28
02
开发环境
05-28
03
JS基础知识(一)-变量类型和计算
05-28
更多文章>
Theme by Vdoing | Copyright © 2021-2023 uploadhub | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式